UNPKG

@reis/seki

Version:

Seki – A modern javascript based Go board renderer and player, that is simple to use, extensible, compact and intuitive.

259 lines (214 loc) 6.2 kB
import {stoneColors} from '../constants/stone.js' import {scoreStates} from '../constants/score.js' /** * Stores the state of the game score */ export default class GameScoreState { /** * Constructor */ constructor(game) { //Set game and initialise this.game = game this.states = game.position.stones.clone() } /** * Mark stones as dead */ markDead(x, y) { //Get color of original position const {game} = this const color = game.position.stones.get(x, y) //Was white, mark it and any territory it's in as black's if (color === stoneColors.WHITE) { this.territorySet( x, y, scoreStates.BLACK_CANDIDATE, scoreStates.BLACK_STONE ) } //Was black, mark it and any territory it's in as white's else if (color === stoneColors.BLACK) { this.territorySet( x, y, scoreStates.WHITE_CANDIDATE, scoreStates.WHITE_STONE ) } } /** * Toggle stones dead or alive */ toggle(x, y) { //Get data const {states, game} = this //Get color of original position and scoring state const color = game.position.stones.get(x, y) const state = states.get(x, y) //White stone if (color === stoneColors.WHITE) { //Was white, mark it and any territory it's in as black's if (state === scoreStates.WHITE_STONE) { this.territorySet( x, y, scoreStates.BLACK_CANDIDATE, scoreStates.BLACK_STONE ) } //Was marked as not white, reset the territory else { this.territoryReset(x, y) } } //Black stone else if (color === stoneColors.BLACK) { //Was black, mark it and any territory it's in as white's if (state === scoreStates.BLACK_STONE) { this.territorySet( x, y, scoreStates.WHITE_CANDIDATE, scoreStates.WHITE_STONE ) } //Was marked as not black, reset the territory else { this.territoryReset(x, y) } } } /** * Convert stone color to score state color */ getCandidateState(color) { switch (color) { case stoneColors.BLACK: return scoreStates.BLACK_CANDIDATE case stoneColors.WHITE: return scoreStates.WHITE_CANDIDATE } } /************************************************************************** * Helpers ***/ /** * Helper to set territory */ territorySet(x, y, candidateState, boundaryState) { //Not on grid const {states, game} = this if (!states.isOnGrid(x, y)) { return } //Get state at given position and original color const state = states.get(x, y) const color = game.position.stones.get(x, y) //Position is already in the candidate or boundary state if (state === candidateState || state === boundaryState) { return } //Don't turn stones which are already in the candidate state into candidates //Instead, reset their state to what they were if (this.getCandidateState(color) === candidateState) { states.set(x, y, color) } //Otherwise, mark as candidate else { states.set(x, y, candidateState) } //Set adjacent squares this.territorySet(x - 1, y, candidateState, boundaryState) this.territorySet(x, y - 1, candidateState, boundaryState) this.territorySet(x + 1, y, candidateState, boundaryState) this.territorySet(x, y + 1, candidateState, boundaryState) } /** * Helper to reset territory */ territoryReset(x, y) { //Not on grid const {states, game} = this if (!states.isOnGrid(x, y)) { return } //Check if already this color const color = game.position.stones.get(x, y) if (states.get(x, y) === color) { return } //Reset the color states.set(x, y, color) //Set adjacent squares this.territoryReset(x - 1, y) this.territoryReset(x, y - 1) this.territoryReset(x + 1, y) this.territoryReset(x, y + 1) } /** * Helper to determine the states grid */ determineStatesGrid() { //Get data const {states} = this //Initialize vars let change = true let curState, newState, adjacent, b, w, a, x, y //Loop while there is change while (change) { //Set to false change = false //Go through the whole position for (x = 0; x < states.width; x++) { for (y = 0; y < states.height; y++) { //Get current state at position curState = states.get(x, y) //Unknown or candiates? if ( !curState || curState === scoreStates.BLACK_CANDIDATE || curState === scoreStates.WHITE_CANDIDATE ) { //Get state in adjacent positions adjacent = [ states.get(x - 1, y), states.get(x, y - 1), states.get(x + 1, y), states.get(x, y + 1), ] //Reset b = w = false //Loop adjacent squares for (a = 0; a < 4; a++) { if ( adjacent[a] === scoreStates.BLACK_STONE || adjacent[a] === scoreStates.BLACK_CANDIDATE ) { b = true } else if ( adjacent[a] === scoreStates.WHITE_STONE || adjacent[a] === scoreStates.WHITE_CANDIDATE ) { w = true } else if (adjacent[a] === scoreStates.NEUTRAL) { b = w = true } } //Determine new state if (b && w) { newState = scoreStates.NEUTRAL } else if (b) { newState = scoreStates.BLACK_CANDIDATE } else if (w) { newState = scoreStates.WHITE_CANDIDATE } else { newState = false } //Change? if (newState !== false && newState !== curState) { change = true states.set(x, y, newState) } } } } } //Return the states grid return states } }