remove json decoration
parent
3a47b0a76a
commit
f59e98981b
|
|
@ -6,9 +6,17 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Poor Man's Blind Man's Poker</h1>
|
<h1>Poor Man's Blind Man's Poker</h1>
|
||||||
<button onclick="start(); return false;">Start</button>
|
<form id="control-games" onsubmit="return false;">
|
||||||
<button onclick="join(); return false;">Join</button>
|
<button onclick="start(); return false;">Start</button>
|
||||||
<button onclick="drop(); return false;">Drop</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>
|
<div id="game"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
forUser(id, uid, cb) {
|
||||||
this.get(id, (game) => {
|
this.get(id, (game) => {
|
||||||
game.Players.forEach((player, idx) => {
|
game.Players.forEach((player, idx) => {
|
||||||
|
|
@ -98,6 +105,7 @@ class Games {
|
||||||
}
|
}
|
||||||
|
|
||||||
update(id, game, cb) {
|
update(id, game, cb) {
|
||||||
|
// TODO compute turn
|
||||||
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);
|
throw new Error("bad status updating game: "+status+": "+text);
|
||||||
|
|
@ -145,15 +153,16 @@ class UI {
|
||||||
`;
|
`;
|
||||||
if (this.me(player)) {
|
if (this.me(player)) {
|
||||||
var myturn = seatnum == game.Turn
|
var myturn = seatnum == game.Turn
|
||||||
var disabled = (!player.Active || !myturn) ? "disabled" : "";
|
var enabled = player.Active && myturn;
|
||||||
state += `
|
var eleControlGame = this.eleControlGame();
|
||||||
<form>
|
var enabledWas = eleControlGame.getAttribute("disabled") == null;
|
||||||
<button ${disabled} onclick="fold(this); return false;">Fold</button>
|
if (enabled != enabledWas) {
|
||||||
<button ${disabled} onclick="check(this); return false;">Check</button>
|
if (enabled) {
|
||||||
<input ${disabled} type="text"/>
|
eleControlGame.removeAttribute("disabled");
|
||||||
<button ${disabled} onclick="raise(this); return false;">Raise</button>
|
} else {
|
||||||
</form>
|
eleControlGame.setAttribute("disabled", true);
|
||||||
`;
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state += `</player>`;
|
state += `</player>`;
|
||||||
}
|
}
|
||||||
|
|
@ -170,6 +179,14 @@ class UI {
|
||||||
this.ele().innerHTML = "";
|
this.ele().innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eleControlGame() {
|
||||||
|
return document.getElementById("control-game");
|
||||||
|
}
|
||||||
|
|
||||||
|
eleControlGames() {
|
||||||
|
return document.getElementById("control-games");
|
||||||
|
}
|
||||||
|
|
||||||
ele() {
|
ele() {
|
||||||
return document.getElementById("game");
|
return document.getElementById("game");
|
||||||
}
|
}
|
||||||
|
|
@ -273,6 +290,8 @@ 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) => {
|
games.forUser("id", id, (player) => {
|
||||||
|
if (player.Participating)
|
||||||
|
throw new Error("redundant join");
|
||||||
player.Participating = true;
|
player.Participating = true;
|
||||||
player.Active = false;
|
player.Active = false;
|
||||||
});
|
});
|
||||||
|
|
@ -282,18 +301,47 @@ 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;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fold(ele) {
|
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) {
|
function check(ele) {
|
||||||
|
var db = new DB();
|
||||||
|
var id = db.get("id");
|
||||||
|
games.forGame("id", (game) => {
|
||||||
|
game.Turn += 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function raise(ele) {
|
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();
|
var games = new Games();
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,5 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Players [16]Player
|
type Players [16]Player
|
||||||
|
|
||||||
type Game struct {
|
type Game struct {
|
||||||
|
|
@ -40,41 +32,3 @@ func (game Game) GetPlayers() []Player {
|
||||||
func (p Player) Empty() bool {
|
func (p Player) Empty() bool {
|
||||||
return p == (Player{})
|
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,101 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
"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) {
|
func TestPlayerEmpty(t *testing.T) {
|
||||||
var p Player
|
var p Player
|
||||||
if !p.Empty() {
|
if !p.Empty() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue