add player input
This commit is contained in:
parent
70e0e18815
commit
793d2bbb06
3 changed files with 75 additions and 86 deletions
|
@ -13,8 +13,8 @@ a working game of go for a 9x9 board that
|
||||||
- [x] logs game record
|
- [x] logs game record
|
||||||
- [x] allows players to pass or resign
|
- [x] allows players to pass or resign
|
||||||
- [x] ends game upon 2 consecutive passes
|
- [x] ends game upon 2 consecutive passes
|
||||||
- [ ] calculates estimated score at game end
|
- [x] calculates estimated score at game end
|
||||||
- [ ] compares board groups to most common dead shapes
|
- [x] suggests dead groups
|
||||||
- [x] allows users to override dead group estimates
|
- [x] allows users to override dead group estimates
|
||||||
- [ ] allows users to submit finalized score to game record
|
- [ ] allows users to submit finalized score to game record
|
||||||
- [ ] displays game record as string
|
- [ ] displays game record as string
|
||||||
|
@ -27,7 +27,7 @@ stretch goals
|
||||||
- [ ] add stone placement sounds
|
- [ ] add stone placement sounds
|
||||||
|
|
||||||
superstretch goals
|
superstretch goals
|
||||||
- [x] allows users to select board size (9x9, 13x13, 19x19)
|
- [ ] allows users to select board size (9x9, 13x13, 19x19)
|
||||||
- [ ] allows users to load .sgf main lines
|
- [ ] allows users to load .sgf main lines
|
||||||
- [ ] allow for responsivity in the form of
|
- [ ] allow for responsivity in the form of
|
||||||
- - [ ] 9x9 games simply stretch with screen size
|
- - [ ] 9x9 games simply stretch with screen size
|
||||||
|
|
12
index.html
12
index.html
|
@ -33,7 +33,7 @@
|
||||||
<div id="player-meta">
|
<div id="player-meta">
|
||||||
<div data-player-meta="black">
|
<div data-player-meta="black">
|
||||||
<h4 class="menu-heading">Black</h4>
|
<h4 class="menu-heading">Black</h4>
|
||||||
<span class="menu-heading">Name:</span><input type="text" name="black-name">
|
<span class="menu-heading">Name:</span><input type="text" name="black-name">
|
||||||
<div class="menu-line">
|
<div class="menu-line">
|
||||||
<span class="menu-heading">Rank:</span><span id="black-rank">9k</span><input type="button" id="black-rank-up" value="▲"><input type="button" id="black-rank-down" value="▼">
|
<span class="menu-heading">Rank:</span><span id="black-rank">9k</span><input type="button" id="black-rank-up" value="▲"><input type="button" id="black-rank-down" value="▼">
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,11 +43,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div data-player-meta="white">
|
<div data-player-meta="white">
|
||||||
<h4 class="menu-heading">White</h4>
|
<h4 class="menu-heading">White</h4>
|
||||||
<span class="menu-heading">Name:</span><input type="text" name="white-name">
|
<span class="menu-heading">Name:</span><input type="text" name="white-name">
|
||||||
<div class="menu-heading">
|
<div class="line">
|
||||||
<span class="menu-heading">Rank:</span><span id="white-rank">9k</span><input type="button" id="white-rank-up" value="▲"><input type="button" id="white-rank-down" value="▼">
|
<span class="menu-heading">Rank:</span><span id="white-rank">9k</span><input type="button" id="white-rank-up" value="▲"><input type="button" id="white-rank-down" value="▼">
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-heading">
|
<div class="menu-line">
|
||||||
<input type="checkbox" name="white-rank-certain"><label for="white-rank-certain">Rank Certainty</label>
|
<input type="checkbox" name="white-rank-certain"><label for="white-rank-certain">Rank Certainty</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,8 +59,8 @@
|
||||||
To override Browser Go's suggestion, use the sliders above. Be sure to check the 'rank certainty' box if you're club-rated.<br><br>
|
To override Browser Go's suggestion, use the sliders above. Be sure to check the 'rank certainty' box if you're club-rated.<br><br>
|
||||||
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.
|
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. After the game ends, groups and territory will display Browser Go's estimate for final state.
|
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.
|
Simply click on a group to change a group between live and dead, or a point between territory and dame.<br><br>
|
||||||
I've got great things planned for the future, though! Lookout for new releases on <a href="https://github.com/sorrelbri/browser-go">the GitHub page!</a></p>
|
For now, your game can't be saved. I've got great things planned for the future, though! Lookout for new releases and suggest new features on <a href="https://github.com/sorrelbri/browser-go">the GitHub page!</a></p>
|
||||||
<p id="game-record"></p>
|
<p id="game-record"></p>
|
||||||
</div>
|
</div>
|
||||||
<div id="game-update-space">
|
<div id="game-update-space">
|
||||||
|
|
143
js/main.js
143
js/main.js
|
@ -234,6 +234,10 @@ const whiteNameInputEl = document.querySelector('input[name="white-name"]')
|
||||||
const blackNameDisplayEl = document.querySelector('h4#black-player-name');
|
const blackNameDisplayEl = document.querySelector('h4#black-player-name');
|
||||||
const whiteNameDisplayEl = document.querySelector('h4#white-player-name');
|
const whiteNameDisplayEl = document.querySelector('h4#white-player-name');
|
||||||
const gameHudEl = document.querySelector('#game-hud p');
|
const gameHudEl = document.querySelector('#game-hud p');
|
||||||
|
const dateEl = document.getElementById('date');
|
||||||
|
const boardSizeEl = document.getElementById('board-size-radio');
|
||||||
|
const komiDisplayEl = document.getElementById('komi');
|
||||||
|
const handiDisplayEl = document.getElementById('handicap');
|
||||||
|
|
||||||
// store modal #menu for displaying game info
|
// store modal #menu for displaying game info
|
||||||
// store
|
// store
|
||||||
|
@ -254,6 +258,8 @@ document.getElementById('player-meta').addEventListener('click', clickUpdatePlay
|
||||||
document.getElementById('player-meta').addEventListener('change', clickUpdatePlayerMeta);
|
document.getElementById('player-meta').addEventListener('change', clickUpdatePlayerMeta);
|
||||||
document.querySelector('input[name="komi-suggest"]').addEventListener('click', clickKomiSuggestion);
|
document.querySelector('input[name="komi-suggest"]').addEventListener('click', clickKomiSuggestion);
|
||||||
gameHudEl.addEventListener('click', clickGameHud);
|
gameHudEl.addEventListener('click', clickGameHud);
|
||||||
|
boardSizeEl.addEventListener('click', clickBoardSize);
|
||||||
|
document.querySelector('input[name="game-start"]').addEventListener('click', clickSubmitStart);
|
||||||
|
|
||||||
|
|
||||||
/*----- functions -----*/
|
/*----- functions -----*/
|
||||||
|
@ -262,11 +268,15 @@ init();
|
||||||
let findPointFromIdx = (arr) => boardState.find( point => point.pos[0] === arr[0] && point.pos[1] === arr[1] );
|
let findPointFromIdx = (arr) => boardState.find( point => point.pos[0] === arr[0] && point.pos[1] === arr[1] );
|
||||||
|
|
||||||
function changeUpdateKomi() {
|
function changeUpdateKomi() {
|
||||||
document.getElementById('komi').textContent = komiSliderEl.value;
|
komiDisplayEl.textContent = komiSliderEl.value;
|
||||||
|
gameState.komi = komiSliderEl.value;
|
||||||
|
renderMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeUpdateHandicap() {
|
function changeUpdateHandicap() {
|
||||||
document.getElementById('handicap').textContent = handiSliderEl.value;
|
handiDisplayEl.textContent = handiSliderEl.value !== 1 ? handiSliderEl.value : 0;
|
||||||
|
gameState.handicap = handiSliderEl.value !== 1 ? handiSliderEl.value : 0;
|
||||||
|
renderMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickUpdatePlayerMeta(evt) {
|
function clickUpdatePlayerMeta(evt) {
|
||||||
|
@ -288,14 +298,20 @@ function clickUpdatePlayerMeta(evt) {
|
||||||
}
|
}
|
||||||
if (evt.target.name = 'black-rank-certain') gameState.playerMeta.b.rankCertain = !gameState.playerMeta.b.rankCertain;
|
if (evt.target.name = 'black-rank-certain') gameState.playerMeta.b.rankCertain = !gameState.playerMeta.b.rankCertain;
|
||||||
if (evt.target.name = 'white-rank-certain') gameState.playerMeta.w.rankCertain = !gameState.playerMeta.w.rankCertain;
|
if (evt.target.name = 'white-rank-certain') gameState.playerMeta.w.rankCertain = !gameState.playerMeta.w.rankCertain;
|
||||||
blackRankEl.textContent = RANKS[gameState.playerMeta.b.rank];
|
renderMenu();
|
||||||
whiteRankEl.textContent = RANKS[gameState.playerMeta.w.rank];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickKomiSuggestion() {
|
function clickBoardSize() {
|
||||||
let sugg = KOMI_REC[Math.abs(gameState.playerMeta.w.rank - gameState.playerMeta.b.rank)];
|
gameState.boardSize = boardSizeEl.value;
|
||||||
let handi = HANDI_REC[Math.abs(gameState.playerMeta.w.rank - gameState.playerMeta.b.rank)];
|
renderMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickKomiSuggestion(evt) {
|
||||||
|
debugger;
|
||||||
|
evt.stopPropagation();
|
||||||
|
let sugg = KOMI_REC[gameState.boardSize][Math.abs(gameState.playerMeta.w.rank - gameState.playerMeta.b.rank)];
|
||||||
|
let handi = HANDI_REC[gameState.boardSize][Math.abs(gameState.playerMeta.w.rank - gameState.playerMeta.b.rank)];
|
||||||
gameState.komi = sugg;
|
gameState.komi = sugg;
|
||||||
gameState.handicap = handi;
|
gameState.handicap = handi;
|
||||||
renderMenu();
|
renderMenu();
|
||||||
|
@ -312,8 +328,28 @@ function clickSubmitStart() {
|
||||||
initGame();
|
initGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderKomi() {
|
||||||
|
komiSliderEl.value = gameState.komi;
|
||||||
|
komiDisplayEl.textContent = gameState.komi;
|
||||||
|
if (gameState.gameRecord.length) komiSliderEl.setAttribute('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHandiSlider() {
|
||||||
|
handiSliderEl.value = gameState.handicap;
|
||||||
|
handiDisplayEl.textContent = gameState.handicap;
|
||||||
|
if (gameState.gameRecord.length) handiSliderEl.setAttribute('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderBoardSizeRadio() {
|
||||||
|
boardSizeEl.value = gameState.boardSize;
|
||||||
|
if (gameState.gameRecord.length) boardSizeEl.setAttribute('disabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
function renderMenu() {
|
function renderMenu() {
|
||||||
komiSliderEl.value = sugg;
|
dateEl.textContent = gameState.gameMeta.date;
|
||||||
|
renderKomi()
|
||||||
|
renderHandiSlider();
|
||||||
|
renderBoardSizeRadio();
|
||||||
blackNameDisplayEl.textContent = gameState.playerMeta.b.name;
|
blackNameDisplayEl.textContent = gameState.playerMeta.b.name;
|
||||||
whiteNameDisplayEl.textContent = gameState.playerMeta.w.name;
|
whiteNameDisplayEl.textContent = gameState.playerMeta.w.name;
|
||||||
blackRankEl.textContent = RANKS[gameState.playerMeta.b.rank];
|
blackRankEl.textContent = RANKS[gameState.playerMeta.b.rank];
|
||||||
|
@ -332,7 +368,7 @@ function playerPass() {
|
||||||
gameState.pass++;
|
gameState.pass++;
|
||||||
if (gameState.pass === 2) return endGame();
|
if (gameState.pass === 2) return endGame();
|
||||||
gameState.turn*= -1;
|
gameState.turn*= -1;
|
||||||
render();
|
renderGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickMenu() {
|
function clickMenu() {
|
||||||
|
@ -344,12 +380,12 @@ function clickMenu() {
|
||||||
|
|
||||||
function startMenu() {
|
function startMenu() {
|
||||||
modalEl.style.visibility = 'visible';
|
modalEl.style.visibility = 'visible';
|
||||||
renderMenu;
|
renderMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickCloseMenu(evt) {
|
function clickCloseMenu(evt) {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
if (evt.target.className === "modal") modalEl.style.visibility = 'hidden';
|
if (evt.target.className === "modal" && gameState.gameRecord.length) modalEl.style.visibility = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickResign(evt) {
|
function clickResign(evt) {
|
||||||
|
@ -421,7 +457,7 @@ function editTerritory(evt) {
|
||||||
let placement = [ parseInt(evt.target.closest('td').id[0]), parseInt(evt.target.closest('td').id[2]) ];
|
let placement = [ parseInt(evt.target.closest('td').id[0]), parseInt(evt.target.closest('td').id[2]) ];
|
||||||
let point = findPointFromIdx(placement);
|
let point = findPointFromIdx(placement);
|
||||||
point.cycleTerritory();
|
point.cycleTerritory();
|
||||||
render();
|
renderGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkKo(point, cap) {
|
function checkKo(point, cap) {
|
||||||
|
@ -445,7 +481,7 @@ function clickBoard(evt) {
|
||||||
clearCaptures();
|
clearCaptures();
|
||||||
gameState.gameRecord.push(`${STONES_DATA[gameState.turn]}: ${point.pos}`)
|
gameState.gameRecord.push(`${STONES_DATA[gameState.turn]}: ${point.pos}`)
|
||||||
gameState.turn*= -1;
|
gameState.turn*= -1;
|
||||||
render();
|
renderGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearKo() {
|
function clearKo() {
|
||||||
|
@ -487,28 +523,26 @@ function getDate() {
|
||||||
function init() {
|
function init() {
|
||||||
gameState.gameMeta.date = getDate();
|
gameState.gameMeta.date = getDate();
|
||||||
gameState.komi = 5.5; // get komi from player input
|
gameState.komi = 5.5; // get komi from player input
|
||||||
startMenu();
|
|
||||||
gameState.winner = null;
|
gameState.winner = null;
|
||||||
gameState.pass = null;
|
gameState.pass = null;
|
||||||
// gameState.handicap = ; // get handicap from player input
|
|
||||||
gameState.turn = gameState.handicap ? -1 : 1;
|
|
||||||
gameState.boardSize = 9;
|
gameState.boardSize = 9;
|
||||||
gameState.playerState.bCaptures = 0;
|
gameState.playerState.bCaptures = 0;
|
||||||
gameState.playerState.wCaptures = 0;
|
gameState.playerState.wCaptures = 0;
|
||||||
// get any future meta from player input
|
gameState.gameRecord = [];
|
||||||
// gameState.playerMeta.b // get from player input
|
boardState = [];
|
||||||
// gameState.playerMeta.w // get from player input
|
startMenu();
|
||||||
gameState.gameRecord = []; // clear game record from previous game
|
|
||||||
// gameState.boardState // create board from user input
|
|
||||||
|
|
||||||
//need init player meta
|
|
||||||
initBoard();
|
|
||||||
// testing board state for moves at [32]
|
|
||||||
gameState.turn = 1;
|
|
||||||
render();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function render() {
|
function initGame() {
|
||||||
|
gameState.winner = null;
|
||||||
|
gameState.pass = null;
|
||||||
|
gameState.turn = gameState.handicap ? -1 : 1;
|
||||||
|
|
||||||
|
initBoard();
|
||||||
|
renderGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderGame() {
|
||||||
if (gameState.winner || gameState.pass > 1) {
|
if (gameState.winner || gameState.pass > 1) {
|
||||||
renderTerritory();
|
renderTerritory();
|
||||||
renderMessage();
|
renderMessage();
|
||||||
|
@ -527,7 +561,7 @@ function renderMessage() {
|
||||||
else if (gameState.winner && gameState.pass > 1) {
|
else if (gameState.winner && gameState.pass > 1) {
|
||||||
gameHudEl.style.visibility = 'visible';
|
gameHudEl.style.visibility = 'visible';
|
||||||
gameHudEl.style.cursor = 'default';
|
gameHudEl.style.cursor = 'default';
|
||||||
gameHudEl.textContent = `${gameState.playerMeta[gameState.winner === 1 ? 'b' : 'w'].name} won by ${Math.abs(gameState.playerState.wScore - gameState.playerState.bScore)}`;
|
gameHudEl.textContent = `${gameState.playerMeta[gameState.winner === 1 ? 'b' : 'w'].name || STONES_DATA[gameState.winner]} won by ${Math.abs(gameState.playerState.wScore - gameState.playerState.bScore)}`;
|
||||||
} else if (gameState.pass > 1) {
|
} else if (gameState.pass > 1) {
|
||||||
gameHudEl.style.visibility = 'visible';
|
gameHudEl.style.visibility = 'visible';
|
||||||
gameHudEl.textContent = 'click to finalize game'
|
gameHudEl.textContent = 'click to finalize game'
|
||||||
|
@ -599,7 +633,7 @@ function calculateWinner() {
|
||||||
+ blackTerritory;
|
+ blackTerritory;
|
||||||
gameState.winner = gameState.playerState.wScore > gameState.playerState.bScore ? -1 : 1;
|
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)}`)
|
gameState.gameRecord.push(`${STONES_DATA[gameState.winner]}: +${Math.abs(gameState.playerState.wScore - gameState.playerState.bScore)}`)
|
||||||
render();
|
renderGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
function endGameSetTerritory() {
|
function endGameSetTerritory() {
|
||||||
|
@ -636,7 +670,7 @@ function emptyPointSetTerritory(emptyPoints) {
|
||||||
return acc + wNbr;
|
return acc + wNbr;
|
||||||
}, 0);
|
}, 0);
|
||||||
pt.groupMembers.forEach(grp => {
|
pt.groupMembers.forEach(grp => {
|
||||||
if (Math.abs(b - w) < 4) grp.territory = 'd'
|
if (Math.abs(b - w) < 4 && b && w) grp.territory = 'd'
|
||||||
else grp.territory = b > w ? 1 : -1;
|
else grp.territory = b > w ? 1 : -1;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -644,54 +678,9 @@ function emptyPointSetTerritory(emptyPoints) {
|
||||||
|
|
||||||
function endGame() {
|
function endGame() {
|
||||||
if (!gameState.winner) endGameSetTerritory()
|
if (!gameState.winner) endGameSetTerritory()
|
||||||
|
renderGame();
|
||||||
|
|
||||||
// join all remaining groups
|
|
||||||
// check remaining groups life
|
|
||||||
|
|
||||||
// search empty spaces on board for deadShapes
|
|
||||||
// compare spaces to rotations of deadShapes[...]
|
|
||||||
// 'd' if empty spaces
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// stringify according to .sgf format
|
|
||||||
// log as text
|
|
||||||
render();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// game-end
|
|
||||||
// render territory counts
|
|
||||||
// checkLegalMove
|
|
||||||
// clear overlay
|
|
||||||
// if move is not '0', move is illegal (opposing player or 'k' for ko)
|
|
||||||
// iterate through neighboring points in clockwise order
|
|
||||||
// if anyone is '0' move is legal - call render preview
|
|
||||||
// if neighboring point is opposing player
|
|
||||||
// cycle through opposing player group marking points as overlay: 'chk' when checked and
|
|
||||||
// overlay: 'hold' if they are neighboring points of opposing player color
|
|
||||||
// if any neighboring point is '0' terminate cycle and move to next neighboring point of original move
|
|
||||||
// if there are unchecked points of 'hold' return
|
|
||||||
// if no boardState: 0 points, move is legal overlay: 'l'
|
|
||||||
// set all 'chk' to 'x' to represent stones that will be captured upon move
|
|
||||||
// if neighboring point is player's
|
|
||||||
// cycle through player group marking points as overlay: 'chk' || 'hold'
|
|
||||||
// if any neighboring point is '0' ternminate cycle and mark point as 'l'
|
|
||||||
// set move
|
|
||||||
// if checkLegalMove has returned '0' i2llegal move message?
|
|
||||||
// if move state is 'l'
|
|
||||||
// push boardState to lastState
|
|
||||||
// push 'l' move to boardState
|
|
||||||
// resolve captures
|
|
||||||
// for all 'x' in overlay
|
|
||||||
// count number and add to playerCaptures
|
|
||||||
// set boardState to '0'
|
|
||||||
// pass--
|
|
||||||
// push move to game record
|
|
||||||
// game record: [ 0: handicapStones Obj, 1: 1stMove([moveState[],moveState[][])]
|
// game record: [ 0: handicapStones Obj, 1: 1stMove([moveState[],moveState[][])]
|
||||||
// pass() pass++ and player turn to other player
|
// pass() pass++ and player turn to other player
|
||||||
// gameEnd when pass = 2
|
// gameEnd when pass = 2
|
||||||
|
|
Loading…
Reference in a new issue