25.8. Ruchy komputera
Mając sposób oceny sytuacji na planszy można zbudować algorytm wybierający następny ruch do wykonania przez komputer. Prostym algorytmem wybierającym ruch — niekorzystającym nawet z możliwości oceny sytacji — mogłoby być losowe wybranie dowolnego spośród poprawnych ruchów. Jednak program używający takiego algorytmu nie sprawiałby wrażenia, że potrafi grać w szachy, a co najwyżej, że znane mu są przepisy gry. W opisywanym programie jest zaimplementowany trochę bardziej inteligentny algorytm, choć i tak jest on dosyć prymitywny i łatwy do ogrania. Algorytm wyboru ruchu jest zaimplementowany w pliku ComputerPlayer.scala, który zawiera definicję klasy ComputerPlayer i jej obiektu towarzyszącego.
Plik ComputerPlayer.scala: package chess import language.implicitConversions object ComputerPlayer { def chooseRandomly(moves: Seq[Game]) = { import scala.util.Random if (moves.isEmpty) None else Some(moves(Random.nextInt(moves.size))) } implicit def Game2ComputerPlayer(game: Game): ComputerPlayer = new ComputerPlayer(game) } class ComputerPlayer(game: Game) { import ComputerPlayer._ import Rank._ def moves: Seq[Game] = { val moves = game.validGames.toList if (moves.isEmpty) Seq() else { val rankedMoves = moves.map(g => (g, g.rank(game.color))) val rankedMovesSorted = rankedMoves.sortBy(- _._2) val firstRank = rankedMovesSorted.head._2 rankedMovesSorted.takeWhile(_._2 == firstRank).map(_._1) } } def makeMove = chooseRandomly(moves) }
Do wyboru następnego ruchu służy metoda makeMove, wywołująca metodę chooseRandomly, podająca jej w argumencie rezultat wywołania metody moves. Metoda moves wybiera najlepsze spośród możliwych do wykonania ruchów, wykorzystując do oceny sytuacji metodę rank. Metoda chooseRandomly wybiera losowo jeden z nich.
scala> import chess._, ComputerPlayer._ import chess._ import ComputerPlayer._ scala> GameStart.moves.size res1: Int = 4
Poniższa sesja w konsoli języka Scala pokazuje początek przykładowej partii rozgrywanej przez komputer sam ze sobą.
scala> val g1 = GameStart.makeMove g1: Option[chess.Game] = Some(Last move: White d2 to d4 abcdefgh 8RNBQKBNR8 7PPPPPPPP7 6........6 5........5 4...p....4 3........3 2ppp.pppp2 1rnbqkbnr1 abcdefgh) scala> val g2 = g1.get.makeMove g2: Option[chess.Game] = Some(Last move: Black d7 to d5 abcdefgh 8RNBQKBNR8 7PPP.PPPP7 6........6 5...P....5 4...p....4 3........3 2ppp.pppp2 1rnbqkbnr1 abcdefgh) scala> val g3 = g2.get.makeMove g3: Option[chess.Game] = Some(Last move: White c1 to e3 abcdefgh 8RNBQKBNR8 7PPP.PPPP7 6........6 5...P....5 4...p....4 3....b...3 2ppp.pppp2 1rn.qkbnr1 abcdefgh) scala> g3.get.makeMove res2: Option[chess.Game] = Some(Last move: Black c8 to e6 abcdefgh 8RN.QKBNR8 7PPP.PPPP7 6....B...6 5...P....5 4...p....4 3....b...3 2ppp.pppp2 1rn.qkbnr1 abcdefgh)
Plik ComputerPlayer.scala:
package chess
import language.implicitConversions
object ComputerPlayer {
def chooseRandomly(moves: Seq[Game]) = {
import scala.util.Random
if (moves.isEmpty) None
else Some(moves(Random.nextInt(moves.size)))
}
implicit def Game2ComputerPlayer(game: Game): ComputerPlayer =
new ComputerPlayer(game)
}
class ComputerPlayer(game: Game) {
import ComputerPlayer._
import Rank._
def moves: Seq[Game] = {
val moves = game.validGames.toList
if (moves.isEmpty) Seq()
else {
val rankedMoves = moves.map(g => (g, g.rank(game.color)))
val rankedMovesSorted = rankedMoves.sortBy(- _._2)
val firstRank = rankedMovesSorted.head._2
rankedMovesSorted.takeWhile(_._2 == firstRank).map(_._1)
}
}
def makeMove = chooseRandomly(moves)
}
