remove json decoration

master
Bel LaPointe 2021-03-12 09:14:15 -06:00
parent 3a47b0a76a
commit f59e98981b
4 changed files with 68 additions and 150 deletions

View File

@ -6,9 +6,17 @@
</head>
<body>
<h1>Poor Man's Blind Man's Poker</h1>
<form id="control-games" onsubmit="return false;">
<button onclick="start(); return false;">Start</button>
<button onclick="join(); return false;">Join</button>
<button onclick="drop(); return false;">Drop</button>
</form>
<form id="control-game" onsubmit="return false;">
<button onclick="fold(this); return false;">Fold</button>
<button onclick="check(this); return false;">Check</button>
<input min=0 type="number"/>
<button onclick="raise(this); return false;">Raise cents</button>
</form>
<div id="game"></div>
</body>
</html>

View File

@ -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 += `
<form>
<button ${disabled} onclick="fold(this); return false;">Fold</button>
<button ${disabled} onclick="check(this); return false;">Check</button>
<input ${disabled} type="text"/>
<button ${disabled} onclick="raise(this); return false;">Raise</button>
</form>
`;
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>`;
}
@ -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();

View File

@ -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
}

View File

@ -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() {