aboutsummaryrefslogtreecommitdiff
path: root/src/math
diff options
context:
space:
mode:
Diffstat (limited to 'src/math')
-rw-r--r--src/math/index.html29
-rw-r--r--src/math/server.js13
-rw-r--r--src/math/static/black-hole.js181
-rw-r--r--src/math/static/card31.js8
-rw-r--r--src/math/static/help.js21
-rw-r--r--src/math/static/kings-corner.js357
-rw-r--r--src/math/static/main.js149
-rw-r--r--src/math/static/nim.js102
-rw-r--r--src/math/static/solitaire.js8
9 files changed, 868 insertions, 0 deletions
diff --git a/src/math/index.html b/src/math/index.html
new file mode 100644
index 0000000..440e7ff
--- /dev/null
+++ b/src/math/index.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+ <title>Math Games</title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+ <style>
+ canvas {
+ /* transform-origin: top left; */
+ /* transform: scale(4, 4); */
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+ </style>
+</head>
+
+<body style="padding:0; margin:0; overflow:hidden;">
+ <canvas id="canvas"></canvas>
+ <script src="/math/static/help.js"></script>
+ <script src="/math/static/nim.js"></script>
+ <script src="/math/static/solitaire.js"></script>
+ <script src="/math/static/kings-corner.js"></script>
+ <script src="/math/static/black-hole.js"></script>
+ <script src="/math/static/main.js"></script>
+</body>
+
+</html>
diff --git a/src/math/server.js b/src/math/server.js
new file mode 100644
index 0000000..e68a41b
--- /dev/null
+++ b/src/math/server.js
@@ -0,0 +1,13 @@
+const path = require('path');
+const fs = require('fs');
+const express = require('express');
+
+function setUpRoutes(server, models, jwtFunctions, database) {
+ server.get('/math', (req, res) => res.sendFile(__dirname + "/index.html"))
+ server.get('/math/styles.css', (req, res) => res.sendFile(__dirname + "/static/styles.css"))
+ server.use('/math/static', express.static(__dirname + '/static'))
+}
+
+module.exports = {
+ setUpRoutes
+};
diff --git a/src/math/static/black-hole.js b/src/math/static/black-hole.js
new file mode 100644
index 0000000..f6b7f8e
--- /dev/null
+++ b/src/math/static/black-hole.js
@@ -0,0 +1,181 @@
+var black_hole = {
+ status: "",
+ state: -1,
+ rowOf: {
+ 0: 0,
+ 1: 0,
+ 2: 0,
+ 3: 0,
+ 4: 0,
+ 5: 0,
+ 6: 1,
+ 7: 1,
+ 8: 1,
+ 9: 1,
+ 10: 1,
+ 11: 2,
+ 12: 2,
+ 13: 2,
+ 14: 2,
+ 15: 3,
+ 16: 3,
+ 17: 3,
+ 18: 4,
+ 19: 4,
+ 20: 5,
+ },
+ colOf: {
+ 0: 0,
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ 4: 4,
+ 5: 5,
+ 6: 0,
+ 7: 1,
+ 8: 2,
+ 9: 3,
+ 10: 4,
+ 11: 0,
+ 12: 1,
+ 13: 2,
+ 14: 3,
+ 15: 0,
+ 16: 1,
+ 17: 2,
+ 18: 0,
+ 19: 1,
+ 20: 0,
+ },
+ canPlay: function (index) {
+ return this.board[index] == undefined
+ },
+ setup: function () {
+ this.board = [];
+ for(var i =0; i < 21; i++){
+ this.board.push(undefined);
+ }
+ this.turn = 1
+ },
+
+ play: function () {
+
+ },
+ other_play: function () {
+ var madePlay = false
+ while (!madePlay) {
+ // guess random
+ var index = Math.floor(Math.random() * 21)
+ if(this.canPlay(index)){
+ black_hole.board[index] = {
+ "color": "blue",
+ "value": Math.ceil(black_hole.turn / 2)
+ }
+ black_hole.turn++
+ madePlay = true
+ }
+ }
+
+ },
+};
+black_hole.updateCallback = function () {
+ if(black_hole.turn == 21 && black_hole.state < 2) {
+ black_hole.state = 2
+ }
+
+ if (black_hole.state == -1){ // setup
+ black_hole.setup();
+ black_hole.state = 0
+ } else if (black_hole.state == 0) { // player turn
+ // nothing, wait for click
+ } else if (black_hole.state == 1) { // other turn
+ black_hole.other_play();
+ black_hole.state = 0
+ } else if (black_hole.state == 2) { // calculate end
+ score = {"blue": 0, "red": 0}
+ black_hole.board.forEach((spot, i) => {
+ if(spot == undefined){
+ var row = black_hole.rowOf[i];
+ var col = black_hole.colOf[i];
+ black_hole.board.forEach((other_spot, j) => {
+ var row2 = black_hole.rowOf[j];
+ var col2 = black_hole.colOf[j];
+ if(other_spot != undefined &&
+ (
+ (row == row2-1 && 0 <= (col - col2) && (col - col2) <= 1) ||
+ (row == row2 && Math.abs(col - col2) <= 1) ||
+ (row == row2+1 && 0 <= (col2 - col) && (col2 - col) <= 1)
+ )
+ ){
+ score[other_spot.color] += other_spot.value
+ }
+ })
+ }
+ })
+ black_hole.score = score
+ if(score.red < score.blue){
+ black_hole.winner = "red"
+ } else {
+ black_hole.winner = "blue"
+ }
+ black_hole.state = -1;
+ switchState(menu);
+ }
+}
+black_hole.drawCallback = function () {
+ if(black_hole.state < 0){
+ return;
+ }
+ ctx.fillStyle = "#99b3ff";
+ ctx.fillRect(0, 0, width, height);
+
+
+ ctx.lineWidth = 2;
+ black_hole.board.forEach((spot, i) => {
+ var row = black_hole.rowOf[i];
+ var col = black_hole.colOf[i];
+ if(spot == undefined){
+ ctx.fillStyle = "black";
+ ctx.strokeStyle = "black"
+ } else {
+ ctx.fillStyle = spot["color"];
+ ctx.strokeStyle = spot["color"]
+ ctx.fillText(spot["value"], 100 + row * 100 + col * 50, 100 + col*88)
+ }
+ ctx.beginPath();
+ ctx.arc(100 + row * 100 + col * 50, 100 + col*88, 50, 0, 2 * Math.PI);
+ ctx.stroke();
+ })
+
+ if(black_hole.winner){
+ font(32);
+ ctx.fillStyle = "black";
+ ctx.fillText(black_hole.winner + " wins!", 550, 330)
+ ctx.fillText("red: " + black_hole.score.red, 550, 370)
+ ctx.fillText("blue: " + black_hole.score.blue, 550, 410)
+ }
+}
+black_hole.mouseDownCallback = function (e) {
+ if(black_hole.state == 3){
+ return;
+ }
+
+ black_hole.board.forEach((spot, i) => {
+ var row = black_hole.rowOf[i];
+ var col = black_hole.colOf[i];
+ var x = 100 + row * 100 + col * 50;
+ var y = 100 + col*88;
+ if(spot == undefined && Math.sqrt(Math.pow(x - e.x, 2) + Math.pow(y - e.y, 2)) < 50){
+ console.log(i);
+ black_hole.board[i] = {
+ "color": "red",
+ "value": Math.ceil(black_hole.turn / 2)
+ }
+ black_hole.turn++;
+ black_hole.state = 1
+ }
+ })
+}
+black_hole.mouseUpCallback = function (e) {
+
+} \ No newline at end of file
diff --git a/src/math/static/card31.js b/src/math/static/card31.js
new file mode 100644
index 0000000..c2b6172
--- /dev/null
+++ b/src/math/static/card31.js
@@ -0,0 +1,8 @@
+var solitaire = {};
+solitaire.updateCallback = function(){
+
+}
+solitaire.drawCallback = function(){
+ ctx.fillStyle = "green";
+ ctx.fillRect(0, 0, width, height);
+} \ No newline at end of file
diff --git a/src/math/static/help.js b/src/math/static/help.js
new file mode 100644
index 0000000..2dfab9f
--- /dev/null
+++ b/src/math/static/help.js
@@ -0,0 +1,21 @@
+var help = {
+
+};
+help.updateCallback = function(){
+ // nothing
+}
+help.drawCallback = function(){
+ ctx.fillStyle = "#99b3ff";
+ ctx.fillRect(0, 0, width, height);
+
+ font(26)
+ ctx.fillStyle = "black"
+ ctx.fillText("Click on a game to play.", 10, 200)
+ ctx.fillText("After finishing your game, click to return.", 10, 230)
+}
+help.mouseDownCallback = function (e) {
+ switchState(menu);
+}
+help.mouseUpCallback = function(e){
+
+} \ No newline at end of file
diff --git a/src/math/static/kings-corner.js b/src/math/static/kings-corner.js
new file mode 100644
index 0000000..c182b56
--- /dev/null
+++ b/src/math/static/kings-corner.js
@@ -0,0 +1,357 @@
+var kings_corner = {
+ suit_color: {
+ "C": "black",
+ "S": "black",
+ "H": "red",
+ "D": "red"
+ },
+ value_to_num: {
+ "A": 0,
+ "2": 1,
+ "3": 2,
+ "4": 3,
+ "5": 4,
+ "6": 5,
+ "7": 6,
+ "8": 7,
+ "9": 8,
+ "10": 9,
+ "J": 10,
+ "Q": 11,
+ "K": 12
+ },
+ selected: [],
+ selected_positions: [],
+ status: "",
+ state: -1,
+ shuffle: function (a) {
+ var j, x, i;
+ for (i = a.length - 1; i > 0; i--) {
+ j = Math.floor(Math.random() * (i + 1));
+ x = a[i];
+ a[i] = a[j];
+ a[j] = x;
+ }
+ return a;
+ },
+ canBePlayedOn: function (bottom, top, board_position) {
+ if (top == undefined) {
+ return false;
+ }
+ if (bottom == undefined) {
+ return top.value == "K" || board_position < 4;
+ }
+ if (this.suit_color[bottom.suit] != this.suit_color[top.suit]) {
+ return this.value_to_num[bottom.value] - this.value_to_num[top.value] == 1;
+ } else {
+ return false;
+ }
+ },
+ findBoardPosition(cards) {
+ var board_position;
+ for (var index = 0; index < this.board.length; index++) {
+ if (this.board[index] == cards) {
+ board_position = index;
+ }
+ }
+ return board_position
+ },
+ canPlayBoardHand: function (cards, hand) {
+ var bottom = cards[cards.length - 1];
+ var board_position = this.findBoardPosition(cards);
+ return this.canBePlayedOn(bottom, hand, board_position)
+ },
+ canPlay: function () {
+ if (this.selected_positions[0] == "board"
+ && this.selected_positions[1] == "hand") {
+ return this.canPlayBoardHand(this.selected[0], this.selected[1])
+ } else if (this.selected_positions[1] == "board"
+ && this.selected_positions[0] == "hand") {
+ return this.canPlayBoardHand(this.selected[1], this.selected[0])
+ } else if (this.selected_positions[0] == "board"
+ && this.selected_positions[1] == "board") {
+
+ var cards1 = this.selected[1];
+ var cards2 = this.selected[0];
+ var top = cards1[0]
+ var bottom = cards2[cards2.length - 1]
+ var board_position = this.findBoardPosition(cards2);
+ if (this.canBePlayedOn(bottom, top, board_position)) {
+ return true;
+ }
+ top = cards2[0]
+ bottom = cards1[cards1.length - 1]
+ board_position = this.findBoardPosition(cards1);
+ if (this.canBePlayedOn(bottom, top, board_position)) {
+ return true;
+ }
+ }
+ return false;
+ },
+ setup: function () {
+ this.deck = [];
+ Object.keys(this.value_to_num).forEach((value) => {
+ Object.keys(this.suit_color).forEach((suit) => {
+ kings_corner.deck.push({ suit: suit, value: value });
+ })
+ })
+ this.shuffle(this.deck);
+ this.board = [[this.deck.pop()], [this.deck.pop()],
+ [this.deck.pop()], [this.deck.pop()],
+ [], [], [], []]
+ this.hand = []
+ this.other_hand = []
+ for (var i = 0; i < 7; i++) {
+ this.hand.push(this.deck.pop());
+ this.other_hand.push(this.deck.pop());
+ }
+ this.hand.push(this.deck.pop());
+ },
+ removeCard: function (arr, c) {
+ return arr.filter((card) => {
+ return !(card.value == c.value && card.suit == c.suit);
+ })
+ },
+ play: function () {
+ if (this.selected.length != 2) {
+ this.state = 1
+ } else if (this.canPlay()) {
+ if (this.selected_positions[0] == "board" && this.selected_positions[1] == "hand") {
+ var cards = this.selected[0];
+ var top = this.selected[1];
+ cards.push(top);
+ this.hand = this.removeCard(this.hand, top)
+ } else if (this.selected_positions[1] == "board" && this.selected_positions[0] == "hand") {
+ var cards = this.selected[1];
+ var top = this.selected[0];
+ cards.push(top);
+ this.hand = this.removeCard(this.hand, top)
+ } else if (this.selected_positions[0] == "board" && this.selected_positions[1] == "board") {
+ var cards1 = this.selected[1];
+ var cards2 = this.selected[0];
+ var top = cards1[0]
+ var bottom = cards2[cards2.length - 1]
+ var board_position = this.findBoardPosition(cards2);
+ if (this.canBePlayedOn(bottom, top, board_position)) {
+ while (this.selected[1].length > 0) {
+ this.selected[0].push(this.selected[1].shift());
+ }
+ return;
+ }
+ top = cards2[0]
+ bottom = cards1[cards1.length - 1]
+ board_position = this.findBoardPosition(cards1);
+ if (this.canBePlayedOn(bottom, top, board_position)) {
+ while (this.selected[0].length > 0) {
+ this.selected[1].push(this.selected[0].shift());
+ }
+ return;
+ }
+ }
+ } else {
+ console.log("no play")
+ }
+ },
+ other_play: function () {
+ var madePlay = true
+ var playedCards = [];
+ while (madePlay && this.other_hand.length > 0) {
+ madePlay = false;
+ for (var i = 0; i < this.other_hand.length; i++) {
+ let card = this.other_hand[i]
+ for (var index = 0; index < this.board.length; index++) {
+ var top = card;
+ var cards = this.board[index];
+ var bottom = cards[cards.length - 1];
+ if (this.canBePlayedOn(bottom, top, index)) {
+ cards.push(card);
+ this.other_hand = this.removeCard(this.other_hand, card)
+ playedCards.push(card);
+ console.log(madePlay)
+ madePlay = true
+ break;
+ }
+
+ }
+ if (madePlay) {
+ break;
+ }
+ }
+ for (var index1 = 0; index1 < this.board.length; index1++) {
+ for (var index2 = 0; index2 < this.board.length; index2++) {
+ var cards1 = this.board[index1];
+ var cards2 = this.board[index2];
+ var top = cards1[0]
+ var bottom = cards2[cards2.length - 1]
+ var board_position = this.findBoardPosition(cards2);
+ if (index1 >= 4) {
+ continue
+ // dont move a king to the left
+ }
+ if (this.canBePlayedOn(bottom, top, board_position)) {
+ while (cards1.length > 0) {
+ cards2.push(cards1.shift());
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if (playedCards.length == 0) {
+ this.status = "They played nothing"
+ } else {
+ this.status = "They played "
+ for (var index = 0; index < playedCards.length - 1; index++) {
+ this.status += `${playedCards[index].value} of ${playedCards[index].suit}, `
+ }
+ this.status += `${playedCards[playedCards.length - 1].value} of ${playedCards[playedCards.length - 1].suit}`
+ }
+ },
+};
+kings_corner.updateCallback = function () {
+ if (kings_corner.state == -1){ // setup
+ kings_corner.setup();
+ kings_corner.state = 0
+ } else if (kings_corner.state == 0) { // player turn
+ if (kings_corner.hand.length == 0) {
+ kings_corner.status = "You win!"
+ kings_corner.state = 2
+ return;
+ }
+ } else if (kings_corner.state == 1) { // other turn
+ kings_corner.other_hand.push(kings_corner.deck.pop());
+ kings_corner.other_play();
+ if (kings_corner.other_hand.length == 0) {
+ kings_corner.status = "You lose!"
+ kings_corner.state = 3
+ return;
+ }
+ kings_corner.state = 0
+ kings_corner.hand.push(kings_corner.deck.pop());
+ } else if (kings_corner.state == 2 || kings_corner.state == 3) {
+ // nothing
+ }
+}
+kings_corner.drawCallback = function () {
+ if(kings_corner.state < 0){
+ return;
+ }
+ ctx.fillStyle = "#99b3ff";
+ ctx.fillRect(0, 0, width, height);
+
+ font(26)
+ ctx.fillStyle = "lime";
+ ctx.fillRect(5, 5, 90, 40);
+ ctx.fillStyle = "black"
+ if (kings_corner.selected.length != 2) {
+ ctx.fillText("Pass", 10, 30);
+ } else {
+ ctx.fillText("Play", 10, 30);
+ }
+
+ ctx.fillStyle = "black"
+ ctx.fillText("You", 10, 240)
+ kings_corner.hand.forEach((card, i) => {
+ if (kings_corner.selected.includes(card)) {
+ ctx.fillStyle = "#CCC"
+ } else {
+ ctx.fillStyle = "white";
+ }
+ ctx.fillRect(i * 75 + 100, 210, 70, 120);
+ ctx.fillStyle = kings_corner.suit_color[card.suit]
+ ctx.fillText(card.suit, i * 75 + 105, 250)
+ ctx.fillText(card.value, i * 75 + 105, 230)
+ })
+
+ ctx.fillStyle = "black"
+ ctx.fillText("Other", 10, 360)
+ kings_corner.other_hand.forEach((card, i) => {
+ ctx.fillStyle = "blue"
+ ctx.fillRect(i * 75 + 100, 340, 70, 120);
+ })
+
+ ctx.fillStyle = "black"
+ ctx.fillText(kings_corner.status, 100, 500)
+
+ ctx.fillStyle = "black"
+ ctx.fillText("Board", 10, 120)
+ kings_corner.board.forEach((cards, i) => {
+ if (kings_corner.selected.includes(cards)) {
+ ctx.fillStyle = "#CCC"
+ } else {
+ ctx.fillStyle = "white";
+ }
+ ctx.fillRect(i * 75 + 100, 80, 70, 120);
+ ctx.fillStyle = "black"
+ // var card = kings_corner.board[i];
+ var top = cards[cards.length - 1];
+ var bottom = cards[0];
+ if (top != undefined) {
+ ctx.fillStyle = kings_corner.suit_color[top.suit]
+ ctx.fillText(top.suit, i * 75 + 105, 160)
+ ctx.fillText(top.value, i * 75 + 105, 180)
+
+ if (top != bottom) {
+ ctx.fillStyle = kings_corner.suit_color[bottom.suit]
+ ctx.fillText(bottom.suit, i * 75 + 105, 120)
+ ctx.fillText(bottom.value, i * 75 + 105, 100)
+ }
+ }
+ })
+ if(kings_corner.state >= 2){
+ kings_corner.state = -1;
+ switchState(menu);
+ }
+}
+kings_corner.mouseDownCallback = function (e) {
+ if(kings_corner.state != 0){
+ return;
+ }
+
+ if (5 < e.x && e.x < 95 && 5 < e.y && e.y < 95) {
+ kings_corner.play();
+ return
+ }
+
+ var new_selected = false
+ kings_corner.hand.forEach((card, i) => {
+ if (i * 75 + 100 < e.x && e.x < i * 75 + 170 &&
+ 210 < e.y && e.y < 330) {
+
+ kings_corner.selected.unshift(card);
+ if (kings_corner.selected.length > 2) {
+ kings_corner.selected.pop();
+ }
+ kings_corner.selected_positions.unshift("hand");
+ if (kings_corner.selected_positions.length > 2) {
+ kings_corner.selected_positions.pop();
+ }
+ new_selected = true
+ }
+ })
+
+ kings_corner.board.forEach((cards, i) => {
+ if (i * 75 + 100 < e.x && e.x < i * 75 + 170 &&
+ 80 < e.y && e.y < 200) {
+
+ kings_corner.selected.unshift(cards);
+ if (kings_corner.selected.length > 2) {
+ kings_corner.selected.pop();
+ }
+ kings_corner.selected_positions.unshift("board");
+ if (kings_corner.selected_positions.length > 2) {
+ kings_corner.selected_positions.pop();
+ }
+ new_selected = true
+ }
+ })
+
+ if (!new_selected) {
+ kings_corner.selected = []
+ kings_corner.selected_positions = []
+ }
+}
+kings_corner.mouseUpCallback = function (e) {
+
+} \ No newline at end of file
diff --git a/src/math/static/main.js b/src/math/static/main.js
new file mode 100644
index 0000000..d66f48c
--- /dev/null
+++ b/src/math/static/main.js
@@ -0,0 +1,149 @@
+// The callbacks to be called each frame on update,
+// and on draw
+var updateCallback, drawCallback, mouseDownCallback, mouseUpCallback;
+// The interval object
+var gameInterval;
+let width = 800;
+let height = 600;
+let fps = 30;
+
+window.onload = function () {
+ canvas = document.getElementById("canvas");
+ ctx = canvas.getContext("2d");
+ canvas.width = width;
+ canvas.height = height;
+ document.addEventListener("keydown", keyPush);
+ document.addEventListener("mousedown", mouseDown);
+ document.addEventListener("mouseup", mouseUp);
+ init();
+}
+
+function switchState(game) {
+ updateCallback = game.updateCallback;
+ drawCallback = game.drawCallback;
+ mouseDownCallback = game.mouseDownCallback;
+ mouseUpCallback = game.mouseUpCallback;
+}
+
+function game() {
+ updateCallback();
+ drawCallback();
+}
+
+function init() {
+ switchState(menu);
+ gameInterval = setInterval(game, 1000 / fps);
+
+ let buttonX = (width / 5) * 1 // 2/5 the width
+ let buttonWidth = (width / 5) * 3
+ let buttonHeight = 40
+ menu.buttons.forEach((gameData, i) => {
+ gameData.x = buttonX;
+ gameData.y = (buttonHeight + 10) * i + 200;
+ gameData.width = buttonWidth;
+ gameData.height = buttonHeight;
+ })
+ menu.buttons.push({
+ x: 680,
+ y: 530,
+ width: 100,
+ height: buttonHeight,
+ name: "Help",
+ game: help,
+ })
+}
+
+var menu = {
+ "buttons": [
+ {
+ "name": "Nim",
+ "game": nim,
+ },
+ // {
+ // "name": "Solitaire",
+ // "game": solitaire,
+ // },
+ {
+ "name": "Kings Corner",
+ "game": kings_corner,
+ },
+ {
+ "name": "Black Hole",
+ "game": black_hole,
+ },
+ ]
+};
+menu.updateCallback = function () {
+
+}
+menu.drawCallback = function () {
+ font(48);
+ ctx.fillStyle = "#99b3ff";
+ ctx.fillRect(0, 0, width, height);
+
+ menu.buttons.forEach((gameData, i) => {
+ button(gameData.x, gameData.y, gameData.width, gameData.height, gameData.name, gameData.isClicked);
+ })
+}
+
+menu.mouseDownCallback = function (e) {
+ let newGame = buttonAt(e.x, e.y, menu.buttons);
+ if(newGame){
+ newGame.isClicked = true;
+ }
+}
+
+menu.mouseUpCallback = function (e) {
+ let newGame = buttonAt(e.x, e.y, menu.buttons);
+ if(newGame && newGame.isClicked){
+ switchState(newGame.game)
+ }
+ menu.buttons.forEach((gameData, i) => {
+ gameData.isClicked = false;
+ })
+}
+
+function buttonAt(x, y, buttons) {
+ return buttons.find((gameData, i) => {
+ if (gameData.x < x && x < gameData.x + gameData.width
+ && gameData.y < y && y < gameData.y + gameData.height) {
+ return true;
+ }
+ })
+}
+
+function font(size) {
+ ctx.font = size + "px Courier";
+}
+
+function keyPush(e) {
+
+}
+
+function mouseDown(e) {
+ mouseDownCallback(e);
+}
+
+function mouseUp(e) {
+ mouseUpCallback(e);
+}
+
+function button(x, y, w, h, text, isClicked){
+ if(isClicked){
+ ctx.fillStyle = "grey"
+ } else {
+ ctx.fillStyle = "darkgrey"
+ }
+ ctx.fillRect(x, y, w, h);
+ ctx.strokeStyle = "black"
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(x+w, y);
+ ctx.lineTo(x+w, y+h);
+ ctx.lineTo(x, y+h);
+ ctx.lineTo(x, y);
+ ctx.stroke();
+ font(36);
+ ctx.fillStyle = "black"
+ ctx.fillText(text, x+5, y+h-8)
+}
diff --git a/src/math/static/nim.js b/src/math/static/nim.js
new file mode 100644
index 0000000..b8d1665
--- /dev/null
+++ b/src/math/static/nim.js
@@ -0,0 +1,102 @@
+var nim = {
+ pieces: 10,
+ buttons: [
+ {
+ "name": "1",
+ "x": 50,
+ "y": 50,
+ "width": 50,
+ "height": 50,
+ "value": 1
+ },
+ {
+ "name": "2",
+ "x": 50,
+ "y": 125,
+ "width": 50,
+ "height": 50,
+ "value": 2
+ }
+ ],
+ status: "It is your turn",
+ gameOver: false,
+};
+var nimSetup = false;
+nim.updateCallback = function(){
+ // Check for who wins/reset/etc
+}
+nim.drawCallback = function(){
+ ctx.fillStyle = "#99b3ff";
+ ctx.fillRect(0, 0, width, height);
+ nim.buttons.forEach((b, i) => {
+ button(b.x, b.y, 50, 50, b.name, b.isClicked);
+ })
+
+ ctx.fillStyle = "green"
+ for(var i = 0; i < nim.pieces; i++){
+ ctx.beginPath();
+ ctx.arc(175 + i * 50, 300 + (i%2)*50, 25, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+ ctx.fillStyle = "grey"
+ for(var i = nim.pieces; i < 10; i++){
+ ctx.beginPath();
+ ctx.arc(175 + i * 50, 300 + (i%2)*50, 25, 0, 2 * Math.PI);
+ ctx.fill();
+ }
+
+ font(26)
+ ctx.fillStyle = "black"
+ ctx.fillText(nim.status, 175, 75)
+}
+nim.mouseDownCallback = function (e) {
+ if(nim.gameOver){
+ nim.pieces = 10;
+ nim.gameOver = false;
+ nim.status = "It is your turn";
+ switchState(menu);
+ return;
+ }
+ let choice = buttonAt(e.x, e.y, nim.buttons);
+ if(choice){
+ choice.isClicked = true;
+ }
+}
+nim.mouseUpCallback = function (e) {
+ let choice = buttonAt(e.x, e.y, nim.buttons);
+ if(choice && choice.isClicked){
+ nim.turn(choice.value);
+ }
+ nim.buttons.forEach((gameData, i) => {
+ gameData.isClicked = false;
+ })
+}
+nim.subtract = function(value){
+ nim.pieces -= value;
+ if(nim.pieces < 0){
+ nim.pieces = 0;
+ }
+}
+nim.turn = function(value){
+ nim.subtract(value);
+ if(nim.pieces == 0){
+ nim.gameOver = true;
+ nim.status = "You win!"
+ return;
+ }
+ if(nim.pieces % 3 == 0){
+ nim.subtract(1);
+ nim.status = "The other player took 1"
+ } else if(nim.pieces % 3 == 1){
+ nim.subtract(1);
+ nim.status = "The other player took 1"
+ } else if(nim.pieces % 3 == 2){
+ nim.subtract(2);
+ nim.status = "The other player took 2"
+ }
+ if(nim.pieces == 0){
+ this.gameOver = true;
+ nim.status = "You lose!"
+ return;
+ }
+} \ No newline at end of file
diff --git a/src/math/static/solitaire.js b/src/math/static/solitaire.js
new file mode 100644
index 0000000..c2b6172
--- /dev/null
+++ b/src/math/static/solitaire.js
@@ -0,0 +1,8 @@
+var solitaire = {};
+solitaire.updateCallback = function(){
+
+}
+solitaire.drawCallback = function(){
+ ctx.fillStyle = "green";
+ ctx.fillRect(0, 0, width, height);
+} \ No newline at end of file