intitial commit

This commit is contained in:
2024-09-20 02:29:41 +00:00
parent 13871f60f9
commit f7135004cf
5 changed files with 560 additions and 0 deletions

3
backend.js Normal file
View File

@@ -0,0 +1,3 @@
class BackendConnection {
}

75
card-v2.js Normal file
View File

@@ -0,0 +1,75 @@
class Card {
#suit
#rank
#value
#faceUp
#color
constructor(suit, rank, vis=false) {
/*Create an object of class Card; provide suit, rank, [visible]*/
this.#suit = suit;
this.#rank = rank;
this.#faceUp = vis;
this.#setColor();
switch(this.#rank) {
case 'J':
this.#value = 11;
break;
case 'Q':
this.#value = 12;
break;
case 'K':
this.#value = 13;
break;
case 'A':
this.#value = 1;
break;
default:
this.#value = parseInt(this.#rank);
}
}
#setColor() {
if (this.#suit[0] == "H" || this.#suit[0] == "D") {
this.#color = "red";
}
else {
this.#color = "black";
}
}
flip() {
/*Inverts the card's visibility*/
this.#faceUp = !this.#faceUp;
}
getVisible() {
/*Returns a Boolean; True if the card face is visible*/
return this.#faceUp;
}
getValue() {
/*Returns the card's equivalent integer value; Ace is 14*/
return this.#value;
}
getRank() {
/*Returns the card's rank*/
return this.#rank;
}
getSuit() {
/*Returns the card's suit*/
return this.#suit;
}
getColor() {
/*Returns the card's color*/
return this.#color;
}
getImageRef() {
/*Returns a string containing a local filename for the card*/
return `${this.#rank + this.#suit}.png`;
}
}

33
cardgame.html Normal file
View File

@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<style>
html {
background-color: #808080;
}
/*canvas styling*/
#canvas {
position: absolute;
top:0;
bottom: 0;
left: 0;
right: 0;
aspect-ratio: 16/9;
margin:auto;
border: solid rgb(400,400,300) 4px;
}
</style>
<title>Solitaire - Klondike - Yurun Chen</title>
<!-- <link rel="stylesheet" href="style.css"> -->
<script type="text/javascript" defer src="card-v2.js"></script>
<script type="text/javascript" defer src="deck-v2.js"></script>
<!-- main game javascript file-->
<script type="text/javascript" defer src="game.js"></script>
<!-- not currently in use-->
<script type="text/javascript" defer src="backend.js"></script>
</head>
<body>
<canvas id="canvas" width="400" height="300"> </canvas>
</body>
</html>

62
deck-v2.js Normal file
View File

@@ -0,0 +1,62 @@
class Deck {
#deck
constructor() {
/*Initialises a new shuffled deck of 52 cards*/
this.#deck = [];
this.createDeck();
this.shuffle();
}
createDeck() {
/*Creates an array of 52 Card objects*/
const suits = ['H', 'S', 'C', 'D'];
const faces = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 13; j++) {
this.#deck.push(new Card(suits[i], faces[j]));
}
}
}
shuffle() {
/*Randomly shuffles the deck*/
for (let i = this.getSize() - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
var temp = this.#deck[i];
this.#deck[i] = this.#deck[j];
this.#deck[j] = temp;
}
}
getSize() {
/*Returns the number of elements in the deck*/
return this.#deck.length;
}
isEmpty() {
/*Returns a Boolean; True if the deck is currently empty*/
return this.getSize() < 1;
}
viewTop() {
/*Returns the topmost card without removing it from the deck, or null if the deck is empty*/
if (!this.isEmpty()) {
return this.#deck[this.getSize() - 1]
}
else {
return null;
}
}
drawCard() {
/*Returns the topmost card in the deck, or null if the deck is empty*/
if (!this.isEmpty()) {
return this.#deck.pop();
}
else {
return null;
}
}
}

