From 201407b8ea988dcba0d661c73eabff957d6db3d8 Mon Sep 17 00:00:00 2001 From: Sorrel Bri Date: Wed, 7 Aug 2019 12:45:58 -0700 Subject: [PATCH] debug territory count at endgame --- README.md | 3 +- css/main.css | 26 ++++++++-- index.html | 4 +- js/main.js | 140 ++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 125 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index dcd7716..2221f04 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ a working game of go for a 9x9 board that - [x] ends game upon 2 consecutive passes - [ ] calculates estimated score at game end - [ ] compares board groups to most common dead shapes -- [ ] allows users to override dead group estimates and submit finalized score to game record +- [x] allows users to override dead group estimates +- [ ] allows users to submit finalized score to game record - [ ] displays game record as string stretch goals diff --git a/css/main.css b/css/main.css index 2906b1c..843affb 100644 --- a/css/main.css +++ b/css/main.css @@ -1,5 +1,9 @@ @import url('https://fonts.googleapis.com/css?family=La+Belle+Aurore|Raleway:300|Raleway:600'); +html { + font-size: 12px; +} + * { box-sizing: border-box; margin: 0; @@ -39,7 +43,7 @@ body { "player" "record" "submit"; - font: 14px 'La Belle Aurore', cursive; + font-family: 'La Belle Aurore', cursive; min-height: 0; } @@ -83,7 +87,6 @@ h4 { #player-meta input[type="button"] { margin: .25em; - height: 100%; } div[data-player-meta] { @@ -176,6 +179,14 @@ content { #game-hud p { font-size: 130%; + width: 50%; + order: 0; + width: 10vh; + background-color: rgba(0,0,0,0.3); + padding: 1vh; + color: #fff; + cursor: pointer; + visibility: hidden; } .player-pos#black-pos { @@ -222,7 +233,7 @@ content { } .bowl[data-turn] { - box-shadow: 0 0 3vh 3vh rgb(31, 255, 2); + box-shadow: 0 0 3vh 3vh rgb(255, 175, 2); } .caps-space { @@ -401,20 +412,27 @@ td .dot .seki { } @media only screen and (min-width: 560px) { + #player-meta { flex-direction: row; } + div[data-player-meta] { width: 50%; } + #menu { grid-template-columns: 60vw; grid-template-rows: auto auto 60vw auto; - font-size: 14px; } } @media only screen and (min-width: 500px) { + + html { + font-size: 14px; + } + .player-pos { height: 14vh; } diff --git a/index.html b/index.html index ba10700..43d7e3c 100644 --- a/index.html +++ b/index.html @@ -50,8 +50,8 @@ To begin a game enter player names and ranks above, then click "Suggest Komi" Browser Go will calculate the appropriate komi based on AGA guidelines. To override Browser Go's suggestion, use the sliders above. Be sure to check the 'rank certainty' box if you're club-rated.

When the game begins, click on a legal point on the board to make a move. The active player's bowl will be highlighted. To pass, click on your bowl. - This will only be possible on your turn. To resign click on your capture tray. To view the game record or adjust player settings, click the kifu on black's side.

- For now, Browser Go only supports games on a small board. + This will only be possible on your turn. To resign click on your capture tray. After the game ends, groups and territory will display Browser Go's estimate for final state. + Simply click on a group to change a group between live and dead, or a point between territory and dame. I've got great things planned for the future, though! Lookout for new releases on the GitHub page!

diff --git a/js/main.js b/js/main.js index ca914ba..f2a308d 100644 --- a/js/main.js +++ b/js/main.js @@ -12,7 +12,6 @@ const DOTS_DATA = { '0': 'none', '1': 'black', 'd': 'dame', - 's': 'seki' } const RANKS = [ @@ -49,13 +48,15 @@ const HANDI_REC = { const gameState = { winner: null, turn: 1, // turn logic depends on handicap stones - pass: null, + pass: null, // -1 represents state in which resignation has been submitted, not confirmed komi: null, // komi depends on handicap stones + player rank handicap: null, boardSize: 9, playerState: { bCaptures: null, - wCaptures: null + wCaptures: null, + bScore: null, + wScore: null }, gameMeta: { // declared at game start and not editable after date: null // contains metadata @@ -188,8 +189,12 @@ class Point { } } cycleTerritory = () => { - this.groupMembers.forEach(pt => { - switch (pt.territory) { + console.log(this); + if (this.stone) { + this.groupMembers.forEach(pt => pt.territory = pt.territory * -1); + } else { + this.groupMembers.forEach(pt => { + switch (pt.territory) { case 1: pt.territory = -1; break; @@ -199,8 +204,9 @@ class Point { case 'd': pt.territory = 1; break; - } - }) + } + }); + } } } // could use this Array to iterate through and create @@ -235,15 +241,8 @@ const gameHudEl = document.querySelector('#game-hud p'); /*----- event listeners -----*/ -// input listeners for player names, ranks, rank certainty (editable during game) -//input lister for handicap + komi (only editable pre-game) -// ::hover-over on board to preview move (with legal move logic) document.getElementById('board').addEventListener('mousemove', hoverPreview); -// click on board to play move document.getElementById('board').addEventListener('click', clickBoard); -// ::hover-over on either bowl for pass, one-level undo options (CSS implementation) -// click on menu items -// click on kifu to display game menu document.getElementById('white-bowl').addEventListener('click',clickPass); document.getElementById('black-bowl').addEventListener('click',clickPass); document.getElementById('kifu').addEventListener('click', clickMenu); @@ -255,7 +254,7 @@ handiSliderEl.addEventListener('change', changeUpdateHandicap); document.getElementById('player-meta').addEventListener('click', clickUpdatePlayerMeta); document.getElementById('player-meta').addEventListener('change', clickUpdatePlayerMeta); document.querySelector('input[name="komi-suggest"]').addEventListener('click', clickKomiSuggestion); -gameHudEl.addEventListener('click', clickSubmitScore); +gameHudEl.addEventListener('click', clickGameHud); /*----- functions -----*/ @@ -303,12 +302,12 @@ function clickKomiSuggestion() { renderMenu(); } -function clickSubmitScore() { +function clickGameHud() { if (gameState.pass > 1 && !gameState.winner) calculateWinner(); + if (gameState.pass < 0) confirmResign(); } function clickSubmitStart() { - gameState.playerMeta.b.name = blackNameInputEl.value; gameState.playerMeta.w.name = whiteNameInputEl.value; initGame(); @@ -344,6 +343,14 @@ function clickMenu() { clickUpdatePlayerMeta(); } +function startMenu() { + modalEl.style.visibility = 'visible'; + changeUpdateKomi(); + changeUpdateHandicap(); + clickUpdatePlayerMeta(); + +} + function clickCloseMenu(evt) { evt.stopPropagation(); if (evt.target.className === "modal") modalEl.style.visibility = 'hidden'; @@ -354,14 +361,19 @@ function clickResign(evt) { } function playerResign() { - // display confirmation message - if (!confirm('Do you want to resign?')) return; + // display confirmation message\ + gameState.pass = -1; + gameHudEl.style.visibility = "visible"; + gameHudEl.textContent = "Do you want to resign?"; +} +function confirmResign() { gameState.gameRecord.push(`${STONES_DATA[gameState.turn]}: resign`); gameState.winner = STONES_DATA[gameState.turn * -1]; endGame(); } + function hoverPreview(evt) { evt.stopPropagation(); if (gameState.pass > 1 || gameState.winner) return; @@ -477,15 +489,16 @@ function getDate() { return `${d.getFullYear()}-${String(d.getMonth()+1).charAt(-1)||0}${String(d.getMonth()+1).charAt(-0)}-${String(d.getDate()).charAt(-1)||0}${String(d.getDate()+1).charAt(-0)}` } function init() { + gameState.gameMeta.date = getDate(); + gameState.komi = 5.5; // get komi from player input + // startMenu(); gameState.winner = null; gameState.pass = null; - // gameState.komi = ; // get komi from player input // gameState.handicap = ; // get handicap from player input gameState.turn = gameState.handicap ? -1 : 1; gameState.boardSize = 9; gameState.playerState.bCaptures = 0; gameState.playerState.wCaptures = 0; - gameState.gameMeta.date = getDate(); // get any future meta from player input // gameState.playerMeta.b // get from player input // gameState.playerMeta.w // get from player input @@ -511,12 +524,19 @@ function render() { function renderMessage() { if (gameState.winner && gameState.pass < 2) { + gameHudEl.style.visibility = 'visible'; + gameHudEl.style.cursor = 'default'; gameHudEl.textContent = `${gameState.playerMeta[gameState.winner === 1 ? 'b' : 'w'].name} won by resignation`; } else if (gameState.winner && gameState.pass > 1) { - gameHudEl.textContent = `${gameState.playerMeta[gameState.winner === 1 ? 'b' : 'w'].name} won by `; - } else { + gameHudEl.style.visibility = 'visible'; + gameHudEl.style.cursor = 'default'; + gameHudEl.textContent = `${gameState.playerMeta[gameState.winner === 1 ? 'b' : 'w'].name} won by ${Math.abs(gameState.playerState.wScore - gameState.playerState.bScore)}`; + } else if (gameState.pass > 1) { + gameHudEl.style.visibility = 'visible'; gameHudEl.textContent = 'click to finalize game' + } else { + gameHudEl.style.visibility = 'hidden'; } } @@ -560,31 +580,69 @@ function renderPreview(hoverPoint) { } function calculateWinner() { - + // debugger; + let whiteTerritory = boardState.reduce((acc, pt) => { + if (pt.territory === -1 && pt.stone !== -1) { + return acc = acc + (pt.stone === 0 ? 1 : 2); + } + return acc; + }, 0); + console.log(whiteTerritory); + let blackTerritory = boardState.reduce((acc, pt) => { + if (pt.territory === 1 && pt.stone !== 1) { + return acc + (pt.stone === 0 ? 1 : 2); + } + return acc; + }, 0); + console.log(blackTerritory); + gameState.playerState.wScore = + gameState.playerState.wCaptures + + (gameState.komi < 0 ? gameState.komi * -1 : 0) + + whiteTerritory; + gameState.playerState.bScore = + gameState.playerState.bCaptures + + (gameState.komi > 0 ? gameState.komi : 0) + + blackTerritory; + gameState.winner = gameState.playerState.wScore > gameState.playerState.bScore ? -1 : 1; + gameState.gameRecord.push(`${STONES_DATA[gameState.winner]}: +${Math.abs(gameState.playerState.wScore - gameState.playerState.bScore)}`) + render(); } function endGameSetTerritory() { - boardState.forEach(pt => { - pt.territory = pt.stone ? pt.stone : 'd' - }); + // boardState.forEach(pt => { + // pt.territory = pt.stone ? pt.stone : 'd' + // }); let emptyPoints = boardState.filter(pt => !pt.stone); emptyPoints.forEach(pt => pt.joinGroup()); emptyPointSetTerritory(emptyPoints); - boardState.filter(pt => { - return pt.groupMembers.length < 6 && pt.stone - }).forEach(pt => pt.territory = pt.stone * -1); + // boardState.filter(pt => { + // return pt.groupMembers.length < 6 && pt.stone + // }).forEach(pt => pt.territory = pt.stone * -1); } function emptyPointSetTerritory(emptyPoints) { - // let dame = emptyPoints.filter(pt => pt.checkNeighbors().some(nbr => nbr.territory === 1) - // && pt.checkNeighbors().some(nbr => nbr.territory === -1)); - // dame.forEach(pt => pt.territory = 'd'); - // emptyPoints.filter(pt => pt.territory = 0) + emptyPoints.filter(pt => !pt.territory && pt.checkNeighbors().filter(nbr => nbr.stone !== 0)) + .forEach(pt => { + console.log(pt); + let b = pt.groupMembers.reduce((acc, rdcPt) => { + let bNbr = rdcPt.checkNeighbors().filter(nbr => nbr.stone === 1).length; + return acc + bNbr; + }, 0); + let w = pt.groupMembers.reduce((acc, rdcPt) => { + debugger; + let wNbr = rdcPt.checkNeighbors().filter(nbr => nbr.stone === -1).length; + return acc + wNbr; + }, 0); + pt.groupMembers.forEach(grp => { + if (Math.abs(b - w) < 4) grp.territory = 'd' + else grp.territory = b > w ? 1 : -1; + }) + }); } function endGame() { - if (!gameState.winner) - endGameSetTerritory() + if (!gameState.winner) endGameSetTerritory() + // join all remaining groups // check remaining groups life @@ -593,15 +651,15 @@ function endGame() { // compare spaces to rotations of deadShapes[...] // 'd' if empty spaces - render(); - // return dead group suggestion - // users can flip status of any dead group overlay( 1, -1 ) - // confirm state + // return dead group suggestion + // users can flip status of any dead group overlay( 1, -1 ) + // confirm state // calculate score = points in overlay for each player + captures // render final board state with dead groups removed - // log game record + // log game record // stringify according to .sgf format // log as text + render(); } // game-end