class DB {
constructor() {
if (typeof(localStorage) === "undefined") {
throw new Error('Hmmm... no "localStorage" support');
}
}
get(key) {
var b = localStorage.getItem(key);
if (b) {
b = JSON.parse(b);
} else {
b = null;
}
return b
}
set(key, value) {
var b = JSON.stringify(value);
localStorage.setItem(key, b);
}
del(key) {
localStorage.removeItem(key);
}
}
class Requests {
put(remote, body, callback) {
this.http("put", remote, callback, body);
}
post(remote, body, callback) {
this.http("post", remote, callback, body);
}
get(remote, callback) {
this.http("get", remote, callback, null);
}
http(method, remote, callback, body) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
callback(xmlhttp.responseText, xmlhttp.status);
}
};
xmlhttp.open(method, remote, true);
if (typeof body == "undefined") {
body = null;
}
xmlhttp.send(body);
}
}
class Games {
constructor() {
this.db = new DB();
this.requests = new Requests();
}
list(cb) {
this.requests.get("/api/games", (text) => {
var list = JSON.parse(text);
cb(list);
});
}
forGame(id, cb, log) {
this.get(id, (game) => {
cb(game);
games.update(id, game, (game) => {ui.drawGame(game)}, console.log, log);
});
}
forUser(id, uid, cb, log) {
this.get(id, (game) => {
var found = false;
game.Players.forEach((player, idx) => {
if (player.ID == uid) {
cb(game.Players[idx]);
found = true;
}
});
if (found)
games.update(id, game, (game) => {ui.drawGame(game)}, console.log, log);
});
}
get(id, cb, catcher) {
if (!catcher)
catcher = console.log;
this.requests.get("/api/games/"+id, (text, status) => {
if (status != 200) {
catcher("bad status getting game:", text, status);
return;
}
var game = JSON.parse(text);
cb(game);
});
}
create(id, cb, catcher) {
if (!catcher)
catcher = console.log;
this.requests.post("/api/games/"+id, null, (text, status) => {
if (status != 200) {
catcher("bad status creating game:", text, status);
return;
}
var game = JSON.parse(text);
cb(game);
});
}
update(id, game, cb, catcher, log) {
var n = 0;
var m = game.Players.length;
game.Players.forEach((player) => n += player.Participating ? 1 : 0);
game.Turn = game.Turn % (m || 1);
game.Log += "
" + log;
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) {
catcher("bad status updating game: ", text, status);
return;
}
var game2 = JSON.parse(text);
cb(game2);
});
}
}
class UI {
constructor(games) {
this.games = games;
this.ts = 0;
this.threshold = 2;
this.refresh();
setInterval(() => { this.refresh() }, 500);
}
now() {
return new Date() / 1000;
}
refresh() {
if (this.now() - this.ts < this.threshold) {
return;
}
this.games.get("id", (game) => {
this.drawGame(game);
});
}
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 11 : value = "jack"; break;
case 12 : value = "queen"; break;
case 13 : value = "king"; break;
case 14 : 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 = `
${this.formatCurrency(game.Pot)}
${game.Log.split("
").slice(-15).join("
")}
`;
var myseat = -1;
game.Players.forEach((player, seatnum) => {
if (player.ID != "") {
state += ``;
state += `
${player.Name}
${this.formatCurrency(player.Balance)}
${this.formatCard(!complete && (this.me(player) || !player.Participating || !player.Active) ? -1 : player.Card)}
`;
if (this.me(player)) {
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;
}
me(player) {
return new DB().get("id") == player.ID
}
clear() {
this.ele().innerHTML = "";
}
eleControlGame() {
return document.getElementById("control-game");
}
eleControlGames() {
return document.getElementById("control-games");
}
ele() {
return document.getElementById("game");
}
}
function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
class Deck {
constructor() {
this.cards = new Array(52);
}
draw() {
while (true) {
var idx = Math.floor(Math.random() * 52);
if (!this.cards[idx]) {
this.cards[idx] = 1;
return {Suit: idx%4, Value: idx%13};
}
}
}
}
function init() {
var db = new DB();
if (!db.get("id")) {
db.set("id", uuid());
}
if (!db.get("name")) {
var name = prompt("who are you?");
db.set("name", name);
}
var id = db.get("id");
var name = db.get("name");
games.create("id", () => {
games.update("id", {
Pot: 0,
Players: [
{ID: id, Name: name},
],
}, (game) => ui.drawGame(game));
resetGame();
});
}
function start() {
var db = new DB();
var deck = new Deck()
var id = db.get("id");
var name = db.get("name");
games.get("id", (game) => {
var myturn = 0;
var n = 0;
game.Players.forEach((player, idx) => {
myturn = player.ID == id ? idx : myturn;
if (player.Participating) {
n += 1;
game.Players[idx].Active = true;
game.Players[idx].Checked = false;
game.Players[idx].Card = deck.draw();
}
});
if (n == 0) {
throw new Error("will not start game with no participants");
}
game.Pot = 0;
game.Log = "start!";
game.Turn = myturn;
while (!game.Players[game.Turn].Participating) {
game.Turn = (game.Turn+1) % game.Players.length;
}
games.update("id", game, (game) => {ui.drawGame(game)}, console.log, `${name} started the game`);
});
}
function join() {
var db = new DB();
var id = db.get("id");
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 == id) {
game.Players[i].Name = name
game.Players[i].Participating = true
set = true
}
}
if (!set) {
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");
}
}, `${name} joined the game`);
}
function drop() {
var db = new DB();
var id = db.get("id");
var name = db.get("name");
games.forUser("id", id, (player) => {
player.Participating = false;
player.Active = false;
}, `${name} dropped`);
}
function fold(ele) {
var db = new DB();
var id = db.get("id");
var name = db.get("name");
games.forUser("id", id, (player) => {
player.Active = false;
}, `${name} folded`);
}
function check(ele) {
var db = new DB();
var id = db.get("id");
games.forGame("id", (game) => {
game.Turn += 1;
game.Players.forEach((player) => {
if (player.ID == id)
player.Checked = true;
});
}, `${name} checked`);
}
function collect(ele) {
var db = new DB();
var id = db.get("id");
var name = db.get("name");
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;
}, `${name} collected the pot`);
}
function resetGame() {
console.log("resetting game");
var db = new DB();
var name = db.get("name");
games.forGame("id", (game) => {
game.Players = [];
game.Turn = 0;
game.Pot = 0;
game.Log = "reset";
}, `${name} reset the game`);
}
function setWallet(ele) {
var db = new DB();
var id = db.get("id");
var balance = parseInt(ele.parentNode.getElementsByTagName("input")[0].value);
var name = db.get("name");
games.forUser("id", id, (player) => {
player.Balance = balance;
}, `${name} set their wallet to ${balance}`);
}
function raise(ele) {
var db = new DB();
var id = db.get("id");
var bump = parseInt(ele.parentNode.getElementsByTagName("input")[0].value);
var name = db.get("name");
games.forGame("id", (game) => {
game.Turn += 1;
game.Players.forEach((player, idx) => {
if (player.ID == id) {
player.Balance -= bump;
if (player.Balance < 0)
throw new Error("cannot bet more than you have");
game.Pot += bump;
} else {
player.Checked = false;
}
});
}, `${name} raises by ${bump}`);
}
var games = new Games();
var ui = new UI(games);
init()