diff --git a/src/client/css.css b/src/client/css.css
index e69de29..5add65c 100644
--- a/src/client/css.css
+++ b/src/client/css.css
@@ -0,0 +1,66 @@
+players, player, pot {
+ display: block;
+}
+
+players {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ font-size: 2em;
+}
+
+players > * {
+ width: 10em;
+ flex-grow: 1;
+}
+
+player {
+ background-color: var(--background);
+ margin: .25em;
+ padding: .25em;
+ border-radius: 6px;
+ display: flex;
+ flex-direction: column;
+}
+
+player > * {
+ flex-grow: 1;
+}
+
+player[participating] {
+}
+
+player:not([active]) {
+ opacity: .5;
+}
+
+player[current] {
+ color: var(--code);
+}
+
+player[me] {
+ font-weight: bold;
+}
+
+player[winner] {
+ font-weight: bold;
+ font-size: 3em;
+}
+
+pot {
+ font-size: 3em;
+ display: block;
+ width: 100%;
+ text-align: center;
+}
+
+row {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+card {
+ text-align: center;
+ width: 100%;
+}
diff --git a/src/client/index.html b/src/client/index.html
index 3355321..5d25a43 100644
--- a/src/client/index.html
+++ b/src/client/index.html
@@ -10,10 +10,17 @@
+
+ Debug
+
+
+
+
-
diff --git a/src/client/js.js b/src/client/js.js
index e533a64..50c4d4a 100644
--- a/src/client/js.js
+++ b/src/client/js.js
@@ -75,40 +75,61 @@ class Games {
forUser(id, uid, cb) {
this.get(id, (game) => {
+ var found = false;
game.Players.forEach((player, idx) => {
if (player.ID == uid) {
cb(game.Players[idx]);
+ found = true;
}
});
- games.update(id, game, (game) => {ui.drawGame(game)});
+ if (found)
+ games.update(id, game, (game) => {ui.drawGame(game)});
});
}
- get(id, cb) {
+ get(id, cb, catcher) {
+ if (!catcher)
+ catcher = console.log;
this.requests.get("/api/games/"+id, (text, status) => {
if (status != 200) {
- throw new Error("bad status getting game: "+status+": "+text);
+ catcher("bad status getting game:", text, status);
+ return;
}
var game = JSON.parse(text);
cb(game);
});
}
- create(id, cb) {
+ create(id, cb, catcher) {
+ if (!catcher)
+ catcher = console.log;
this.requests.post("/api/games/"+id, null, (text, status) => {
if (status != 200) {
- throw new Error("bad status creating game: "+status+": "+text);
+ catcher("bad status creating game:", text, status);
+ return;
}
var game = JSON.parse(text);
cb(game);
});
}
- update(id, game, cb) {
+ update(id, game, cb, catcher) {
// TODO compute turn
+ var n = 0;
+ var m = game.Players.length;
+ game.Players.forEach((player) => n += player.Participating ? 1 : 0);
+ game.Turn = game.Turn % (m || 1);
+ if (n)
+ while (m > 0 && (!game.Players[game.Turn].Active || !game.Players[game.Turn].Participating)) {
+ game.Turn = (game.Turn + 1) % game.Players.length;
+ m -= 1;
+ }
+ if (!catcher)
+ catcher = console.log;
this.requests.put("/api/games/"+id, JSON.stringify(game), (text, status) => {
if (status != 200) {
- throw new Error("bad status updating game: "+status+": "+text);
+ catcher("bad status updating game: ", text, status);
+ return;
}
var game2 = JSON.parse(text);
cb(game2);
@@ -121,7 +142,8 @@ class UI {
this.games = games;
this.ts = 0;
this.threshold = 2;
- setInterval(() => { this.refresh() }, 2000);
+ this.refresh();
+ setInterval(() => { this.refresh() }, 500);
}
now() {
@@ -137,36 +159,92 @@ class UI {
});
}
+ formatCurrency(currency) {
+ return `${Math.floor(currency/100)}.${currency%100 < 10 ? "0" : ""}${currency%100}`
+ }
+
+ formatCard(card) {
+ if (card == -1)
+ return `
?`;
+ var suit = card.Suit;
+ var value = card.Value + 2;
+ switch (suit) {
+ case 0 : suit = "hearts"; break;
+ case 1 : suit = "spades"; break;
+ case 2 : suit = "diamonds"; break;
+ case 3 : suit = "clubs"; break;
+ }
+ switch (value) {
+ case 10 : value = "jack"; break;
+ case 11 : value = "queen"; break;
+ case 12 : value = "king"; break;
+ case 13 : value = "ace"; break;
+ }
+ return `
${value} of ${suit}`;
+ }
+
drawGame(game) {
+ var playersActive = 0;
+ var activePlayersChecked = 0;
+ var winning = -1;
+ game.Players.forEach((player, idx) => {
+ if (player.ID != "" && player.Participating && player.Active) {
+ if (winning == -1 || game.Players[winning].Card.Value <= player.Card.Value) {
+ winning = idx;
+ }
+ playersActive += 1;
+ if (player.Checked) {
+ activePlayersChecked += 1;
+ }
+ }
+ });
+ var complete = playersActive < 2 || playersActive == activePlayersChecked;
this.ts = this.now();
var state = `
- ${game.Pot}
+ ${this.formatCurrency(game.Pot)}
`;
+ var myseat = -1;
game.Players.forEach((player, seatnum) => {
if (player.ID != "") {
- state += ``;
+ state += ``;
state += `
- ${player.Name}
- ${player.Balance}
- ${this.me(player) ? "?" : player.Card}
+
+ ${player.Name}
+ ${this.formatCurrency(player.Balance)}
+
+
+ ${this.formatCard(!complete && (this.me(player) || !player.Participating || !player.Active) ? -1 : player.Card)}
+
`;
if (this.me(player)) {
- var myturn = seatnum == game.Turn
- var enabled = player.Active && myturn;
- var eleControlGame = this.eleControlGame();
- var enabledWas = eleControlGame.getAttribute("disabled") == null;
- if (enabled != enabledWas) {
- if (enabled) {
- eleControlGame.removeAttribute("disabled");
- } else {
- eleControlGame.setAttribute("disabled", true);
- }
- }
+ myseat = seatnum;
}
state += ``;
}
});
+ var enabled = myseat == game.Turn && game.Players[myseat].Participating && game.Players[myseat].Active;
+ var eleControlGame = this.eleControlGame();
+ var enabledWas = eleControlGame.getAttribute("disabled") == null;
+ if (enabled != enabledWas) {
+ var foo = (ele) => {
+ ele.removeAttribute("disabled");
+ };
+ if (!enabled) {
+ foo = (ele) => {
+ ele.setAttribute("disabled", true);
+ };
+ }
+ foo(eleControlGame)
+ Array.from(eleControlGame.children).forEach(foo);
+ }
state += "";
this.ele().innerHTML = state;
}
@@ -209,29 +287,10 @@ class Deck {
var idx = Math.floor(Math.random() * 52);
if (!this.cards[idx]) {
this.cards[idx] = 1;
- return idx;
+ return {Suit: idx%4, Value: idx%13};
}
}
}
-
- card(idx) {
- var suit = idx % 4;
- switch (suit) {
- case 0: suit = "hearts"; break;
- case 1: suit = "clubs"; break;
- case 2: suit = "diamonds"; break;
- case 3: suit = "spades"; break;
- }
- var num = idx % 13;
- num += 2
- switch (num) {
- case 10: num = "jack"; break;
- case 11: num = "queen"; break;
- case 12: num = "king"; break;
- case 13: num = "ace"; break;
- }
- return `${num} of ${suit}`;
- }
}
function init() {
@@ -248,16 +307,12 @@ function init() {
games.create("id", () => {
games.update("id", {
- Pot: "$0",
+ Pot: 0,
Players: [
{ID: id, Name: name},
],
}, (game) => ui.drawGame(game));
});
-
- games.get("id", (game) => {
- ui.drawGame(game);
- });
}
function start() {
@@ -272,6 +327,7 @@ function start() {
if (player.Participating) {
n += 1;
game.Players[idx].Active = true;
+ game.Players[idx].Checked = false;
game.Players[idx].Card = deck.draw();
}
});
@@ -289,11 +345,28 @@ function start() {
function join() {
var db = new DB();
var id = db.get("id");
- games.forUser("id", id, (player) => {
- if (player.Participating)
- throw new Error("redundant join");
- player.Participating = true;
- player.Active = false;
+ var name = db.get("name");
+ games.forGame("id", (game) => {
+ var redundant = false;
+ var set = false;
+ for (var i = 0; i < game.Players.length; i++) {
+ if (!set && game.Players[i].ID == "") {
+ game.Players[i] = {
+ ID: id,
+ Name: name,
+ Participating: true,
+ }
+ set = true;
+ } else {
+ redundant = redundant || game.Players[i].ID == id;
+ }
+ }
+ if (!set) {
+ throw new Error("did not take a seat");
+ }
+ if (redundant) {
+ throw new Error("cannot take 2 seats");
+ }
});
}
@@ -301,8 +374,6 @@ function drop() {
var db = new DB();
var id = db.get("id");
games.forUser("id", id, (player) => {
- if (!player.Participating)
- throw new Error("redundant drop");
player.Participating = false;
player.Active = false;
});
@@ -312,8 +383,6 @@ function fold(ele) {
var db = new DB();
var id = db.get("id");
games.forUser("id", id, (player) => {
- if (!player.Active)
- throw new Error("redundant fold");
player.Active = false;
});
}
@@ -323,22 +392,63 @@ function check(ele) {
var id = db.get("id");
games.forGame("id", (game) => {
game.Turn += 1;
+ game.Players.forEach((player) => {
+ if (player.ID == id)
+ player.Checked = true;
+ });
+ });
+}
+
+function collect(ele) {
+ var db = new DB();
+ var id = db.get("id");
+ games.forGame("id", (game) => {
+ var found = false;
+ game.Players.forEach((player, idx) => {
+ if (player.ID == id) {
+ player.Balance += game.Pot;
+ found = true;
+ }
+ });
+ if (!found) {
+ throw new Error("nil player cannot collect pot");
+ }
+ game.Pot = 0;
+ });
+}
+
+function resetGame() {
+ console.log("resetting game");
+ games.forGame("id", (game) => {
+ game.Players = [];
+ game.Turn = 0;
+ game.Pot = 0;
+ });
+}
+
+function setWallet(ele) {
+ var db = new DB();
+ var id = db.get("id");
+ var balance = parseInt(ele.parentNode.getElementsByTagName("input")[0].value);
+ games.forUser("id", id, (player) => {
+ player.Balance = balance;
});
}
function raise(ele) {
var db = new DB();
var id = db.get("id");
- var bump = ele.parentNode.getElementsByTagName("input")[0].value;
+ var bump = parseInt(ele.parentNode.getElementsByTagName("input")[0].value);
games.forGame("id", (game) => {
game.Turn += 1;
game.Players.forEach((player, idx) => {
if (player.ID == id) {
- // todo it's supposed to be a string, should render client-side
player.Balance -= bump;
if (player.Balance < 0)
throw new Error("cannot bet more than you have");
game.Pot += bump;
+ } else {
+ player.Checked = false;
}
});
});
diff --git a/src/server/game.go b/src/server/game.go
index 0f4fc96..57aa615 100644
--- a/src/server/game.go
+++ b/src/server/game.go
@@ -11,14 +11,20 @@ type Game struct {
type Player struct {
ID string
Name string
- Card int
+ Card Card
Balance Currency
Active bool
Participating bool
+ Checked bool
}
type Currency int
+type Card struct {
+ Suit int
+ Value int
+}
+
func (game Game) GetPlayers() []Player {
players := []Player{}
for _, player := range game.Players {