Created
February 26, 2014 19:48
-
-
Save Kuniwak/9237040 to your computer and use it in GitHub Desktop.
@masuipeoさんの問題 「今週のお題:飛車と角の利きを考えて!」の回答。
This file contains 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
var util = {}; | |
util.array = {}; | |
util.array.remove = function(arr, obj) { | |
var i = arr.indexOf(obj); | |
var rv; | |
if ((rv = i >= 0)) { | |
util.array.removeAt(arr, i); | |
} | |
return rv; | |
}; | |
util.array.removeAt = function(arr, i) { | |
return arr.splice(i, 1).length == 1; | |
}; | |
util.array.contains = function(arr, obj) { | |
return arr.indexOf(obj) >= 0; | |
}; | |
var inherits = function(Child, Parent) { | |
var Ctor = function() {}; | |
Ctor.prototype = Parent.prototype; | |
Child.prototype = new Ctor(); | |
}; | |
var abstractMethod = function() { | |
throw Error('Implement me.'); | |
}; | |
var Rectangle = function(top, right, bottom, left) { | |
this.top = top; | |
this.right = right; | |
this.bottom = bottom; | |
this.left = left; | |
}; | |
Rectangle.prototype.contains = function(coord) { | |
return this.left <= coord.x && this.right >= coord.x && | |
this.top <= coord.y && this.bottom >= coord.y; | |
}; | |
var Coord = function(opt_x, opt_y) { | |
this.set(opt_x || 0, opt_y || 0); | |
}; | |
Coord.fromIndex = function(idx, width) { | |
var x = idx % width; | |
var y = (idx - x) / width; | |
return new Coord(x, y); | |
}; | |
Coord.prototype.set = function(x, y) { | |
this.x = x; | |
this.y = y; | |
}; | |
Coord.prototype.add = function(coord) { | |
this.x += coord.x; | |
this.y += coord.y; | |
return this; | |
}; | |
Coord.prototype.equals = function(coord) { | |
return this.x === coord.x && this.y === coord.y; | |
}; | |
Coord.prototype.toString = function() { | |
return '(' + this.x + ', ' + this.y + ')'; | |
}; | |
Coord.prototype.toIndex = function(width) { | |
return this.y * width + this.x; | |
}; | |
Coord.prototype.clone = function() { | |
return new this.constructor(this.x, this.y); | |
}; | |
var AbstractBoard = function(opt_width, opt_height) { | |
this.width = opt_width > 0 ? opt_width : AbstractBoard.WIDTH; | |
this.height = opt_height > 0 ? opt_height : AbstractBoard.HEIGHT; | |
this.board = []; | |
for (var y = 0; y < this.height; y++) { | |
this.board[y] = []; | |
for (var x = 0; x < this.width; x++) { | |
this.board[y][x] = this.createSquare(new Coord(x, y)); | |
} | |
} | |
}; | |
AbstractBoard.WIDTH = 9; | |
AbstractBoard.HEIGHT = 9; | |
AbstractBoard.AbstractSquare = function(coord) { | |
this.coord = coord; | |
}; | |
AbstractBoard.prototype.contains = function(coord) { | |
var rect = new Rectangle(0, this.width - 1, this.height - 1, 0); | |
return rect.contains(coord); | |
}; | |
AbstractBoard.prototype.createSquare = abstractMethod; | |
AbstractBoard.prototype.getSquareByCoord = function(coord) { | |
return this.board[coord.y] ? this.board[coord.y][coord.x] : undefined; | |
}; | |
AbstractBoard.prototype.forEachSquare = function(func, opt_this) { | |
var coord; | |
for (var y = 0; y < this.height; y++) { | |
for (var x = 0; x < this.width; x++) { | |
coord = new Coord(x, y); | |
func.call(opt_this, this.getSquareByCoord(coord), coord); | |
} | |
} | |
}; | |
AbstractBoard.prototype.map = function(func, opt_this) { | |
var result = [], idx = 0; | |
this.forEach(function(square, coord) { | |
result[idx++] = func.call(opt_this, square, coord); | |
}); | |
return result; | |
}; | |
AbstractBoard.prototype.toString = function() { | |
var verticalSeparator = new Array(this.width + 1).join('+-') + '+'; | |
return verticalSeparator + this.board.map(function(horizontal) { | |
return '\n|' + horizontal.join('|') + '|'; | |
}).join('\n' + verticalSeparator) + '\n' + verticalSeparator; | |
}; | |
var Board = function(opt_width, opt_height) { | |
AbstractBoard.call(this, opt_width, opt_height); | |
this.pieces = []; | |
}; | |
inherits(Board, AbstractBoard); | |
Board.prototype.createSquare = function(coord) { | |
return new Board.Square(coord); | |
}; | |
Board.prototype.hasPiece = function(piece) { | |
return util.array.contains(this.pieces, piece); | |
}; | |
Board.prototype.getPiece = function(coord) { | |
var square = this.getSquareByCoord(coord); | |
return square ? square.piece : null; | |
}; | |
Board.prototype.setPiece = function(coord, piece) { | |
var square = this.getSquareByCoord(coord); | |
if (square) { | |
this.removePieceAt(coord); | |
piece.board = board; | |
piece.coord = coord; | |
square.piece = piece; | |
this.pieces.push(piece); | |
return true; | |
} | |
return false; | |
}; | |
Board.prototype.removePiece = function(piece) { | |
if (piece.board !== this || !piece.isOnBoard()) { | |
return null; | |
} | |
return this.removePieceAt(piece.coord); | |
}; | |
Board.prototype.removePieceAt = function(coord) { | |
var piece = this.getPiece(coord); | |
if (!piece) { | |
return null; | |
} | |
var square = this.getSquareByCoord(coord); | |
square.piece = null; | |
piece.coord = null; | |
util.array.remove(this.pieces, piece); | |
return piece; | |
}; | |
Board.Square = function(coord, opt_piece) { | |
AbstractBoard.AbstractSquare.call(this, coord); | |
this.piece = opt_piece || null; | |
}; | |
inherits(Board.Square, AbstractBoard.AbstractSquare); | |
Board.Square.prototype.toString = function() { | |
return this.piece === null ? ' ' : this.piece.toString(); | |
}; | |
var MarkerBoard = function(opt_width, opt_height) { | |
AbstractBoard.call(this, opt_width, opt_height); | |
}; | |
inherits(MarkerBoard, AbstractBoard); | |
MarkerBoard.fromBoard = function(board) { | |
return new MarkerBoard(board.width, board.height); | |
}; | |
MarkerBoard.prototype.createSquare = function(coord) { | |
return new MarkerBoard.Marker(coord); | |
}; | |
MarkerBoard.prototype.countMarks = function() { | |
var count = 0; | |
this.forEachSquare(function(marker) { | |
if (marker.mark) { | |
count++; | |
} | |
}); | |
return count; | |
}; | |
MarkerBoard.prototype.isMarked = function(coord) { | |
var marker = this.getSquareByCoord(coord); | |
if (marker) { | |
return marker.mark; | |
} | |
return false; | |
}; | |
MarkerBoard.prototype.mark = function(coord, mark) { | |
var marker = this.getSquareByCoord(coord); | |
if (marker) { | |
marker.mark = mark; | |
} | |
return this; | |
}; | |
MarkerBoard.Marker = function(coord, opt_mark) { | |
AbstractBoard.AbstractSquare.call(this, coord); | |
this.mark = Boolean(opt_mark); | |
}; | |
inherits(MarkerBoard.Marker, AbstractBoard.AbstractSquare); | |
MarkerBoard.Marker.prototype.toString = function() { | |
return this.mark ? 'X' : ' '; | |
}; | |
var Piece = function(opt_board, opt_coord) { | |
this.board = opt_board || null; | |
this.coord = opt_coord || null; | |
}; | |
Piece.prototype.assertOnBoard = function() { | |
if (!this.isOnBoard()) { | |
throw Error('This piece is not on board.'); | |
} | |
}; | |
Piece.prototype.isOnBoard = function() { | |
return this.board && this.coord; | |
}; | |
Piece.prototype.moveTo = function(coord) { | |
this.assertOnBoard(); | |
if (this.markMovableArea().isMark(coord)) { | |
this.board.setPiece(coord, this); | |
} | |
}; | |
Piece.prototype.markMovableArea = function(opt_markerBoard) {}; | |
var Rook = function(opt_board, opt_coord) { | |
Piece.call(this, opt_board, opt_coord); | |
}; | |
inherits(Rook, Piece); | |
Rook.prototype.markMovableArea = function(opt_markerBoard) { | |
var markerBoard = opt_markerBoard || MarkerBoard.fromBoard(this.board); | |
var deltas = [ | |
new Coord(1, 0), | |
new Coord(-1, 0), | |
new Coord(0, 1), | |
new Coord(0, -1) | |
]; | |
deltas.forEach(function(delta) { | |
var coord = this.coord.clone(); | |
while (markerBoard.contains(coord)) { | |
coord.add(delta); | |
if (this.board.getPiece(coord)) { | |
// Piece cannot move to a square that already has any piece. | |
break; | |
} | |
markerBoard.mark(coord, true); | |
} | |
}, this); | |
return markerBoard; | |
}; | |
Rook.prototype.toString = function() { | |
return 'R'; | |
}; | |
var Bishop = function(opt_board, opt_coord) { | |
Piece.call(this, opt_board, opt_coord); | |
}; | |
inherits(Bishop, Piece); | |
Bishop.prototype.markMovableArea = function(opt_markerBoard) { | |
var markerBoard = opt_markerBoard || MarkerBoard.fromBoard(this.board); | |
var deltas = [ | |
new Coord(1, 1), | |
new Coord(1, -1), | |
new Coord(-1, 1), | |
new Coord(-1, -1) | |
]; | |
deltas.forEach(function(delta) { | |
var coord = this.coord.clone(); | |
while (markerBoard.contains(coord)) { | |
coord.add(delta); | |
if (this.board.getPiece(coord)) { | |
// Piece cannot move to a square that already has any piece. | |
break; | |
} | |
markerBoard.mark(coord, true); | |
} | |
}, this); | |
return markerBoard; | |
}; | |
Bishop.prototype.toString = function() { | |
return 'B'; | |
}; | |
var BoardPrinter = function(opt_width, opt_height) { | |
AbstractBoard.call(this, opt_width, opt_height); | |
}; | |
inherits(BoardPrinter, AbstractBoard); | |
BoardPrinter.prototype.print = function(var_args) { | |
var boards = Array.prototype.slice.call(arguments, 0); | |
var coord; | |
var str; | |
for (var idx = this.width * this.height - 1; idx >= 0; idx--) { | |
coord = Coord.fromIndex(idx, board.width); | |
str = ' '; | |
boards.forEach(function(board) { | |
var square = board.getSquareByCoord(coord); | |
if (square.toString() !== ' ') { | |
str = square.toString(); | |
} | |
}); | |
var squarePrinter = this.getSquareByCoord(coord); | |
squarePrinter.setChar(str); | |
} | |
return this.toString(); | |
}; | |
BoardPrinter.prototype.createSquare = function(coord) { | |
return new BoardPrinter.SquarePrinter(coord); | |
}; | |
BoardPrinter.SquarePrinter = function(coord) { | |
AbstractBoard.AbstractSquare.call(this, coord); | |
this.str = ' '; | |
}; | |
inherits(BoardPrinter.SquarePrinter, AbstractBoard.AbstractSquare); | |
BoardPrinter.SquarePrinter.prototype.setChar = function(str) { | |
this.str = str; | |
}; | |
BoardPrinter.SquarePrinter.prototype.toString = function() { | |
return this.str; | |
}; | |
var forEachPosition = function(board, pieces, func, opt_this) { | |
return forEachPositionInternal(board, pieces, 0, func, opt_this); | |
}; | |
var forEachPositionInternal = function(board, pieces, depth, func, opt_this) { | |
var piece = pieces[depth]; | |
var coord; | |
for (var idx = board.width * board.height - 1; idx >= 0; idx--) { | |
coord = Coord.fromIndex(idx, board.width); | |
// Remove deeper pieces because deeper pieces may block to place the current | |
// piece. | |
pieces.slice(depth).forEach(function(piece) { | |
board.removePiece(piece); | |
}); | |
// Piece cannot move to a square that already has any piece. | |
if (board.getPiece(coord)) { | |
continue; | |
} | |
board.setPiece(coord, piece); | |
if (pieces.length > depth + 1) { | |
forEachPositionInternal(board, pieces, depth + 1, func, opt_this); | |
} | |
else { | |
func.call(opt_this, board); | |
} | |
} | |
}; | |
var coordPrint = function(coord) { | |
return '(' + (coord.x) + ',' + (coord.y) + ')'; | |
}; | |
var board = new Board(); | |
var pieces = [new Rook(), new Bishop()]; | |
var answer = 0; | |
var outcome = 0; | |
forEachPosition(board, pieces, function(board) { | |
var markerBoard = MarkerBoard.fromBoard(board); | |
board.pieces.forEach(function(piece) { | |
piece.markMovableArea(markerBoard); | |
}); | |
answer += markerBoard.countMarks(); | |
console.log(coordPrint(pieces[0].coord) + ',' + coordPrint(pieces[1].coord) + ': ' + markerBoard.countMarks()); | |
console.log(new BoardPrinter().print(markerBoard, board), 'ID: ' + (++outcome), 'Marked: ' + markerBoard.countMarks()); | |
console.log('\n' + Array(21).join('-') + '\n'); | |
}); | |
console.log('RESULT: ' + answer); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment