cant match but bretty good overall
This commit is contained in:
@@ -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%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,10 +10,17 @@
|
|||||||
<button onclick="start(); return false;">Start</button>
|
<button onclick="start(); return false;">Start</button>
|
||||||
<button onclick="join(); return false;">Join</button>
|
<button onclick="join(); return false;">Join</button>
|
||||||
<button onclick="drop(); return false;">Drop</button>
|
<button onclick="drop(); return false;">Drop</button>
|
||||||
|
<details>
|
||||||
|
<summary>Debug</summary>
|
||||||
|
<button onclick="resetGame(); return false;">RESET</button>
|
||||||
|
<input min=0 type="number"/>
|
||||||
|
<button onclick="setWallet(this); return false;">Set wallet cents</button>
|
||||||
|
</details>
|
||||||
</form>
|
</form>
|
||||||
<form id="control-game" onsubmit="return false;">
|
<form id="control-game" onsubmit="return false;" >
|
||||||
<button onclick="fold(this); return false;">Fold</button>
|
<button onclick="fold(this); return false;">Fold</button>
|
||||||
<button onclick="check(this); return false;">Check</button>
|
<button onclick="check(this); return false;">Check</button>
|
||||||
|
<button onclick="collect(this); return false;">Collect</button>
|
||||||
<input min=0 type="number"/>
|
<input min=0 type="number"/>
|
||||||
<button onclick="raise(this); return false;">Raise cents</button>
|
<button onclick="raise(this); return false;">Raise cents</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
226
src/client/js.js
226
src/client/js.js
@@ -75,40 +75,61 @@ class Games {
|
|||||||
|
|
||||||
forUser(id, uid, cb) {
|
forUser(id, uid, cb) {
|
||||||
this.get(id, (game) => {
|
this.get(id, (game) => {
|
||||||
|
var found = false;
|
||||||
game.Players.forEach((player, idx) => {
|
game.Players.forEach((player, idx) => {
|
||||||
if (player.ID == uid) {
|
if (player.ID == uid) {
|
||||||
cb(game.Players[idx]);
|
cb(game.Players[idx]);
|
||||||
|
found = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (found)
|
||||||
games.update(id, game, (game) => {ui.drawGame(game)});
|
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) => {
|
this.requests.get("/api/games/"+id, (text, status) => {
|
||||||
if (status != 200) {
|
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);
|
var game = JSON.parse(text);
|
||||||
cb(game);
|
cb(game);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
create(id, cb) {
|
create(id, cb, catcher) {
|
||||||
|
if (!catcher)
|
||||||
|
catcher = console.log;
|
||||||
this.requests.post("/api/games/"+id, null, (text, status) => {
|
this.requests.post("/api/games/"+id, null, (text, status) => {
|
||||||
if (status != 200) {
|
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);
|
var game = JSON.parse(text);
|
||||||
cb(game);
|
cb(game);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id, game, cb) {
|
update(id, game, cb, catcher) {
|
||||||
// TODO compute turn
|
// 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) => {
|
this.requests.put("/api/games/"+id, JSON.stringify(game), (text, status) => {
|
||||||
if (status != 200) {
|
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);
|
var game2 = JSON.parse(text);
|
||||||
cb(game2);
|
cb(game2);
|
||||||
@@ -121,7 +142,8 @@ class UI {
|
|||||||
this.games = games;
|
this.games = games;
|
||||||
this.ts = 0;
|
this.ts = 0;
|
||||||
this.threshold = 2;
|
this.threshold = 2;
|
||||||
setInterval(() => { this.refresh() }, 2000);
|
this.refresh();
|
||||||
|
setInterval(() => { this.refresh() }, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
now() {
|
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 `<br>?`;
|
||||||
|
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 `<br>${value} of ${suit}`;
|
||||||
|
}
|
||||||
|
|
||||||
drawGame(game) {
|
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();
|
this.ts = this.now();
|
||||||
var state = `
|
var state = `
|
||||||
<pot>${game.Pot}</pot>
|
<pot>${this.formatCurrency(game.Pot)}</pot>
|
||||||
<players>
|
<players>
|
||||||
`;
|
`;
|
||||||
|
var myseat = -1;
|
||||||
game.Players.forEach((player, seatnum) => {
|
game.Players.forEach((player, seatnum) => {
|
||||||
if (player.ID != "") {
|
if (player.ID != "") {
|
||||||
state += `<player ${player.Participating ? "participating" : ""} ${player.Active ? "active" : ""}>`;
|
state += `<player
|
||||||
|
${this.me(player) ? "me" : ""}
|
||||||
|
${player.Participating ? "participating" : ""}
|
||||||
|
${player.Active ? "active" : ""}
|
||||||
|
${player.Checked ? "checked" : ""}
|
||||||
|
${game.Turn == seatnum ? "current" : ""}
|
||||||
|
${complete && winning == seatnum ? "winner" : ""}
|
||||||
|
>`;
|
||||||
state += `
|
state += `
|
||||||
|
<row>
|
||||||
<name>${player.Name}</name>
|
<name>${player.Name}</name>
|
||||||
<balance>${player.Balance}</balance>
|
<balance>${this.formatCurrency(player.Balance)}</balance>
|
||||||
<card>${this.me(player) ? "?" : player.Card}</card>
|
</row>
|
||||||
|
<row>
|
||||||
|
<card>${this.formatCard(!complete && (this.me(player) || !player.Participating || !player.Active) ? -1 : player.Card)}</card>
|
||||||
|
</row>
|
||||||
`;
|
`;
|
||||||
if (this.me(player)) {
|
if (this.me(player)) {
|
||||||
var myturn = seatnum == game.Turn
|
myseat = seatnum;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
state += `</player>`;
|
state += `</player>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
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 += "</players>";
|
state += "</players>";
|
||||||
this.ele().innerHTML = state;
|
this.ele().innerHTML = state;
|
||||||
}
|
}
|
||||||
@@ -209,29 +287,10 @@ class Deck {
|
|||||||
var idx = Math.floor(Math.random() * 52);
|
var idx = Math.floor(Math.random() * 52);
|
||||||
if (!this.cards[idx]) {
|
if (!this.cards[idx]) {
|
||||||
this.cards[idx] = 1;
|
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() {
|
function init() {
|
||||||
@@ -248,16 +307,12 @@ function init() {
|
|||||||
|
|
||||||
games.create("id", () => {
|
games.create("id", () => {
|
||||||
games.update("id", {
|
games.update("id", {
|
||||||
Pot: "$0",
|
Pot: 0,
|
||||||
Players: [
|
Players: [
|
||||||
{ID: id, Name: name},
|
{ID: id, Name: name},
|
||||||
],
|
],
|
||||||
}, (game) => ui.drawGame(game));
|
}, (game) => ui.drawGame(game));
|
||||||
});
|
});
|
||||||
|
|
||||||
games.get("id", (game) => {
|
|
||||||
ui.drawGame(game);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
@@ -272,6 +327,7 @@ function start() {
|
|||||||
if (player.Participating) {
|
if (player.Participating) {
|
||||||
n += 1;
|
n += 1;
|
||||||
game.Players[idx].Active = true;
|
game.Players[idx].Active = true;
|
||||||
|
game.Players[idx].Checked = false;
|
||||||
game.Players[idx].Card = deck.draw();
|
game.Players[idx].Card = deck.draw();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -289,11 +345,28 @@ function start() {
|
|||||||
function join() {
|
function join() {
|
||||||
var db = new DB();
|
var db = new DB();
|
||||||
var id = db.get("id");
|
var id = db.get("id");
|
||||||
games.forUser("id", id, (player) => {
|
var name = db.get("name");
|
||||||
if (player.Participating)
|
games.forGame("id", (game) => {
|
||||||
throw new Error("redundant join");
|
var redundant = false;
|
||||||
player.Participating = true;
|
var set = false;
|
||||||
player.Active = 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 db = new DB();
|
||||||
var id = db.get("id");
|
var id = db.get("id");
|
||||||
games.forUser("id", id, (player) => {
|
games.forUser("id", id, (player) => {
|
||||||
if (!player.Participating)
|
|
||||||
throw new Error("redundant drop");
|
|
||||||
player.Participating = false;
|
player.Participating = false;
|
||||||
player.Active = false;
|
player.Active = false;
|
||||||
});
|
});
|
||||||
@@ -312,8 +383,6 @@ function fold(ele) {
|
|||||||
var db = new DB();
|
var db = new DB();
|
||||||
var id = db.get("id");
|
var id = db.get("id");
|
||||||
games.forUser("id", id, (player) => {
|
games.forUser("id", id, (player) => {
|
||||||
if (!player.Active)
|
|
||||||
throw new Error("redundant fold");
|
|
||||||
player.Active = false;
|
player.Active = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -323,22 +392,63 @@ function check(ele) {
|
|||||||
var id = db.get("id");
|
var id = db.get("id");
|
||||||
games.forGame("id", (game) => {
|
games.forGame("id", (game) => {
|
||||||
game.Turn += 1;
|
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) {
|
function raise(ele) {
|
||||||
var db = new DB();
|
var db = new DB();
|
||||||
var id = db.get("id");
|
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) => {
|
games.forGame("id", (game) => {
|
||||||
game.Turn += 1;
|
game.Turn += 1;
|
||||||
game.Players.forEach((player, idx) => {
|
game.Players.forEach((player, idx) => {
|
||||||
if (player.ID == id) {
|
if (player.ID == id) {
|
||||||
// todo it's supposed to be a string, should render client-side
|
|
||||||
player.Balance -= bump;
|
player.Balance -= bump;
|
||||||
if (player.Balance < 0)
|
if (player.Balance < 0)
|
||||||
throw new Error("cannot bet more than you have");
|
throw new Error("cannot bet more than you have");
|
||||||
game.Pot += bump;
|
game.Pot += bump;
|
||||||
|
} else {
|
||||||
|
player.Checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,14 +11,20 @@ type Game struct {
|
|||||||
type Player struct {
|
type Player struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Card int
|
Card Card
|
||||||
Balance Currency
|
Balance Currency
|
||||||
Active bool
|
Active bool
|
||||||
Participating bool
|
Participating bool
|
||||||
|
Checked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Currency int
|
type Currency int
|
||||||
|
|
||||||
|
type Card struct {
|
||||||
|
Suit int
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
func (game Game) GetPlayers() []Player {
|
func (game Game) GetPlayers() []Player {
|
||||||
players := []Player{}
|
players := []Player{}
|
||||||
for _, player := range game.Players {
|
for _, player := range game.Players {
|
||||||
|
|||||||
Reference in New Issue
Block a user