123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314 |
- <!DOCTYPE html>
- <html>
- <head>
- <title>Backgammon</title>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <script src="../js/snap.svg-min.js"></script>
- <style>
- /*
- .board-container {
- display: inline-block;
- position: relative;
- width: 80%;
- padding-bottom: 47%;
- vertical-align: middle;
- overflow: hidden;
- }
- */
- body {
- margin: 0px;
- box-sizing: border-box;
- max-height: 100vh;
- }
- .game-ui {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- box-sizing: border-box;
- max-height: 100vh;
- flex-basis: auto;
- padding: 20px;
- }
- .toolbar {
- display: flex;
- flex-direction: row;
- flex-grow: 2;
- justify-content: space-between;
- align-items: baseline;
- }
- .toolbar-button {
- flex: 1 1 100px;
- margin: 2px;
- height: 40px;
- width: 50px;
- }
- .player-info {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- }
- .match-info {
- display: flex;
- box-sizing: border-box;
- flex-direction: row;
- justify-content: space-between;
- margin-right: 50px;
- }
- .svg-board {
- flex: 1 2 auto;
- padding: 5px;
- }
- .hint {
- height: 1em;
- }
- </style>
-
- </head>
- <body>
- <div class="game-ui">
- <div id="toolbar" class="toolbar" style="padding-bottom: 10px;">
- <!-- <svg id="player" width=20 height=20> </svg> -->
- <span id="player"></span>
- <button id="double" type="button" class="toolbar-button" onclick="graphicToolbar.onDouble()" disabled="true">Double</button>
- <button id="accept" type="button" class="toolbar-button" onclick="graphicToolbar.onAccept()" disabled="true">Accept</button>
- <button id="refuse" type="button" class="toolbar-button" onclick="graphicToolbar.onRefuse()" disabled="true">Refuse</button>
- <button id="undo" type="button" class="toolbar-button" onclick="graphicToolbar.onUndo()" disabled="false">Undo</button>
- <button id="direction" type="button" class="toolbar-button" onclick="graphicToolbar.onChangeDirection()">Direction</button>
- </div>
- <svg id="board" viewBox="0 0 520 300" class="svg-board"></svg>
- <p id="hint" class="hint"></p>
- <div class="match-info">
- <div class="player-info">
- <div class="player-name">White <span id="white-name"></span></div>
- <div class="score">Score: <span id="white-score"></span> <span id="white-away"></span></div>
- <div class="pips">Pips: <span id="white-pips"></span> (<span id="white-diff"></span>)</div>
- </div>
- <div class="player-info">
- <div class="player-name">Black <span id="black-name"></span></div>
- <div class="score">Score: <span id="black-score"></span> <span id="black-away"></span></div>
- <div class="pips">Pips: <span id="black-pips"></span> (<span id="black-diff"></span>)</div>
- </div>
- <div class "match-options">
- <div class="match-limit">
- Match: <span id="match-limit"></span>
- </div>
- <div class="match-misc">
- <span id="match-misc"></span>
- </div>
- </div>
- </div>
- </div>
- <div id="status" hidden="true"></div>
- <script>
- "use strict";
- function Board(game, ui, boardPic) {
- this.pic = boardPic;
- this.game = game;
- this.ui = ui;
- var self = this;
- this.clockwise = true;
- this.orientation = "white";
- this.onChangeDirection = function() {
- self.clockwise = !self.clockwise;
- self.refresh();
- }
- this.onPointClick = function(p) {
- var a = physicalToAbsolute(p, self.clockwise, self.orientation);
- if (ui.checkersEnabled) {
- let canMove = game.canMoveFrom(a);
- if (canMove === "swap") game.swapDice();
- if (canMove) ui.putEvent(moveFromEvent(a, game));
- }
- };
- this.onBarClick = function() {
- if (ui.checkersEnabled) {
- if (ui.checkersEnabled) {
- let canMove = game.canMoveFrom("bar");
- if (canMove === "swap") game.swapDice();
- if (canMove) ui.putEvent(moveFromBarEvent(game));
- }
- }
- };
- this.onRightPaneClick = function() {
- if (ui.moveCompletionEnabled) {
- ui.putEvent(finishMoveEvent());
- } else if (ui.offerDoubleEnabled) {
- ui.putEvent(offerDoubleEvent("no"));
- } else if (game.canSwapDice()) {
- game.swapDice();
- self.refresh();
- }
- }
- this.onTrayClick = function(ID) {
- if (ui.doublingEnabled && ID === self.cubeTrayID[PLAYER]()) {
- ui.putEvent(offerDoubleEvent("yes"));
- }
- }
- this.plug = function() {
- var foo = function() {};
- this.pic.onPointClick = this.onPointClick; // phys_i
- this.pic.onBarClick = this.onBarClick; // ()
- this.pic.onRightPaneClick = this.onRightPaneClick; // ()
- this.pic.onTrayClick = this.onTrayClick; // phys_i
- this.setCheckersBar = this.pic.setCheckersBar || foo; // k_white, k_black
- this.setCheckersPoint = this.pic.setCheckersPoint || foo; // phys_i, n, player
- this.setCheckersTray = this.pic.setCheckersTray || foo; // phys_i, n, player
- this.setCubeLeft = this.pic.setCubeLeft || foo; // val
- this.setCubeRight = this.pic.setCubeRight || foo; // val
- this.setCubeLeftPane = this.pic.setCubeLeftPane || foo; // val
- this.setCubeRightPane = this.pic.setCubeRightPane || foo; // val
- this.setCubeTray = this.pic.setCubeTray || foo; // phys_i, val
- this.hideCube = this.pic.hideCube || foo; // ()
- this.setDiceLeft = this.pic.setDiceLeft || foo; // d1, opacity1, d2, opacity2; opacity: "max", "half", "min"
- this.setDiceRight = this.pic.setDiceRight || foo;
- this.hideDice = this.pic.hideDice || foo; // ()
- }
- this.refresh = function() {
- // refresh checkers on the points
- for (let i = 0; i < 24; ++i) {
- let a = physicalToAbsolute(i, this.clockwise, this.orientation);
- this.setCheckersPoint(i, game.board.points[a].checkers, game.board.points[a].player);
- }
- // refresh checkers on the bar
- this.setCheckersBar(game.board.bar.white, game.board.bar.black);
- this.hideDice();
- this.hideCube();
- // refresh the trays
- var offWhite = this.bearoffTrayID.white();
- var offBlack = this.bearoffTrayID.black();
- var cubeLocation = this.cubeLocation();
- for (let i = 0; i < 4; ++i) {
- if (i === offWhite) {
- this.setCheckersTray(i, game.board.off.white, "white");
- } else if (i === offBlack) {
- this.setCheckersTray(i, game.board.off.black, "black");
- } else if (i === cubeLocation) {
- this.setCubeTray(i, game.cube);
- } else {
- this.setCheckersTray(i, 0, null);
- }
- }
- // Dice go before cube so that we could hide them without hiding the cube
- // It turns out this.hideDice() removes the cube as well.
- // Is this a bug or not?
- if (!game.dice) this.hideDice()
- else if (!game.turn) {
- if (this.orientation === "white") {
- this.setDiceRight(game.dice[0], "max");
- this.setDiceLeft(game.dice[1], "max");
- } else {
- this.setDiceRight(game.dice[1], "max");
- this.setDiceLeft(game.dice[0], "max");
- }
- } else {
- let op0 = "max", op1 = "max";
- if (game.turn === PLAYER) {
- if (game.dice[0] != game.dice[1]) {
- if (!game.restDice.includes(game.dice[0])) op0 = "min";
- if (!game.restDice.includes(game.dice[1])) op1 = "min";
- } else {
- let len = game.restDice.length;
- if (len === 3) op0 = "half"
- else if (len === 2) op0 = "min"
- else if (len === 1) {
- op0 = "min";
- op1 = "half";
- } else if (len === 0) op0 = op1 = "min";
- }
- }
- if (game.turn === this.orientation) this.setDiceRight(game.dice[0], op0, game.dice[1], op1)
- else this.setDiceLeft(game.dice[0], op0, game.dice[1], op1);
- }
- if (cubeLocation === "left") this.setCubeLeft(game.cube)
- else if (cubeLocation === "right") this.setCubeRight(game.cube)
- else if (cubeLocation === "leftPane") this.setCubeLeftPane(2*game.cube)
- else if (cubeLocation === "rightPane") this.setCubeRightPane(2*game.cube)
- else if (cubeLocation === null) this.hideCube();
- }
- this.bearoffTrayID = {
- white: function() {
- return (self.orientation === "white") ? (self.clockwise ? 3 : 2) : (self.clockwise ? 0 : 1);
- },
- black: function() {
- return (self.orientation === "black") ? (self.clockwise ? 3 : 2) : (self.clockwise ? 0 : 1);
- }
- }
- // Returns the storage number, "left", "right", or null.
- this.cubeLocation = function() {
- if (!game.cube) return null
- else if (game.isDoubling === PLAYER) return "leftPane"
- else if (game.isDoubling) return "rightPane"
- else if (!game.cubeOwner) {
- if (this.clockwise) return "right"
- else return "left";
- } else if (game.cubeOwner === this.orientation) {
- if (this.clockwise) return 2
- else return 3;
- } else {
- if (this.clockwise) return 1
- else return 0;
- }
- }
- this.cubeTrayID = {
- white: function() {
- return (self.orientation === "white") ? (self.clockwise ? 2 : 3) : (self.clockwise ? 1 : 0);
- },
- black: function() {
- return (self.orientation === "black") ? (self.clockwise ? 2 : 3) : (self.clockwise ? 1 : 0);
- }
- }
- }
- function normalizeCube(value) {
- return (value === 1) ? 64 : value;
- }
- function die(pic, x, y, a, r, alpha, value, faceColour, pipColour) {
- var g = pic.g();
- var face = pic.rect(x - 0.5*a, y - 0.5*a, a, a, 5).attr({
- fill: faceColour
- }).appendTo(g);
- var pip = pic.circle(x, y, r).attr({
- fill: pipColour
- }).appendTo(g);
- var shift = alpha*a* 0.5;
- if (value === 1) {
- } else if (value === 2) {
- pip.clone().transform(Snap.matrix().translate(shift, shift));
- pip.transform(Snap.matrix().translate(-shift, -shift));
- } else if (value === 3) {
- pip.clone().transform(Snap.matrix().translate(shift, shift));
- pip.clone().transform(Snap.matrix().translate(-shift, -shift));
- } else if (value === 4) {
- pip.clone().transform(Snap.matrix().translate(shift, shift));
- pip.clone().transform(Snap.matrix().translate(-shift, -shift));
- pip.clone().transform(Snap.matrix().translate(-shift, shift));
- pip.transform(Snap.matrix().translate(shift, -shift));
- } else if (value === 5) {
- pip.clone().transform(Snap.matrix().translate(shift, shift));
- pip.clone().transform(Snap.matrix().translate(-shift, -shift));
- pip.clone().transform(Snap.matrix().translate(-shift, shift));
- pip.clone().transform(Snap.matrix().translate(shift, -shift));
- } else if (value === 6) {
- pip.clone().transform(Snap.matrix().translate(shift, shift));
- pip.clone().transform(Snap.matrix().translate(-shift, -shift));
- pip.clone().transform(Snap.matrix().translate(-shift, shift));
- pip.clone().transform(Snap.matrix().translate(shift, -shift));
- pip.clone().transform(Snap.matrix().translate(shift, 0));
- pip.transform(Snap.matrix().translate(-shift, 0));
- }
- return g;
- };
- function cube(pic, x, y, a, value, bgColour, fgColour, orientation) {
- a = a * 0.9;
- var g = pic.g();
- pic.rect(x - 0.5*a, y - 0.5*a, a, a, 5).attr({
- fill: bgColour
- }).appendTo(g);
- var label = pic.text(x, y, value).attr({
- textAnchor: "middle",
- alignmentBaseline: "central",
- fill: "beige"
- });
- var t = Snap.matrix();
- if (orientation === "W") t.rotate(-90, x, y)
- else if (orientation === "S") t.rotate(180, x, y)
- else if (orientation === "E") t.rotate(90, x, y)
- label.transform(t).appendTo(g);
- return g;
- };
- function moveFromEvent(p, game) {
- return moveEvent(p + 1, game.restDice[0]);
- }
- function moveFromBarEvent(game) {
- return moveEvent("bar", game.restDice[0]);
- }
- function finishMoveEvent() {
- return ["f"];
- }
- function undoEvent() {
- return ["u"];
- }
- function offerDoubleEvent(yesNo) {
- return ["offer-double", yesNo];
- }
- function acceptDoubleEvent(yesNo) {
- return ["accept-double", yesNo];
- }
- function SVGPoint(board, ID, checkerCount, player) {
- var self = this;
- var g = board.paper.g();
- g.rect(pointX(board, ID) - 1/2*board.params.pointWidth,
- (ID < 12) ? 0 : board.params.height - board.params.pointHeight,
- 0.99*board.params.pointWidth, board.params.pointHeight)
- .attr({
- fillOpacity: 0
- })
- pointPic(board, ID).appendTo(g);
- var checkersToDraw = Math.min(checkerCount, maxCirclesOnPoint);
- var label = (checkerCount > maxCirclesOnPoint) ? checkerCount : null;
- var direction = pointDirection(ID);
- var baseX = pointX(board, ID);
- var baseY = pointBaseY(board, ID);
- for (let i = 0; i < checkersToDraw; ++i) {
- checkerPic(board, player, baseX,
- baseY + direction * (2*i+1) * board.params.checkerRadius).appendTo(g);
- }
- if (checkersToDraw > 0 && label) {
- textLabel(board, baseX, baseY + direction * (2 * checkersToDraw - 1) * board.params.checkerRadius, label).appendTo(g);
- }
- g.click(function () { board.onPointClick(ID) });
- return g;
- }
- function checkerPic(board, player, x, y) {
- return board.paper.circle(x, y, board.params.checkerRadius).attr({
- fill: board.params.checkerColour[player]
- });
- }
- function textLabel(board, x, y, text) {
- return board.paper.text(x, y, text).attr({
- textAnchor: "middle",
- alignmentBaseline: "central"
- });
- };
- function SVGBar(board, white, black) {
- var g = board.paper.g();
- // background
- board.paper.rect(7 * board.params.pointWidth + 2 * board.params.borderWidth, 0, board.params.barWidth, board.params.height)
- .attr({
- fill: board.params.borderColour
- }).appendTo(g);
- // TODO text labels
- var setCheckers = function(k, player) {
- var x = 7 * board.params.pointWidth + 2 * board.params.borderWidth + 0.5 * board.params.barWidth;
- var topY = (player == board.orientation) ? 0.33 * board.params.height : 0.67 * board.params.height;
- var dir = (player == board.orientation) ? -1 : 1;
- for (let i = 0; i < k; ++i) {
- checkerPic(board, player, x,
- topY + dir * (2*i+1) * board.params.checkerRadius).appendTo(g);
- }
- };
- setCheckers(white, "white");
- setCheckers(black, "black");
- g.click(board.onBarClick);
- return g;
- }
- function Pane(board, which, d0, op0, d1, op1) {
- var g = board.paper.g();
- if (which === "right") g.click(board.onRightPaneClick);
- var x0 = (which === "left") ? board.params.pointWidth + 2 * board.params.borderWidth : 7 * board.params.pointWidth + 2 * board.params.borderWidth + board.params.barWidth;
- var y0 = board.params.borderWidth + board.params.pointHeight;
- // background
- board.paper.rect(x0, y0,
- 6 * board.params.pointWidth, board.params.height - 2*board.params.pointHeight)
- .attr({
- fillOpacity: 0
- }).appendTo(g);
- // two dice
- if (d0 && d1) {
- let a = 30;
- let r = 3;
- let alpha = 0.6;
- let faceColour = "red";
- let pipColour = "white";
- let x1 = x0 + 3 * board.params.pointWidth;
- let y1 = 0.5 * board.params.height;
- let delta = 0.75*a;
- let pic0 = die(board.paper, x1 - delta, y1, a, r, alpha, d0, faceColour, pipColour);
- let pic1 = die(board.paper, x1 + delta, y1, a, r, alpha, d1, faceColour, pipColour);
- if (op0 === "min") {
- pic0.attr({
- fillOpacity: 0.33
- });
- } else if (op0 === "half") {
- pic0.attr({
- fillOpacity: 0.67
- });
- }
- if (op1 === "min") {
- pic1.attr({
- fillOpacity: 0.33
- });
- } else if (op1 === "half") {
- pic1.attr({
- fillOpacity: 0.67
- });
- }
- pic0.appendTo(g);
- pic1.appendTo(g);
- }
- // one die
- // I've copied & pasted the above. :blush: I promise to refactor it some day.
- if (d0 && !d1) {
- let a = 30;
- let r = 3;
- let alpha = 0.6;
- let faceColour = "red";
- let pipColour = "white";
- let x1 = x0 + 3 * board.params.pointWidth;
- let y1 = 0.5 * board.params.height;
- let pic = die(board.paper, x1, y1, a, r, alpha, d0, faceColour, pipColour);
- pic.appendTo(g);
- }
- return g;
- }
- function Tray(board, ID, checkerCount, player) {
- var g = board.paper.g();
- g.click(function() {board.onTrayClick(ID);});
- var x = (ID === 0 || ID === 3) ? board.params.borderWidth : 13*board.params.pointWidth + board.params.barWidth + 3 * board.params.borderWidth;
- var y = (ID === 0 || ID === 1) ? board.params.borderWidth : board.params.height - board.params.borderWidth - board.params.pointHeight;
- // background
- g.rect(x, y, board.params.pointWidth, board.params.pointHeight)
- .attr({
- fill: board.params.backgroundColour
- });
- // checkers
- var checkersToDraw = Math.min(checkerCount, maxCirclesOnPoint);
- var label = (checkerCount > maxCirclesOnPoint) ? checkerCount : null;
- var direction = (ID < 2) ? 1 : -1;
- var baseX = x + 0.5 * board.params.pointWidth;
- var baseY = (ID === 0 || ID === 1) ? board.params.borderWidth : board.params.height - board.params.borderWidth;
- for (let i = 0; i < checkersToDraw; ++i) {
- checkerPic(board, player, baseX,
- baseY + direction * (2*i+1) * board.params.checkerRadius).appendTo(g);
- }
- if (checkersToDraw > 0 && label) {
- textLabel(board, baseX, baseY + direction * (2 * checkersToDraw - 1) * board.params.checkerRadius, label).appendTo(g);
- }
- return g;
- }
- function SVGBoard(paper) {
- this.params = {
- width: 520,
- height: 300,
- pointWidth: 30,
- pointHeight: 120,
- barWidth: 60,
- blackCheckerColour: "#753421",
- checkerColour: {
- black: "#753421",
- white: "plum"
- },
- checkerRadius: 10,
- maxCheckersOnPoint: 6,
- evenColour: "#669900",
- oddColour: "#6699ff",
- borderColour: "#ffcc00",
- borderWidth: 10,
- backgroundColour: "beige"
- };
- var self = this;
- this.paper = paper;
- this.onBarClick = function() {};
- this.onPointClick = function() {};
- this.onTrayClick = function() {};
- this.onRightPaneClick = function() {};
- // draw the board
- // TODO check that we don't draw the same things twice
- paper.rect(0, 0, 4 * this.params.borderWidth + 14 * this.params.pointWidth + this.params.barWidth,
- this.params.height).attr({
- fill: this.params.backgroundColour
- });
- paper.rect(0, 0, 2 * this.params.borderWidth + this.params.pointWidth,
- this.params.height).attr({
- fill: this.params.borderColour
- });
- paper.rect(13 * this.params.pointWidth + 2 * this.params.borderWidth + this.params.barWidth, 0, 2 * this.params.borderWidth + this.params.pointWidth,
- this.params.height).attr({
- fill: this.params.borderColour
- });
- paper.rect(0, 0, 14 * this.params.pointWidth + this.params.barWidth + 4 * this.params.borderWidth, this.params.borderWidth).attr({
- fill: this.params.borderColour
- });
- paper.rect(0, this.params.height - this.params.borderWidth, 14 * this.params.pointWidth + this.params.barWidth + 4 * this.params.borderWidth, this.params.borderWidth).attr({
- fill: this.params.borderColour
- });
- this.point = function(x, y, direction, colour) {
- var triangle = paper.polyline([x, y, x + this.params.pointWidth, y, x + 0.5 * this.params.pointWidth, y + direction * this.params.pointHeight, x, y]);
- triangle.attr({
- fill: colour
- });
- return triangle;
- }
- // draw the points, etc.
- var bar = SVGBar(this, 0, 0);
- var trays = [];
- for (let i = 0; i < 4; ++i) trays.push(Tray(this, i, 0, null));
- var cubePic = null;
- var points = [];
- for (let i = 0; i < 24; ++i) points.push(SVGPoint(this, i, 0, null));
- var leftPane = null;
- var rightPane = null;
- this.setCubeLeft = function(c) {
- var x = self.params.borderWidth + 0.5 * self.params.pointWidth;
- var y = 0.5 * self.params.height;
- if (cubePic) cubePic.remove();
- cubePic = cube(paper, x, y, self.params.pointWidth,
- normalizeCube(c), "brown", "beige", "W");
- }
- this.setCubeRight = function(c) {
- var x = 3 * self.params.borderWidth + 13.5 * self.params.pointWidth + self.params.barWidth;
- var y = 1/2 * self.params.height;
- if (cubePic) cubePic.remove();
- cubePic = cube(paper, x, y, self.params.pointWidth,
- normalizeCube(c), "brown", "beige", "W");
- }
- this.setCubeRightPane = function(value) {
- var x = 2 * self.params.borderWidth + 7 * self.params.pointWidth + self.params.barWidth + 3 * self.params.pointWidth;
- var y = 0.5 * self.params.height;
- if (rightPane) rightPane.remove();
- rightPane = Pane(self, "right");
- if (cubePic) cubePic.remove();
- cubePic = cube(paper, x, y, self.params.pointWidth,
- normalizeCube(value), "brown", "beige", "N");
- cubePic.appendTo(rightPane);
- }
- this.setCubeLeftPane = function(value) {
- var x = 2 * self.params.borderWidth + 4 * self.params.pointWidth;
- var y = 0.5 * self.params.height;
- if (leftPane) leftPane.remove();
- leftPane = Pane(self, "left");
- if (cubePic) cubePic.remove();
- cubePic = cube(paper, x, y, self.params.pointWidth,
- normalizeCube(value), "brown", "beige", "N");
- cubePic.appendTo(leftPane);
- }
- this.hideCube = function() {
- if (cubePic) cubePic.remove();
- }
- this.setCubeTray = function(ID, value) {
- var baseX = (ID === 0 || ID === 3) ? self.params.borderWidth + 1/2 * self.params.pointWidth :
- 13.5 * self.params.pointWidth + 3 * self.params.borderWidth + self.params.barWidth;
- var baseY = (ID === 0 || ID === 1) ? self.params.borderWidth :
- self.params.height - self.params.borderWidth;
- var direction = (ID === 0 || ID === 1) ? 1 : -1;
- if (cubePic) cubePic.remove();
- cubePic = cube(paper, baseX, baseY + direction * 0.5 * self.params.pointWidth, self.params.pointWidth,
- normalizeCube(value), "brown", "beige", (ID < 2) ? "S" : "N");
- }
- this.bar = SVGBar(this);
- this.leftPane = Pane(this, "left");
- this.rightPane = Pane(this, "right");
- this.setDiceLeft = function(d0, op0, d1, op1) {
- if (leftPane) leftPane.remove();
- leftPane = Pane(self, "left", d0, op0, d1, op1);
- }
- this.setDiceRight = function(d0, op0, d1, op1) {
- if (rightPane) rightPane.remove();
- rightPane = Pane(self, "right", d0, op0, d1, op1);
- }
- this.hideDice = function() {
- if (leftPane) leftPane.remove();
- leftPane = Pane(self, "left");
- if (rightPane) rightPane.remove();
- rightPane = Pane(self, "right");
- }
- this.setCheckersPoint = function(id, k, player) {
- if (points[id]) points[id].remove();
- points[id] = SVGPoint(self, id, k, player);
- }
- this.setCheckersBar = function(white, black) {
- if (bar) bar.remove();
- bar = SVGBar(self, white, black);
- }
- this.setCheckersTray = function(id, k, player) {
- if (trays[id]) trays[id].remove();
- trays[id] = Tray(self, id, k, player);
- }
- }
- function Game() {
- this.dice = null;
- this.restDice = null;
- this.turn = null;
- this.moves = null;
- this.diceNo = -1;
- this.gameNo = -1;
- this.canMoveFrom = function(p) {
- var restDice = this.restDice;
- var from = (p === "bar") ? "bar" : p + 1;
- if (restDice.length === 0) return false;
- if (this.moves.some(function(move) {
- return (move[0] === restDice[0] && move[1] === from);
- })) {
- return "no-swap";
- }
- if (restDice.length === 1) return "swap";
- if (this.moves.some(function(move) {
- return (move[0] === restDice[1] && move[1] === from);
- })) {
- return "swap";
- }
- return false;
- }
- this.canSwapDice = function() {
- var dice = this.restDice;
- return (game.turn === PLAYER) && (dice.length == 2) && (dice[0] != dice[1]);
- }
- this.swapDice = function() {
- var tmp = this.restDice[0];
- this.restDice[0] = this.restDice[1];
- this.restDice[1] = tmp;
- tmp = this.dice[0];
- this.dice[0] = this.dice[1];
- this.dice[1] = tmp;
- }
- this.pips = function(player) {
- var pips = 0;
- var points = this.board.points;
- for (let i = 0; i < 24; ++i) {
- if (points[i].player === player) {
- pips += points[i].checkers * ((player === "white") ? (i + 1) : (24 - i));
- }
- }
- pips += this.board.bar[player] * 25;
- return pips;
- }
- }
- function UI() {
- this.putEvent = function(evt) {
- sendEvent(evt);
- } ;
- }
- function Toolbar(game, ui, board, graphicToolbar) {
- this.pic = graphicToolbar;
- this.game = game;
- this.ui = ui;
- this.board = board;
- var self = this;
- this.plug = function() {
- var foo = function() {};
- this.pic.onDouble = this.onDouble;
- this.pic.onAccept = this.onAccept;
- this.pic.onRefuse = this.onRefuse;
- this.pic.onUndo = this.onUndo;
- this.pic.onChangeDirection = this.board.onChangeDirection;
- this.enableDouble = this.pic.enableDouble || foo;
- this.enableAccept = this.pic.enableAccept || foo;
- this.enableRefuse = this.pic.enableRefuse || foo;
- this.enableUndo = this.pic.enableUndo || foo;
- }
- // TODO We assume that disabling works properly, but still it would be nice
- // to check ui & make sure we are allowed to do that.
- this.onDouble = function() {
- ui.putEvent(offerDoubleEvent("yes"));
- }
- this.onAccept = function() {
- ui.putEvent(acceptDoubleEvent("yes"));
- }
- this.onRefuse = function() {
- ui.putEvent(acceptDoubleEvent("no"));
- }
- this.onUndo = function() {
- if (ui.undoEnabled) ui.putEvent(undoEvent());
- }
- this.refresh = function() {
- this.enableDouble(ui.offerDoubleEnabled);
- this.enableAccept(ui.acceptDoubleEnabled);
- this.enableRefuse(ui.acceptDoubleEnabled);
- this.enableUndo(ui.undoEnabled);
- }
- }
- function UserInterface(game, ui, graphicBoard, graphicToolbar, matchInfo, graphicHint) {
- this.game = game;
- this.ui = ui;
- this.board = new Board(game, ui, graphicBoard);
- this.toolbar = new Toolbar(game, ui, this.board, graphicToolbar);
- this.matchinfo = new MatchInfo(game, matchInfo);
- this.hint = new Hint(graphicHint);
- this.board.plug();
- this.toolbar.plug();
- this.matchinfo.plug();
- this.hint.plug()
- this.refresh = function() {
- this.board.refresh();
- this.toolbar.refresh();
- this.matchinfo.refresh();
- if (game.matchLimit && game.matchLimit <= game.matchScore[0]) {
- this.hint.setHint("White wins the match.");
- } else if (game.matchLimit && game.matchLimit <= game.matchScore[1]) {
- this.hint.setHint("Black wins the match.");
- } else if (game.winner) {
- this.hint.setHint(game.winner + " wins the game.");
- } else if (!game.turn) {
- this.hint.setHint("Starting the game.");
- } else if (ui.checkersEnabled) {
- this.hint.setHint("Move your checkers and click on the right to complete the move.");
- } else if (ui.offerDoubleEnabled) {
- this.hint.setHint("Double or click on the right to roll the dice.");
- } else if (ui.acceptDoubleEnabled) {
- this.hint.setHint("Accept or refuse the double.");
- } else if (game.turn === PLAYER && game.dice && ! game.moves) {
- this.hint.setHint("NO MOVES");
- } else if (game.turn !== PLAYER) {
- this.hint.setHint("Your opponent’s turn.");
- } else {
- this.hint.setHint(null);
- }
- }
- }
- function GraphicToolbar() {
- var self = this;
- this.doubleButton = document.getElementById("double")
- this.acceptButton = document.getElementById("accept")
- this.refuseButton = document.getElementById("refuse")
- this.undoButton = document.getElementById("undo");
- this.directionButton = document.getElementById("direction")
- this.enableDouble = function(b) {
- self.doubleButton.disabled = !b;
- }
- this.enableAccept = function(b) {
- self.acceptButton.disabled = !b;
- }
- this.enableRefuse = function(b) {
- self.refuseButton.disabled = !b;
- }
- this.enableUndo = function(b) {
- self.undoButton.disabled = !b;
- }
- }
- function MatchInfo(game, graphicMatchInfo) {
- this.pic = graphicMatchInfo;
- this.plug = function() {
- var foo = function() {};
- this.setNames = this.pic.setNames || foo; // white-name black-name
- this.setScore = this.pic.setScore || foo; // player score away
- this.setPips = this.pic.setPips || foo; // player pips diff
- this.setMatchLimit = this.pic.setMatchLimit || foo; // limit/null
- this.setCrawford = this.pic.setCrawford || foo; // bool
- this.setJacoby = this.pic.setJacoby || foo; // bool
- }
- this.refresh = function() {
- // TODO names
- //this.setName("white", game.names.white);
- this.setNames(ui.whiteName, ui.blackName);
- this.setScore("white", game.matchScore[0], game.matchLimit && (game.matchLimit - game.matchScore[0]));
- this.setScore("black", game.matchScore[1], game.matchLimit && (game.matchLimit - game.matchScore[1]));
- var whitePips = game.pips("white");
- var blackPips = game.pips("black");
- this.setPips("white", whitePips, whitePips - blackPips);
- this.setPips("black", blackPips, blackPips - whitePips);
- this.setMatchLimit(game.matchLimit);
- if (game.matchLimit) {
- this.setCrawford(game.isCrawford);
- } else {
- this.setJacoby(game.withJacoby);
- }
- }
- }
- function GraphicMatchInfo() {
- this.setNames = function(whiteName, blackName) {
- document.getElementById("white-name").innerHTML = whiteName || "";
- document.getElementById("black-name").innerHTML = blackName || "";
- }
- this.setScore = function(player, score, away) {
- document.getElementById( player === "white" ? "white-score" : "black-score").innerHTML = score;
- if (!isNaN(away)) {
- if (away > 0) {
- document.getElementById( player === "white" ? "white-away" : "black-away")
- .innerHTML = "(" + away + "-away)";
- } else {
- document.getElementById( player === "white" ? "white-away" : "black-away")
- .innerHTML = "(won match)";
- }
- }
- }
- this.setPips = function(player, pips, diff) {
- document.getElementById( player === "white" ? "white-pips" : "black-pips").innerHTML = pips;
- document.getElementById( player === "white" ? "white-diff" : "black-diff").innerHTML
- = (diff >= 0) ? "+" + diff : diff;
- }
- this.setMatchLimit = function(limit) {
- document.getElementById("match-limit").innerHTML = (limit || "unlimited");
- }
- this.setCrawford = function(isCrawford) {
- document.getElementById("match-misc").innerHTML = isCrawford ? "Crawford game" : "";
- }
- this.setJacoby = function(withJacoby) {
- document.getElementById("match-misc").innerHTML = withJacoby ? "Jacoby rule" : "";
- }
- }
- function Hint(graphicHint) {
- this.pic = graphicHint;
- this.plug = function () {
- // set to null to clear
- this.setHint = this.pic.setHint;
- }
- }
- function GraphicHint() {
- var self = this;
- this.setHint = function(text) {
- document.getElementById("hint").innerHTML = text || "";
- }
- }
- var score = [0, 0];
- var game = new Game();
- var ui = new UI();
- //var boardPic = Snap(520, 300);
- var boardPaper = Snap("#board");
- var boardPic = new SVGBoard(boardPaper);
- var maxCirclesOnPoint = 6;
- //var board = new Board(game, ui, boardPic)
- var graphicToolbar = new GraphicToolbar();
- var userIntereface = new UserInterface(game, ui, boardPic, graphicToolbar, new GraphicMatchInfo(), new GraphicHint());
- var PLAYER = "watching";
- document.getElementById("player").innerHTML = PLAYER;
- function statusBar() {
- return document.getElementById("status");
- }
- function point(x, y, direction, colour) {
- var triangle = boardPic.polyline([x, y, x + board.pointWidth, y, x + 0.5 * board.pointWidth, y + direction * board.pointHeight, x, y]);
- triangle.attr({
- fill: colour
- });
- return triangle;
- }
- function checkPointID(ID) {
- if (!(0 <= ID && ID < 24))
- throw "Invalid point ID";
- }
- function checkPlayer(player) {
- if (!(player == "black" || player == "white" || player === null))
- throw "Invalid player";
- }
- function pointPic(board, ID) {
- checkPointID(ID);
- var direction = pointDirection(ID);
- var colour = (ID % 2 == 0) ? board.params.evenColour : board.params.oddColour;
- return board.point(pointX(board, ID) - 0.5 * board.params.pointWidth, pointBaseY(board, ID), direction, colour);
- }
- function pointX(board, ID) {
- checkPointID(ID);
- var base = (ID < 12) ? ID * board.params.pointWidth : (23 - ID) * board.params.pointWidth;
- base += 0.5 * board.params.pointWidth + 2 * board.params.borderWidth + board.params.pointWidth;
- if (6 <= ID && ID < 18) base += board.params.barWidth;
- return base;
- }
- function pointBaseY(board, ID) {
- return (ID < 12) ? board.params.borderWidth : board.params.height - board.params.borderWidth;
- }
- function pointTopY(board, ID) {
- checkPointID(ID);
- return (ID < 12) ? board.params.pointHeight : board.params.height - board.params.pointHeight;
- }
- function pointDirection(ID) {
- checkPointID(ID);
- return (ID < 12) ? 1 : -1;
- }
- function moveEvent(from, pips) {
- return ["m", from, pips];
- }
- function sendEvent(evt) {
- console.log("sending " + JSON.stringify(evt));
- websocket.send(JSON.stringify(evt));
- statusBar().innerHTML = (JSON.stringify(evt));
- }
- function continueEvent(decision) {
- return ["c", decision ? "yes" : "no"];
- }
- function proposalDecisionEvent(decision) {
- return ["proposal-decision", decision ? "yes" : "no"];
- }
- function dispatchCommand(command) {
- console.log(command);
- if (command[0] == "player") {
- PLAYER = command[1];
- userIntereface.board.orientation = PLAYER;
- document.getElementById("player").innerHTML = PLAYER;
- //checkerPic(Snap("#player"), PLAYER, 10, 10);
- } else if (command[0] == "update") {
- setGame(game, ui, command[1]);
- userIntereface.refresh();
- } else if (command[0] == "continue?") {
- sendEvent(continueEvent(confirm("One more?")));
- } else if (command[0] == "message") {
- statusBar().innerHTML = command[1];
- } else if (command[0] == "proposal") {
- ui.putEvent(proposalDecisionEvent(confirm("Do you want to play with " + command[1] + "?")));
- } else if (command[0] == "cancelled") {
- alert("Cancelled by " + command[1]);
- }
- }
- function physicalToAbsolute(p, clockwise, orientation) {
- if (clockwise && (orientation === "black")) return p;
- if (!clockwise && (orientation === "black")) return (p < 12) ? 11 - p : 35 - p;
- if (clockwise && (orientation === "white")) return 23 - p;
- if (!clockwise && (orientation === "white")) return (p < 12) ? p + 12 : p - 12;}
- function setGame(game, ui, obj) {
- game.turn = obj.game.turn;
- if (!game.turn) {
- game.dice = obj.game["dice"];
- } else if (obj.game["dice"].length === 0 || obj.game["dice-no"] !== game.diceNo ||
- obj.game["game-no"] !== game.gameNo) {
- game.diceNo = obj.game["dice-no"];
- game.dice = obj.game.dice.sort().reverse();
- game.restDice = obj.game["rest-dice"].sort().reverse();
- } else {
- /* If the move is the same, we've got two dice and we receive two dice
- * from the server, they must be the same two dice as we have, so we
- * copy game.dice to game.restDice in order to save the custom dice
- * order. Otherwise we either have a single die or identical dice,
- * either way we don't care about the order.
- */
- game.restDice = (game.dice.length === 2 && obj.game["rest-dice"].length === 2)
- ? game.dice.slice() : obj.game["rest-dice"]
- }
- game.gameNo = obj.game["game-no"];
- game.cube = obj.game["cube"];
- game.cubeOwner = obj.game["cube-owner"];
- game.isDoubling = obj.game["is-doubling"];
- game.isCrawford = obj.game["crawford?"];
- game.withJacoby = obj.game["jacoby?"];
- game.matchLimit = obj.game["match-limit"];
- game.result = obj.game.result;
- game.moves = obj.game.moves;
- game.winner = obj.game["winner"];
- game.score = obj.game["score"];
- game.matchScore = obj.game["match-score"];
- game.board = obj.game.board;
- if (obj.ui) {
- ui.checkersEnabled = obj.ui["checkers-enabled"];
- ui.undoEnabled = obj.ui["undo-enabled"];
- ui.moveCompletionEnabled = obj.ui["move-completion-enabled"];
- ui.offerDoubleEnabled = obj.ui["offer-double-enabled"];
- ui.acceptDoubleEnabled = obj.ui["accept-double-enabled"];
- ui.whiteName = obj.ui["white-name"];
- ui.blackName = obj.ui["black-name"];
- }
- }
- var wsUri = "ws://" + window.location.host + window.location.pathname;
- var websocket = new WebSocket(wsUri);
- function setupWebSocket()
- {
- websocket.onopen = function(evt) { onOpen(evt) };
- websocket.onclose = function(evt) { onClose(evt) };
- websocket.onmessage = function(evt) { onMessage(evt) };
- websocket.onerror = function(evt) { onError(evt) };
- }
- function onOpen(evt)
- {
- statusBar().innerHTML = "connected";
- }
- function onClose(evt)
- {
- statusBar().innerHTML = "disconnected";
- }
- function onMessage(evt)
- {
- //setGameFromJSON(board, evt.data.toLowerCase());
- dispatchCommand(JSON.parse(evt.data.toLowerCase()));
- //alert(evt.data.toLowerCase());
- }
- function onError(evt)
- {
- }
- function doSend(message)
- {
- }
- function writeToScreen(message)
- {
- }
- //window.addEventListener("load", setupWebSocket, false);
- setupWebSocket();
- //console.log(new checkerPic("black", pointX(board, 3), pointTopY(board, 3) - board.checkerRadius, "15"));
- //var st = new SVGStorage(board, 1);
- //st.setCheckers(4, "white");
- //
- /*
- {
- this.points.forEach(function(p, i) {
- let a = physicalToAbsolute(i, board.clockwise, board.orientation);
- p.setCheckers(game.board.points[a].checkers, game.board.points[a].player);
- });
- this.bar.setCheckers(game.board.bar.white, "white");
- this.bar.setCheckers(game.board.bar.black, "black");
- this.undoButton.disabled = !ui.undoEnabled;
- this.leftPane.refresh();
- document.getElementById("accept").disabled = !ui.acceptDoubleEnabled;
- document.getElementById("refuse").disabled = !ui.acceptDoubleEnabled;
- document.getElementById("double").disabled = !ui.offerDoubleEnabled;
- var offWhite = this.bearoffStorageID.white();
- var offBlack = this.bearoffStorageID.black();
- var cubeLocation = this.cubeLocation();
- for (let i = 0; i < 4; ++i) {
- if (i === offWhite) {
- this.storages[i].setCheckers(game.board.off.white, "white");
- } else if (i === offBlack) {
- this.storages[i].setCheckers(game.board.off.black, "black");
- } else if (i === cubeLocation) {
- this.storages[i].setCube(game.cube);
- } else {
- this.storages[i].setCheckers(0, null);
- }
- }
- if (cubeLocation === "left") this.setCubeLeft(game.cube)
- else if (cubeLocation === "right") this.setCubeRight(game.cube)
- else if (cubeLocation === "leftPane") this.setCubeLeftPane(2*game.cube);
- else if (cubeLocation === "rightPane") this.setCubeRightPane(2*game.cube)
- else if (cubeLocation === null && this.cubePic) this.cubePic.remove();
- document.getElementById("pips").innerHTML = "Pips: white " + game.pips("white") + " black " + game.pips("black");
- if (!game.winner) statusBar().innerHTML = game.turn + " " + game.restDice;
- else {
- let winner = game.winner;
- let res = game.score;
- let text = (res === 1) ? winner + " wins 1 point." : winner + " wins " + res + " points."
- alert(text);
- statusBar().innerHTML = text;
- }
- }
- */
- function showStatus() {
- document.getElementById("status").hidden = false;
- }
- </script>
- </body>
|