Don't castle if the enemy threatens part of the king trip

pull/1/merge
Thibault Duplessis 2012-02-26 20:23:14 +01:00
parent 90356308d5
commit 90946a29b7
4 changed files with 51 additions and 22 deletions

View File

@ -3,6 +3,7 @@ package model
import Pos.makePos
import scalaz.Success
import scala.math.{ min, max }
case class Actor(piece: Piece, pos: Pos, board: Board) {
@ -62,13 +63,15 @@ case class Actor(piece: Piece, pos: Pos, board: Board) {
def is(c: Color) = c == piece.color
def is(p: Piece) = p == piece
def threatens(to: Pos): Boolean = enemies(to) && ((piece.role match {
def threatens(to: Pos): Boolean = enemies(to) && threats(to)
lazy val threats: Set[Pos] = piece.role match {
case Pawn pawnDir(pos) map { next
List(next.left, next.right) flatten
} getOrElse Nil
case role if role.longRange longRangePoss(role.dirs)
case role (role.dirs map { d d(pos) }).flatten
}) contains to)
Set(next.left, next.right) flatten
} getOrElse Set.empty
case role if role.longRange longRangePoss(role.dirs) toSet
case role (role.dirs map { d d(pos) }).flatten toSet
}
private def kingSafety(implications: Implications): Implications =
implications filterNot {
@ -78,20 +81,27 @@ case class Actor(piece: Piece, pos: Pos, board: Board) {
}
private def castle: Implications = {
def on(side: Side): Option[Implication] = for {
kingPos board kingPosOf color
if history canCastle color on side
tripToRook = side.tripToRook(kingPos, board)
rookPos tripToRook.lastOption
if board(rookPos) == Some(color.rook)
newKingPos makePos(side.castledKingX, kingPos.y)
newRookPos makePos(side.castledRookX, rookPos.y)
b1 board take rookPos
b2 b1.move(kingPos, newKingPos)
b3 b2.place(color.rook, newRookPos)
} yield (newKingPos, b3 updateHistory (_ withoutCastles color))
List(on(KingSide), on(QueenSide)).flatten toMap
if (history.canCastle(color).any) {
val enemyThreats = board threatsOf !color
def on(side: Side): Option[Implication] = for {
kingPos board kingPosOf color
if history canCastle color on side
tripToRook = side.tripToRook(kingPos, board)
rookPos tripToRook.lastOption
if board(rookPos) == Some(color.rook)
newKingPos makePos(side.castledKingX, kingPos.y)
securedPoss = kingPos <-> newKingPos
if (enemyThreats & securedPoss.toSet).isEmpty
newRookPos makePos(side.castledRookX, rookPos.y)
b1 board take rookPos
b2 b1.move(kingPos, newKingPos)
b3 b2.place(color.rook, newRookPos)
} yield (newKingPos, b3 updateHistory (_ withoutCastles color))
List(on(KingSide), on(QueenSide)).flatten toMap
}
else Map.empty
}
private def preventsCastle(implications: Implications) =

View File

@ -19,9 +19,10 @@ case class Board(pieces: Map[Pos, Piece], history: History) {
case (pos, piece) (pos, Actor(piece, pos, this))
}
lazy val colorActors: Map[Color, Iterable[Actor]] = actors.values groupBy (_.color)
lazy val colorActors: Map[Color, List[Actor]] =
actors.values groupBy (_.color) mapValues (_.toList)
def actorsOf(c: Color) = colorActors get c getOrElse Nil
def actorsOf(c: Color): List[Actor] = colorActors get c getOrElse Nil
def actorAt(at: Pos): Valid[Actor] = actors get at toSuccess ("No piece on " + at)
@ -33,6 +34,10 @@ case class Board(pieces: Map[Pos, Piece], history: History) {
def movesFrom(from: Pos): Valid[Set[Pos]] = actorAt(from) map (_.moves)
def threatsOf(c: Color): Set[Pos] = actorsOf(c).toSet flatMap { actor: Actor =>
actor.threats
}
def seq(actions: Board Valid[Board]*): Valid[Board] =
actions.foldLeft(success(this): Valid[Board])(_ flatMap _)
@ -96,7 +101,7 @@ case class Board(pieces: Map[Pos, Piece], history: History) {
def withHistory(h: History): Board = copy(history = h)
def updateHistory(f: History => History) = copy(history = f(history))
def updateHistory(f: History History) = copy(history = f(history))
def as(c: Color) = Situation(this, c)

View File

@ -29,6 +29,9 @@ sealed case class Pos private (x: Int, y: Int) extends Ordered[Pos] {
def ?<(other: Pos) = x < other.x
def ?>(other: Pos) = x > other.x
def <->(other: Pos): Iterable[Pos] =
min(x, other.x) to max(x, other.x) map { makePos(_, y) } flatten
def xToString = Pos xToString x
def yToString = y.toString

View File

@ -195,6 +195,17 @@ PPPPPPPP
board place Black.rook at C3 flatMap (_ movesFrom E1) must bePoss(D1, D2, E2, F2)
}
}
"chess 960" in {
"far kingside" in {
val board: Board = """BK R"""
"rook threat" in {
board place Black.rook at F3 flatMap (_ movesFrom B1) must bePoss(A2, B2, C2, C1)
}
"enemy king threat" in {
board place Black.king at E2 flatMap (_ movesFrom B1) must bePoss(A2, B2, C2, C1)
}
}
}
}
"threat on rook does not prevent castling" in {
"king side" in {