Created
April 16, 2014 08:49
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
package com.daggerfrog.luxoft | |
object PiecesSet { | |
val pieces = Set(Empty, Threated, King, Queen, Rook, Bishop, Knight) | |
val fromByte = pieces.map(el ⇒ el.byteRepr → el).toMap | |
val fromChar = pieces.map(el ⇒ el.charRepr → el).toMap | |
def char2Byte(el: Char) = fromChar(el).byteRepr | |
def byte2Char(el: Byte) = fromByte(el).charRepr | |
} | |
trait Cell { | |
def charRepr: Char | |
def byteRepr: Byte | |
} | |
trait Piece extends Cell { | |
protected def threatedNotSafe(x: Int, y: Int, height: Int, width: Int): Iterable[(Int, Int)] | |
def place(x: Int, y: Int, height: Int, width: Int) = | |
crop(height, width, threatedNotSafe(x, y, height, width)) | |
private def crop(height: Int, width: Int, data: Iterable[(Int, Int)]) = | |
data.filter { case(nX, nY) ⇒ nX >= 0 && nX < width && nY >= 0 && nY < height } | |
} | |
object Empty extends Cell { | |
val charRepr = '#' | |
def byteRepr = 0 | |
} | |
object Threated extends Cell { | |
val charRepr = '*' | |
def byteRepr = 1 | |
} | |
object King extends Piece { | |
val charRepr = 'K' | |
def byteRepr = 2 | |
override def threatedNotSafe(x: Int, y: Int, height: Int, width: Int) = | |
for (xShift ← Range(-1, 2); yShift ← Range(-1, 2)) | |
yield (xShift + x, yShift + y) | |
} | |
object Queen extends Piece { | |
val charRepr = 'Q' | |
def byteRepr = 3 | |
override def threatedNotSafe(x: Int, y: Int, height: Int, width: Int) = | |
Bishop.threatedNotSafe(x, y, height, width) ++ Rook.threatedNotSafe(x, y, height, width) | |
} | |
object Rook extends Piece { | |
val charRepr = 'R' | |
def byteRepr = 4 | |
override def threatedNotSafe(x: Int, y: Int, height: Int, width: Int) = | |
Range(0, height).map(i ⇒ (x, i)) ++ Range(0, width).map(i ⇒ (i, y)) | |
} | |
object Bishop extends Piece { | |
val charRepr = 'B' | |
def byteRepr = 5 | |
override def threatedNotSafe(x: Int, y: Int, height: Int, width: Int) = | |
Range(1, y + 1).flatMap(i => List((x - i, y - i), (x + i, y - i))) ++ | |
Range(1, height - y).flatMap(i ⇒ List((x - i, y + i), (x + i, y + i))) | |
} | |
object Knight extends Piece { | |
val charRepr = 'k' | |
def byteRepr = 6 | |
override def threatedNotSafe(x: Int, y: Int, height: Int, width: Int) = | |
List((2, 1), (2, -1), (-2, 1), (-2, -1), (1, 2), (1, -2), (-1, -2), (-1, 2)).map{ | |
case(xShift, yShift) ⇒ (xShift + x, yShift + y) | |
} | |
} | |
object ChessBoard { | |
def create(height: Int, width: Int) = { | |
ChessBoard(height, width, new Array[Byte](height * width)) | |
} | |
} | |
case class ChessBoard private (height: Int, width: Int, board: Array[Byte]) { | |
require(height * width == board.size) | |
override def toString = { | |
board.map(PiecesSet.byte2Char).mkString.grouped(width).mkString("\n") | |
} | |
private def flatDim(point: (Int, Int)): Int = flatDim(point._1, point._2) | |
private def flatDim(x: Int, y: Int): Int = x + y * width | |
def placePieces(pieces: Iterable[Piece]): Int = { | |
if (pieces.isEmpty) { | |
1 | |
} | |
else | |
Range(0, width).foldLeft(0){ | |
case(acc, x) ⇒ acc + Range(0, height).foldLeft(0) {case(acc, y) ⇒ | |
acc + placePiece(x, y, pieces.head).map(_.placePieces(pieces.tail)).getOrElse(0) | |
} | |
} | |
} | |
def placePiece(x: Int, y: Int, piece: Piece): Option[ChessBoard] = { | |
require(x < width) | |
require(y < height) | |
val index = flatDim((x, y)) | |
if (PiecesSet.fromByte(board(index)) != Empty) | |
None | |
else { | |
val newThreated = piece.place(x, y, height, width) | |
val valid = newThreated.forall { | |
point ⇒ | |
val cell = PiecesSet.fromByte(board(flatDim(point))) | |
cell == Empty || cell == Threated | |
} | |
if (!valid) | |
None | |
else { | |
val newBoard = board.clone() | |
newThreated.foreach(point ⇒ newBoard(flatDim(point)) = Threated.byteRepr) | |
newBoard(flatDim(x, y)) = piece.byteRepr | |
Some(ChessBoard(height, width, newBoard)) | |
} | |
} | |
} | |
} | |
object ChessBoardApp extends App { | |
val board = ChessBoard.create(3, 3) | |
val pieces = List(Rook, King, King) | |
println(board.placePieces(pieces)) | |
// println(board) | |
// | |
// val newBoard = board.placePiece(3, 2, Knight).get | |
// | |
//// println | |
// println(newBoard) | |
//// println | |
// println(newBoard.placePiece(9, 0, Bishop).get) | |
// println(newBoard.placePiece(1, 1, Bishop).get) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment