intitial commit
This commit is contained in:
3
backend.js
Normal file
3
backend.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class BackendConnection {
|
||||||
|
|
||||||
|
}
|
||||||
75
card-v2.js
Normal file
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
33
cardgame.html
Normal 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
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
387
game.js
Normal file
387
game.js
Normal 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])
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user