Skip to content

Instantly share code, notes, and snippets.

@Kuniwak
Created February 26, 2014 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kuniwak/9237040 to your computer and use it in GitHub Desktop.
Save Kuniwak/9237040 to your computer and use it in GitHub Desktop.
@masuipeoさんの問題 「今週のお題:飛車と角の利きを考えて!」の回答。
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