Last active
January 4, 2017 03:11
-
-
Save bananaumai/ed5fd031d693d7ffe17396644887d83b to your computer and use it in GitHub Desktop.
オセロ用のモデル
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import IM from 'immutable' | |
import _ from 'lodash' | |
export const DISC = { | |
WHITE_SIDE : Symbol('WHITE_SIDE'), | |
BLACK_SIDE : Symbol('BLACK_SIDE') | |
} | |
export const SQUARE_STATUSES = { | |
WHITE: Symbol('WHITE'), | |
BLACK: Symbol('BLACK'), | |
VACANT: Symbol('VACANT') | |
} | |
export const DIRECTIONS = { | |
TOP : Symbol('TOP'), | |
RIGHT_TOP : Symbol('RIGHT_TOP'), | |
RIGHT : Symbol('RIGHT'), | |
RIGHT_BOTTOM : Symbol('RIGHT_BOTTOM'), | |
BOTTOM : Symbol('BOTTOM'), | |
LEFT_BOTTOM : Symbol('LEFT_BOTTOM'), | |
LEFT : Symbol('LEFT'), | |
LEFT_TOP : Symbol('LEFT_TOP') | |
} | |
export function createBord() { | |
return IM.fromJS(_.fromPairs( | |
_.flatMap( | |
_.range(1, 9), | |
(rowNum, idx, range) => _.map( | |
range, | |
colNum => { | |
const coord = getCoord(rowNum, colNum) | |
switch (coord) { | |
case '44': | |
case '55': | |
return [coord, SQUARE_STATUSES.WHITE] | |
case '45': | |
case '54': | |
return [coord, SQUARE_STATUSES.BLACK] | |
default: | |
return [coord, SQUARE_STATUSES.VACANT] | |
} | |
} | |
) | |
) | |
)) | |
} | |
export function getAvailableCoords(bord, disc) { | |
return Array.from(bord.filter((status, coord) => canPlaceDisc(bord, coord, disc)).keys()) | |
} | |
export function canPlaceDisc(bord, coord, disc) { | |
if (getStatus(bord, coord) !== SQUARE_STATUSES.VACANT) return false | |
return Object.values(DIRECTIONS).reduce((acc, direction) => { | |
return acc || canChangeNeighborStatus(bord, coord, direction, getPossibleStatus(disc)) | |
}, false) | |
} | |
export function canChangeNeighborStatus(bord, coord, direction, status) { | |
const neighborStatus = getNeighborStatus(bord, coord, direction) | |
switch(neighborStatus) { | |
case null: | |
case SQUARE_STATUSES.VACANT: | |
case status: | |
return false | |
default: | |
return statusExists(bord, getNeighborCoord(coord, direction), direction, status) | |
} | |
} | |
export function statusExists(bord, coord, direction, status) { | |
const neighborStatus = getNeighborStatus(bord, coord, direction) | |
switch(neighborStatus) { | |
case null: | |
case SQUARE_STATUSES.VACANT: | |
return false | |
case status: | |
return true | |
default: | |
return statusExists(bord, getNeighborCoord(coord, direction), direction, status) | |
} | |
} | |
export function changeNeighborStatus(bord, coord, direction, status) { | |
if (getStatus(bord, coord) !== status) throw new Error('Invalid status') | |
if (!canChangeNeighborStatus(bord, coord, direction, status)) return bord | |
const neighborCoord = getNeighborCoord(coord, direction) | |
const newBord = changeStatus(bord, neighborCoord, status) | |
return changeNeighborStatus(newBord, neighborCoord, direction, status) | |
} | |
export function placeDisc(bord, coord, disc) { | |
if (!canPlaceDisc(bord, coord, disc)) return bord | |
const status = getPossibleStatus(disc) | |
return Object.values(DIRECTIONS).reduce((prevBord, direction) => { | |
return changeNeighborStatus(prevBord, coord, direction, status) | |
}, changeStatus(bord, coord, status)) | |
} | |
function getNeighborStatus(bord, coord, direction) { | |
const neighborStatus = getNeighborCoord(coord, direction) | |
if (!neighborStatus) return null | |
return getStatus(bord, neighborStatus) | |
} | |
function getNeighborCoord(coord, direction) { | |
const rowNum = getRow(coord), | |
colNum = getCol(coord) | |
switch(direction) { | |
case DIRECTIONS.TOP: | |
return getCoord(rowNum - 1, colNum ) | |
case DIRECTIONS.RIGHT_TOP: | |
return getCoord(rowNum - 1, colNum + 1) | |
case DIRECTIONS.RIGHT: | |
return getCoord(rowNum , colNum + 1) | |
case DIRECTIONS.RIGHT_BOTTOM: | |
return getCoord(rowNum + 1, colNum + 1) | |
case DIRECTIONS.BOTTOM: | |
return getCoord(rowNum + 1, colNum ) | |
case DIRECTIONS.LEFT_BOTTOM: | |
return getCoord(rowNum + 1, colNum - 1) | |
case DIRECTIONS.LEFT: | |
return getCoord(rowNum , colNum - 1) | |
case DIRECTIONS.LEFT_TOP: | |
return getCoord(rowNum - 1, colNum - 1) | |
default: | |
throw new Error() | |
} | |
} | |
function getCoord(row, col) { | |
return `${row}${col}` | |
} | |
function getRow(coord) { | |
return Number(coord[0]) | |
} | |
function getCol(coord) { | |
return Number(coord[1]) | |
} | |
function getRowCol(coord) { | |
return _.map(coord, c => Number(c)) | |
} | |
export function getStatus(bord, coord) { | |
const status = bord.get(coord) | |
if (!status) return null | |
return status | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import _ from 'lodash' | |
export const discs = { | |
WHITE_DISC: Symbol('WHITE_DISC'), | |
BLACK_DISC: Symbol('BLACK_DISC') | |
} | |
export class Square { | |
constructor(coord) { | |
this.coord = coord | |
this.disc = null | |
const nullSquare = new NullSquare() | |
this.neighborSquares = { | |
top: nullSquare, | |
rightTop: nullSquare, | |
right: nullSquare, | |
rightBottom: nullSquare, | |
bottom: nullSquare, | |
leftBottom: nullSquare, | |
left: nullSquare, | |
leftTop: nullSquare | |
} | |
} | |
setDisc(disc) { | |
this.disc = disc | |
Object.values(Object.keys(this.neighborSquares)).forEach((direction) => { | |
this.neighborSquares[direction].reverse(disc, direction) | |
}) | |
} | |
canSetDisc(disc) { | |
Object.keys(this.neighborSquares).reduce((acc, direction) => { | |
return acc || this.neighborSquares[direction].reversible(disc, direction) | |
}, false) | |
} | |
discExists(disc, direction) { | |
if (this.disc === null) return false | |
if (this.disc === disc) return true | |
return this.neighborSquares[direction].discExists(disc, direction) | |
} | |
reverse(prevDisc, direction) { | |
if (!this.reversible(prevDisc, direction)) return | |
console.log(this.coord, prevDisc, direction) | |
this.disc = prevDisc | |
this.neighborSquares[direction].reverse(prevDisc, direction) | |
} | |
reversible(prevDisc, direction) { | |
if (this.disc === null || this.disc === prevDisc) return false | |
return this.neighborSquares[direction].discExists(prevDisc, direction) | |
} | |
} | |
class NullSquare { | |
canSetDisc() { return false } | |
discExists() { return false } | |
reverse() {} | |
} | |
export class Bord { | |
constructor() { | |
this.squares = _.fromPairs( | |
_.flatMap( | |
_.range(1,9), | |
(rowNum, idx, range) => _.map( | |
range, | |
colNum => [this.getSquareKey(rowNum, colNum), new Square([rowNum, colNum])] | |
) | |
) | |
) | |
this.findSquare(4, 4).setDisc(discs.WHITE_DISC) | |
this.findSquare(4, 5).setDisc(discs.BLACK_DISC) | |
this.findSquare(5, 4).setDisc(discs.BLACK_DISC) | |
this.findSquare(5, 5).setDisc(discs.WHITE_DISC) | |
Object.values(this.squares).forEach((square) => { | |
const [rowNum, colNum] = square.coord | |
if (rowNum === 1 && colNum === 1) { | |
this.setNeighborSquare(square, 'right') | |
this.setNeighborSquare(square, 'rightBottom') | |
this.setNeighborSquare(square, 'bottom') | |
} else if (rowNum === 1 && colNum === 8) { | |
this.setNeighborSquare(square, 'bottom') | |
this.setNeighborSquare(square, 'leftBottom') | |
this.setNeighborSquare(square, 'left') | |
} else if (rowNum === 8 && colNum === 1) { | |
this.setNeighborSquare(square, 'top') | |
this.setNeighborSquare(square, 'rightTop') | |
this.setNeighborSquare(square, 'right') | |
} else if (rowNum === 8 && colNum === 8) { | |
this.setNeighborSquare(square, 'left') | |
this.setNeighborSquare(square, 'leftTop') | |
this.setNeighborSquare(square, 'top') | |
} else if (rowNum === 1) { | |
this.setNeighborSquare(square, 'right') | |
this.setNeighborSquare(square, 'rightBottom') | |
this.setNeighborSquare(square, 'bottom') | |
this.setNeighborSquare(square, 'leftBottom') | |
this.setNeighborSquare(square, 'left') | |
} else if (rowNum === 8) { | |
this.setNeighborSquare(square, 'left') | |
this.setNeighborSquare(square, 'leftTop') | |
this.setNeighborSquare(square, 'top') | |
this.setNeighborSquare(square, 'rightTop') | |
this.setNeighborSquare(square, 'right') | |
} else if (colNum === 1) { | |
this.setNeighborSquare(square, 'top') | |
this.setNeighborSquare(square, 'rightTop') | |
this.setNeighborSquare(square, 'right') | |
this.setNeighborSquare(square, 'rightBottom') | |
this.setNeighborSquare(square, 'bottom') | |
} else if (colNum === 8) { | |
this.setNeighborSquare(square, 'bottom') | |
this.setNeighborSquare(square, 'leftBottom') | |
this.setNeighborSquare(square, 'left') | |
this.setNeighborSquare(square, 'leftTop') | |
this.setNeighborSquare(square, 'top') | |
} else { | |
this.setNeighborSquare(square, 'top') | |
this.setNeighborSquare(square, 'rightTop') | |
this.setNeighborSquare(square, 'right') | |
this.setNeighborSquare(square, 'rightBottom') | |
this.setNeighborSquare(square, 'bottom') | |
this.setNeighborSquare(square, 'leftBottom') | |
this.setNeighborSquare(square, 'left') | |
this.setNeighborSquare(square, 'leftTop') | |
} | |
}) | |
} | |
getSquareKey(rowNum, colNum) { | |
return rowNum.toString().concat(colNum) | |
} | |
findSquare(rowNum, colNum) { | |
return this.squares[this.getSquareKey(rowNum, colNum)] | |
} | |
setNeighborSquare(square, direction) { | |
const [rowNum, colNum] = square.coord | |
let neighborSquare = null | |
switch (direction) { | |
case 'top': | |
neighborSquare = this.findSquare(rowNum-1, colNum) | |
break | |
case 'rightTop': | |
neighborSquare = this.findSquare(rowNum-1, colNum+1) | |
break | |
case 'right': | |
neighborSquare = this.findSquare(rowNum, colNum+1) | |
break | |
case 'rightBottom': | |
neighborSquare = this.findSquare(rowNum+1, colNum+1) | |
break | |
case 'bottom': | |
neighborSquare = this.findSquare(rowNum+1, colNum) | |
break | |
case 'leftBottom': | |
neighborSquare = this.findSquare(rowNum+1, colNum-1) | |
break | |
case 'left': | |
neighborSquare = this.findSquare(rowNum, colNum-1) | |
break | |
case 'leftTop': | |
neighborSquare = this.findSquare(rowNum-1, colNum-1) | |
break | |
} | |
if (neighborSquare) square.neighborSquares[direction] = neighborSquare | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment