Inital commit
3
backend.js
Normal file
@@ -0,0 +1,3 @@
|
||||
class BackendConnection {
|
||||
|
||||
}
|
||||
75
card-v2.js
Normal 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
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html {
|
||||
background-color: Azure;
|
||||
}
|
||||
/*canvas styling*/
|
||||
#canvas {
|
||||
position: absolute;
|
||||
top:0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin:auto;
|
||||
border: solid rgb(400,400,300) 4px;
|
||||
}
|
||||
</style>
|
||||
<title>Solitaire - Klondike - Yurun Chen</title>
|
||||
<!-- <link rel="stylesheet" href="style.css"> -->
|
||||
<script type="module">import { Canvg } from 'https://cdn.skypack.dev/canvg@^4.0.0';</script>
|
||||
<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>
|
||||
BIN
cards/10C.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
cards/10D.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
cards/10H.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/10S.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
cards/2C.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
cards/2D.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
cards/2H.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
cards/2S.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
cards/3C.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
cards/3D.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
cards/3H.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
cards/3S.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
cards/4C.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
cards/4D.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
cards/4H.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
cards/4S.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
cards/5C.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
cards/5D.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
cards/5H.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
cards/5S.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
cards/6C.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
cards/6D.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
cards/6H.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
cards/6S.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
cards/7C.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
cards/7D.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
cards/7H.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
cards/7S.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
cards/8C.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
cards/8D.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/8H.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/8S.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/9C.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
cards/9D.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
cards/9H.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/9S.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
cards/AC.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
cards/AD.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
cards/AH.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
cards/AS.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
cards/JC.png
Normal file
|
After Width: | Height: | Size: 174 KiB |
BIN
cards/JD.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
cards/JH.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
cards/JS.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
cards/KC.png
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
cards/KD.png
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
cards/KH.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
cards/KS.png
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
cards/QC.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
cards/QD.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
cards/QH.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
cards/QS.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
cards/cardBackRed.png
Normal file
|
After Width: | Height: | Size: 246 KiB |
BIN
cards/down_arrow.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
cards/red_back.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
cards/up_arrow.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
62
deck-v2.js
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
353
game.js
Normal file
@@ -0,0 +1,353 @@
|
||||
class Stack {
|
||||
#items
|
||||
|
||||
constructor() {
|
||||
this.#items = [];
|
||||
}
|
||||
|
||||
push(element) {
|
||||
this.#items.push(element);
|
||||
//Add element to the stack
|
||||
|
||||
}
|
||||
|
||||
pop() {
|
||||
//Check that the stack is not empty
|
||||
//Remove the last element from the stack and return it
|
||||
if (this.isEmpty() == false){
|
||||
return this.#items.pop()
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
peek() {
|
||||
//Check that the stack is not empty
|
||||
//Return the last element from the stack without removing it
|
||||
return this.#items[this.#items.length - 1];
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
//Return true if the stack is empty
|
||||
if (this.#items.length == 0){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size() {
|
||||
//Return the number of elements in the stack
|
||||
return this.#items.length;
|
||||
}
|
||||
|
||||
get_items() {
|
||||
return this.#items;
|
||||
}
|
||||
|
||||
set_items(items) {
|
||||
this.#items = items;
|
||||
}
|
||||
|
||||
to_array(){
|
||||
return this.#items;
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//base class for element
|
||||
class Element{
|
||||
constructor(x,y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
class Background extends Element {
|
||||
|
||||
#dx
|
||||
#dy
|
||||
|
||||
constructor(){
|
||||
super(0,0);
|
||||
this.#dx = 1920;
|
||||
this.#dy = 1080;
|
||||
}
|
||||
|
||||
resize(scale){
|
||||
this.#dx = 1920 * scale[0];
|
||||
this.#dy = 1080 * 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
|
||||
constructor(revealed, x, y, card){
|
||||
super(x,y);
|
||||
this.#revealed = revealed;
|
||||
this.#img = new Image();
|
||||
if (revealed) {
|
||||
this.#img.src = "cards/"+this.#cur_card.getRank()+Array.from(this.#cur_card.getSuit())[0]+".png";
|
||||
} else {
|
||||
this.#img.src = "cards/cardBackRed.png";
|
||||
}
|
||||
}
|
||||
|
||||
render(ctx){
|
||||
ctx.drawImage(this.#img, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
//0 orientation for landscape 1 orientation for portrait
|
||||
class StackView extends View{
|
||||
#orientation
|
||||
constructor (orientation,element_list){
|
||||
super(element_list)
|
||||
this.#orientation = orientation;
|
||||
}
|
||||
}
|
||||
|
||||
//view for the stock stack
|
||||
class StockView extends StackView{
|
||||
#card_list
|
||||
#stack
|
||||
constructor (stack){
|
||||
super(0, [new CardView(false,50,20)], stack.peek());
|
||||
this.#stack = stack;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//view for the waste stack
|
||||
class WasteView extends StackView{
|
||||
constructor(){
|
||||
super(0);
|
||||
}
|
||||
}
|
||||
|
||||
//view for the vertical columns
|
||||
class ColumnView extends StackView {
|
||||
constructor(){
|
||||
super(1);
|
||||
}
|
||||
}
|
||||
|
||||
//view for the foundations
|
||||
class FoundationView extends StackView {
|
||||
constructor(){
|
||||
super(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TableauView{
|
||||
//passed board object to gen view
|
||||
constructor (board){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//canva rendering manager
|
||||
class RenderMgr{
|
||||
|
||||
#ctx
|
||||
#views
|
||||
#cur_view
|
||||
|
||||
//valid canvas context must be passed
|
||||
constructor(ctx){
|
||||
this.#ctx = ctx;
|
||||
//init bg
|
||||
this.#cur_view = new View([new Background()]);
|
||||
}
|
||||
|
||||
resize(scale){
|
||||
//resize every single element present on view
|
||||
this.#cur_view.resize(scale);
|
||||
}
|
||||
|
||||
render(){
|
||||
this.#cur_view.render(this.#ctx);
|
||||
requestAnimationFrame(this.render.bind(this))
|
||||
}
|
||||
|
||||
parse_view_json(json_str) {
|
||||
var view_list = []
|
||||
console.log(json_str);
|
||||
for (var e in json_str){
|
||||
view_list.push(JSON.parse(e));
|
||||
}
|
||||
console.log(view_list);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KlondikeGame {
|
||||
|
||||
#size_modifier
|
||||
#board
|
||||
#ctx
|
||||
#scale_modifier
|
||||
#mgr
|
||||
|
||||
constructor (){
|
||||
//intialise a new board
|
||||
this.#board = new Board();
|
||||
console.log("initialised board");
|
||||
//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);
|
||||
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 = [resolution[0]/1920, 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.9;
|
||||
canvas.height = window.innerHeight * 0.8;
|
||||
game_instance.update_scale([canvas.width, canvas.height])
|
||||
|
||||
|
||||
}
|
||||
|
||||