diff --git a/src/client/index.html b/src/client/index.html index fed2437..3355321 100644 --- a/src/client/index.html +++ b/src/client/index.html @@ -6,9 +6,17 @@

Poor Man's Blind Man's Poker

- - - +
+ + + +
+
+ + + + +
diff --git a/src/client/js.js b/src/client/js.js index a993044..e533a64 100644 --- a/src/client/js.js +++ b/src/client/js.js @@ -66,6 +66,13 @@ class Games { }); } + forGame(id, cb) { + this.get(id, (game) => { + cb(game); + games.update(id, game, (game) => {ui.drawGame(game)}); + }); + } + forUser(id, uid, cb) { this.get(id, (game) => { game.Players.forEach((player, idx) => { @@ -98,6 +105,7 @@ class Games { } update(id, game, cb) { + // TODO compute turn this.requests.put("/api/games/"+id, JSON.stringify(game), (text, status) => { if (status != 200) { throw new Error("bad status updating game: "+status+": "+text); @@ -145,15 +153,16 @@ class UI { `; if (this.me(player)) { var myturn = seatnum == game.Turn - var disabled = (!player.Active || !myturn) ? "disabled" : ""; - state += ` -
- - - - -
- `; + 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 += ``; } @@ -170,6 +179,14 @@ class UI { this.ele().innerHTML = ""; } + eleControlGame() { + return document.getElementById("control-game"); + } + + eleControlGames() { + return document.getElementById("control-games"); + } + ele() { return document.getElementById("game"); } @@ -273,6 +290,8 @@ 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; }); @@ -282,18 +301,47 @@ 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; }); } 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; + }); } function check(ele) { + var db = new DB(); + var id = db.get("id"); + games.forGame("id", (game) => { + game.Turn += 1; + }); } function raise(ele) { + var db = new DB(); + var id = db.get("id"); + var bump = 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; + } + }); + }); } var games = new Games(); diff --git a/src/server/game.go b/src/server/game.go index c0fb8c6..0f4fc96 100644 --- a/src/server/game.go +++ b/src/server/game.go @@ -1,13 +1,5 @@ package main -import ( - "encoding/json" - "fmt" - "regexp" - "strconv" - "strings" -) - type Players [16]Player type Game struct { @@ -40,41 +32,3 @@ func (game Game) GetPlayers() []Player { func (p Player) Empty() bool { return p == (Player{}) } - -func (c Currency) MarshalJSON() ([]byte, error) { - return json.Marshal(fmt.Sprintf(`$%v.%02d`, c/100, c%100)) -} - -func (c *Currency) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - re := regexp.MustCompile(`^\$([0-9]+(\.[0-9][0-9])?|\.[0-9]{2})$`) - if !re.MatchString(s) { - return fmt.Errorf("illegal currency format: %q", s) - } - s = strings.TrimPrefix(s, "$") - dollars := strings.Split(s, ".")[0] - cents := strings.TrimPrefix(s, dollars+".") - if !strings.HasPrefix(s, dollars+".") { - cents = "0" - } - if dollars == "" { - dollars = "0" - } - if cents == "00" { - cents = "0" - } - dI, err := strconv.Atoi(dollars) - if err != nil { - return err - } - cI, err := strconv.Atoi(cents) - if err != nil { - return err - } - c2 := Currency(dI*100 + cI) - *c = c2 - return nil -} diff --git a/src/server/game_test.go b/src/server/game_test.go index bf12463..3f7a473 100644 --- a/src/server/game_test.go +++ b/src/server/game_test.go @@ -1,101 +1,9 @@ package main import ( - "encoding/json" "testing" ) -func TestCurrencyMarshal(t *testing.T) { - cases := map[string]struct { - input Currency - want string - }{ - "zero": { - want: "$0.00", - }, - "one cent": { - input: 1, - want: "$0.01", - }, - "one dollar and one cent": { - input: 101, - want: "$1.01", - }, - "one dollar and no cent": { - input: 100, - want: "$1.00", - }, - } - - for name, d := range cases { - c := d - t.Run(name, func(t *testing.T) { - b, err := json.Marshal(c.input) - if err != nil { - t.Fatal(err) - } - b = b[1 : len(b)-1] - if s := string(b); s != c.want { - t.Fatalf("given %v, want %q, got %q", c.input, c.want, s) - } - }) - } -} - -func TestCurrencyUnmarshal(t *testing.T) { - cases := map[string]struct { - input string - want Currency - }{ - "no dollar and no cent": { - input: "$0.00", - want: 0, - }, - "omitted no dollar and no cent": { - input: "$.00", - want: 0, - }, - "no dollar and omitted no cent": { - input: "$0", - want: 0, - }, - "no dollar and one cent": { - input: "$0.01", - want: 1, - }, - "omitted no dollar and one cent": { - input: "$.01", - want: 1, - }, - "one dollar and one cent": { - input: "$1.01", - want: 101, - }, - "one dollar and no cent": { - input: "$1.00", - want: 100, - }, - "one dollar and omitted no cent": { - input: "$1", - want: 100, - }, - } - - for name, d := range cases { - c := d - t.Run(name, func(t *testing.T) { - var got Currency - err := json.Unmarshal([]byte(`"`+c.input+`"`), &got) - if err != nil { - t.Fatal(err) - } - if got != c.want { - t.Fatalf("given %s, want %v, got %v", c.input, c.want, got) - } - }) - } -} - func TestPlayerEmpty(t *testing.T) { var p Player if !p.Empty() {