summaryrefslogtreecommitdiff
path: root/src/main/scala/me/robbyzambito/othello/game/Game.scala
blob: 8072bf117d0ab291368d43aea52004871ab72467 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package me.robbyzambito.othello.game

import scala.io.StdIn
import scala.util.Try

/**
 * Represents the state of the game.
 * Reports the winner of the game when that state is reached.
 *
 * Written by Robby Zambito
 * Written on 11/20/2019
 * Targeting Scala 2.13.1
 */
case class Game(board: Board,
                players: List[Player],
                turnCount: Int = 0) {

  val currentPlayer: Player = players(turnCount % players.length)
  val currentOpponent: Player = players(turnCount % players.length)

  /**
   * Save the game state to a file to be loaded at a later date.
   *
   * @return true if the game was successfully saved, otherwise false.
   */
  def save(): Boolean = ???

  /**
   * The winner of the game. Ties are not yet handled
   *
   * [[None]] if there has not been a winner yet. Otherwise return the [[Player]] which has won.
   */
  lazy val winner: Option[Player] = {
    if (currentPlayer.canMove(board) || (!currentPlayer.canMove(board) && currentOpponent.canMove(board)))
      None
    else { // No one can move
      val whiteCount = board.positions.flatten.count(_ == Position.WHITE)
      val blackCount = board.positions.flatten.count(_ == Position.BLACK)

      if (whiteCount > blackCount)
        players.find(p => p.color == Position.WHITE)
      else if (whiteCount < blackCount)
        players.find(p => p.color == Position.BLACK)
      else None
      // throw new Error("Game tied")
    }
  }

  lazy val winnerMessage: String = s"${winner.map(_.toString).getOrElse("Nobody")} has won!"

  /**
   * Take a turn
   *
   * @return the game with the next turn state
   */
  def takeTurn: Game = {
    println(s"${this}\n")

    def getPos: (Int, Int) = {
      val rowCount = Iterator.continually(
        Try(StdIn.readLine(s"Enter the row to move for ${currentPlayer}: ").toInt)
      ).dropWhile(_.isFailure).next().get
      val colCount = Iterator.continually(
        Try(StdIn.readLine(s"Enter the col to move for ${currentPlayer}: ").toInt)
      ).dropWhile(_.isFailure).next().get

      (rowCount, colCount)
    }

    val possibleMoves = currentPlayer.possibleMoves(board)
    val pos = Iterator.continually(getPos)
      .dropWhile(!possibleMoves.map(m => (m.rowCount, m.colCount)).contains(_))
      .next()

    val move = possibleMoves.find(m => m.rowCount == pos._1 && m.colCount == pos._2).get
    this.copy(board = move(board, currentPlayer), turnCount = turnCount + 1)
  }

  override def toString: String =
    s"""  ${0 to 7 mkString " "}
       |${board.toString.split("\n").zipWithIndex.map { case (s, i) => s"$i $s" }.mkString("\n")}""".stripMargin

}

object Game {
  def apply(): Game = new Game(Board.init(), List(Player(Position.WHITE), Player(Position.BLACK)))
}