387
game.js Normal file
View File

@@ -0,0 +1,387 @@
//column class
class Column extends Stack{
constructor(){
super();
}
}
//stock stack
class Stock extends Stack {
constructor(){
super();
}
//append card back to stock after wastepile exceeds threshold CRUDE
append(card){
var items = super.get_items();
items.unshift(card);
super.set_items(items);
}
}
class WastePile extends Stack {
constructor(){
super();
}
//clearing waste pile by popping the cards one by one
clear () {
for (i=super.size();i--;i>-1){
super.pop();
}
}
//determines if the waste pile has met the threshold of 3
threshold (){
if (super.size() == 3){
return true;
} else {
return false;
}
}
}
//Object for board layout
class Board {
#waste_pile
#stock_pile
#foundations
#tableau
#deck
constructor (){
//init a deck
this.#deck = new Deck();
this.#tableau = new Array();
this.#stock_pile = new Stock();
this.#waste_pile = new WastePile();
//initialise the 7 columns
for (var i=1; i<8; i++){
this.#tableau.push(new Column());
}
//initialise the value in the 7 columns
for (var j = 1; j<8; j++){
for (var k = j; k>0; k--){
this.#tableau[j-1].push(this.#deck.drawCard());
}
}
var length = this.#deck.getSize();
//initialise the stock pile
for (var k=0; k <= length; k++){
this.#stock_pile.push(this.#deck.drawCard());
}
//reveal top card except stock pile, otherwise it'd be cheating
}
get_stock(){
return this.#stock_pile;
}
get_tableau(){
return this.#tableau;
}
}
//base class for element
//Elements are required to implement
class Element{
constructor(x,y,dx,dy) {
this.x = x;
this.y = y;
this.dx = dx
this.dy = dy
this.ox = x;
this.oy = y;
this.odx = dx;
this.ody = dy;
}
}
//View of background, really just shoved into a view, very simple
class Background extends Element {
constructor(){
super(0,0,1920,1080);
}
resize(scale){
this.dx = this.odx * scale[0];
this.dy = this.ody * scale[1];
}
render(ctx){
ctx.fillStyle = "#168a22";
ctx.rect(this.x, this.y, this.dx, this.dy);
ctx.stroke();
ctx.fill();
}
}
//view class for different views to extend on
class View {
#element_list
constructor(element_list){
this.#element_list = element_list;
}
resize(scale){
for (var i=0; i< this.#element_list.length; i++) {
this.#element_list[i].resize(scale);
}
}
render(ctx){
for (var i=0; i< this.#element_list.length; i++) {
this.#element_list[i].render(ctx);
}
}
add_element(e){
this.#element_list.append(e);
}
}
//view for single card, bad naming I suppose, as it is not a view (really) more of a element
class CardView extends Element {
#revealed
#img
#ox
#oy
#odx
#ody
constructor(revealed, x, y, card, dx, dy){
super(x,y,dx,dy);
this.#ox = x;
this.#oy = y;
this.#odx = dx;
this.#ody = dy;
this.#revealed = revealed;
this.#img = new Image();
this.card = card;
if (revealed) {
this.#img.src = "cards/"+this.card.getRank()+Array.from(this.card.getSuit())[0]+".png";
} else {
this.#img.src = "cards/cardBackRed.png";
}
}
render(ctx){
ctx.drawImage(this.#img, this.x, this.y,this.dx , this.dy);
}
resize(scale) {
this.x = this.ox*scale[1];
this.dx = this.odx*scale[1];
this.dy = this.odx*scale[0];
this.y = this.oy*scale[1];
}
}
//0 orientation for landscape 1 orientation for portrait
class StackView extends View{
#orientation
constructor (orientation,element_list){
super(element_list)
this.#orientation = orientation;
}
render(ctx){
super.render(ctx);
}
}
//view for the stock stack
class StockView extends StackView{
#card_list
#stack
constructor (stack){
super(0, [new CardView(false,50,20, stack[-1], 200, 300)]);
this.#stack = stack;
}
render (ctx) {
super.render(ctx);
}
}
//view for the waste stack
class WasteView extends StackView{
constructor(){
super(0);
}
}
//view for the vertical columns
class ColumnView extends StackView {
#column_array
constructor(element_list, arrays){
super(0,element_list);
this.#column_array = arrays;
}
render(ctx){
super.render(ctx);
}
}
//view for the foundations
class FoundationView extends StackView {
constructor(){
super(1);
}
}
class TableauView{
//passed board object to gen view
constructor (board){
}
}
//canvas rendering manager
class RenderMgr{
#ctx
#views
#cur_view
//valid canvas context must be passed
constructor(ctx){
this.#ctx = ctx;
this.#cur_view;
}
resize(scale){
//resize every single element present on view
for (var i=0; i<this.#cur_view.length;i++){
this.#cur_view[i].resize(scale);
}
}
render(){
//LOOP THROUGH RENDER IN VIEWS WHICH IN TURN LOOPS THROUGH TO RENDER ELEMENTS
for (var i=0;i<this.#cur_view.length;i++){
this.#cur_view[i].render(this.#ctx);
}
requestAnimationFrame(this.render.bind(this))
}
//switching cur_view lists, not really used extensively
switch_view(view) {
this.#cur_view = view;
}
generate_column_view(tableau){
var column_view = new Array();
var elements = new Array();
for (var i=0; i<tableau.length;i++){
var element_list = new Array();
var cx = 50;
var cy = 240;
var cdx = 180
var cdy = 270;
for (var j=0; j < tableau[i].size()+1; j++){
var card = tableau[i].pop()
//determine if the current card the is last card
if (j==tableau[i].size()){
element_list.unshift(new CardView(true, cx, cy,card, cdx, cdy));
} else {
element_list.unshift(new CardView(false, cx, cy, card,cdx,cdy));
}
//stack em on top
cdy+=20;
}
column_view.push(new ColumnView(element_list, column_view));
//add offset for next column
cx += 93.3;
}
//join the 2d aray into single array because element list, the arrays will be maintained separately
console.log(elements);
return column_view
}
}
class KlondikeGame {
#size_modifier
#ctx
#scale_modifier
#mgr
#stock_view
#bg_view
#column_view
#deck
constructor (){
//intialise a new deck
this.#deck = new Deck();
console.log("initialised deck");
//grab context for render manager
this.#ctx = document.getElementById("canvas").getContext("2d");
console.log(this.#board);
//initialise render manager
this.#mgr = new RenderMgr(this.#ctx);
//bind render function of rendermanager
//initialise stock view
this.#stock_view = new StockView(this.#board.get_stock());
//initialise background
this.#bg_view = new View([new Background()]);
//initialise the 7 columns
var tableau = this.#board.get_tableau();
this.#column_view = this.#mgr.generate_column_view(tableau);
console.log(this.#column_view);
//switch view to deck TODO: ALL DECKS AND MENUBAR
this.#mgr.switch_view([this.#bg_view,this.#stock_view, this.#column_view]);
requestAnimationFrame(this.#mgr.render.bind(this.#mgr));
}
//update scale modifier, however only currently fixed to 16:9 aspect ratio.
//all values calculated from modifier * 1920, 1080
update_scale(resolution){
this.#scale_modifier = [Number(resolution[0]/1920), Number(resolution[1]/1080)];
this.#mgr.resize(this.#scale_modifier);
}
switch_deck_view(){
}
}
var game_instance = new KlondikeGame();
window.onload = window.onresize = function() {
var canvas = document.getElementById('canvas');
canvas.width = window.innerWidth * 0.99;
canvas.height = window.innerHeight * 0.9 ;
game_instance.update_scale([canvas.width, canvas.height])
}