25.7. Ocena sytuacji na planszy
Ponieważ opisywana aplikacja ma potrafić grać w szachy z człowiekiem, więc potrzebna jest implementacja algorytmu określającego jaki następny ruch ma zostać wykonany przez komputer. Z kolei taki algorytm porzebuje sposobu oceny różnych stanów gry. Algorytm oceniający jest zaimplementowany w pliku Rank.scala. Plik zawiera definicję klasy Rank i jej obiektu towarzyszącego.
Plik Rank.scala: package chess import language.implicitConversions object Rank { def figureRank(figure: Figure) = figure.figureType match { case Queen => 900 case Rook => 450 case Knight | Bishop => 300 case Pawn => 100 case _ => 0 } def fieldRank(field: Field) = { def colRowRank(cr: Int) = if (cr>=5) 9-cr else cr 2*colRowRank(field.col) * colRowRank(field.row) } implicit def Game2Rank(game: Game): Rank = new Rank(game)
} class Rank(game: Game) { import Rank._ import FigureMoves._ def figureDefendingOtherFiguresRank(field:Field, figure:Figure) = game.sameColorDestinations(figure.figureColor, figureMoves(figure,field,true)).size/2 def checkRank(color: Color) = if (game.color == color.other && game.isKingUnderCheck) 50 else 0 def colorRank(color: Color) = (for ((field, figure) <- game.board.iterator if figure.figureColor == color; r1 = figureRank(figure); r2 = fieldRank(field); r3 = game.figureDefendingOtherFiguresRank(field, figure)) yield r1 + r2 + r3).sum + game.checkRank(color) def rank(color: Color) = game.colorRank(color)-game.colorRank(color.other) }
Metoda rank klasy Rank zwraca liczbę całkowitą reprezentującą
ocenę stanu gry z punktu widzenia określonego gracza. Im większa jest
ta liczba, tym lepsza jest ocena danej sytuacji na planszy. Klasa
Rank ma parametr game typu Game, który reprezentuje oceniany
stan gry. Dzięki niejawnej konwersji obiektów typu Game na obiekty
typu Rank, zdefiniowanej w wierszu
, możliwe jest wywoływanie
metody rank na obiektach typu Game.
scala> import chess._, Rank._ import chess._ import Rank._ scala> GameStart.rank(White) res0: Int = 0
Metoda rank zwraca różnicę punktów otrzymanych dzięki wywołaniom metody colorRank, oceniającej sytuację na planszy z punktu widzenia konkretnego gracza. Metoda działa w ten sposób, że przypisuje punktację każdej z figur danego koloru i dodaje te punkty, a do tak uzyskanej sumy dodaje jeszcze wynik metody checkRank. Punkty przyznawane są każdej z figur według trzech kryteriów, ocenianych przez metody figureRank, fieldRank oraz figureDefendingOtherFiguresRank. Metoda figureRank przypisuje każdej z figur określoną punktację, zależną od rodzaju figury. Najlepiej oceniany jest hetman, później wieża, następnie równo skoczek i goniec, a najmniej pion. Król nie otrzymuje punktów, gdyż i tak każda ze stron ma przez cały czas trwania partii po jednym i tylko jednym królu.
scala> figureRank(Figure(Queen,White)) res1: Int = 900 scala> figureRank(Figure(Knight,Black)) res2: Int = 300
Metoda fieldRank przypisuje punktację w zależności od pozycji figury na planszy, przy czym lepiej są oceniane pola w centrum planszy, a gorzej pola dalsze od centrum.
scala> fieldRank(Field(1,1)) res3: Int = 2 scala> fieldRank(Field(2,5)) res4: Int = 16
scala> fieldRank(Field(4,4)) res5: Int = 32
Metoda figureDefendingOtherFiguresRank przypisuje punktację zależną od tego, ilu figur tego samego koloru broni dana figura. Im więcej figur jest bronionych, tym lepiej.
scala> GameStart.figureDefendingOtherFiguresRank(Field(4,1),Figure(Queen,White)) res6: Int = 2 scala> GameStart.figureDefendingOtherFiguresRank(Field(4,7),Figure(Pawn,Black)) res7: Int = 0
Metoda checkRank przypisuje dodatkowe punkty, jeśli król przeciwnika jest szachowany.
scala> GameStart.checkRank(White)
res8: Int = 0
scala> val g = GameStart.move(Field(7,2),Field(7,4),None).get.
| move(Field(5,7),Field(5,6),None).get.
| move(Field(6,2),Field(6,4),None).get.
| move(Field(4,8),Field(8,4),None).get
g: chess.OngoingGame =
Last move: Black d8 to h4
abcdefgh
8RNB.KBNR8
7PPPP.PPP7
6....P...6
5........5
4.....ppQ4
3........3
2ppppp..p2
1rnbqkbnr1
abcdefgh
scala> g.checkRank(Black)
res9: Int = 50
Plik Rank.scala:
package chess
import language.implicitConversions
object Rank {
def figureRank(figure: Figure) = figure.figureType match {
case Queen => 900
case Rook => 450
case Knight | Bishop => 300
case Pawn => 100
case _ => 0
}
def fieldRank(field: Field) = {
def colRowRank(cr: Int) = if (cr>=5) 9-cr else cr
2*colRowRank(field.col) * colRowRank(field.row)
}
implicit def Game2Rank(game: Game): Rank = new Rank(game) 