In this homework, you will implement functionality which will allow you to design a completely functional 5-in-a-row game.

About 5-in-a-row

The game:

  • an be played on a square board of any size larger or equal to 5.
  • A player wins if it has marked a line, column or diagonal of 5 consecutive positions in a row.

Example of a winning position for X on a 5×5 board:

X...0
0X.0.
..X0.
...X.
.0..X

Example of a winning position for 0 on a 7×7 board:

.X...X.
...0...
...0...
.X.0..X
0..0..0
...0...
...X...

Coding conventions

  • In your project template, X is encoded as the first player (One), and 0, as Two.
  • A Board is encoded as a List of Lists of positions (i.e. a matrix), where a position can be One, Two or Empty. We make no distinction in the code between a position and a player. This makes the code slightly easier to write, however Empty cannot be seen as a valid player.

Coding tasks

1. Boards will be represented using the class Board (see the project template), which contains a board matrix, as well as the player whose turn it is to play. You may consider that the first player starts the game. (For testing purposes, you may also create other apply methods). In order to create a board, write a function which converts a string into a Board. Implement the apply method in the companion object Board. As a helper, you can use _.split( c ) where c is a separator string, and _.toList. The best solution is to use a combination of map calls with the above mentioned functions. A string is encoded exactly as in the examples shown above:

  • there are no whitespaces - empty positions are marked by the character '.'
  • lines are delimited by '\n' (the last line does not have a trailing '\n').
def apply(s: String): Board = {
    def toPos(c: Char): Player =
      c match {
        case 'X' => One
        case '0' => Two
        case _ => Empty
      }
    ???

2. Implement the member function isFree which checks if a position (x,y) on the board is free. Recall that list indexing can be done using l(_). Positions are numbered from 0.

def isFree(x:Int, y:Int):Boolean = ???

3. Write a function which returns the opponent of a player. The function is defined in the trait Player, which is allowed in Scala:

def complement: Player = ???

4. Implement the toString functions which converts a board to a string, following the same strategy. Important: this function will be used throughout the tests. Make sure the string doesn't end with '\n'. Hint: instead of foldRight, you can use reduce which works quite similarly, but without requiring an accumulator.

override def toString: String = ???

5. Write a function which returns the columns of a board:

def getColumns: Board = ???

6. Implement the following two functions for extracting the first and second diagonal, as lines, from a board. Hint: use for comprehensions.

def getFstDiag: Line = ???
def getSndDiag: Line = ???

7. Implement the following functions for extracting diagonals above/below the first/second diagonal, as lines. It's not really necessary to make sure that at least 5 positions are available, for now. Hint: if one function must be implemented with element-by-element iteration, the three other can be implemented using each-other, as single-line calls.

def getAboveFstDiag: List[Line] = ???
def getBelowFstDiag: List[Line] = ???
def getAboveSndDiag: List[Line] = ???
def getBelowSndDiag: List[Line] = ???

8. Write a function which checks if the current player is the winner. Hint: functions l.forall(_) and l.exists(_) may be very helpful, together with patterns.

def winner: Boolean = ???

9. Write a function which updates a position from the board, with a given player. The position need not be empty and you are not required to check this. Hint: re-use an inner aux-function together with take and drop.

def update(ln: Int, col: Int) : Board = ??? 

10. Write a function which generates all possible next-moves for any of the two players. A next-move consists in a new board, where the player-at-hand played his move. The order in which you generate next-moves is not important.

def next: List[Board] = ???

11. Implement a function sequences, that returns a map of the form: (5,a), (4,b), (3,c), (2,d) where:

  • a is the number sequences of length 5 that the player has established (on lines, columns or diagonals).
  • b is the number of sequences of length 4 which can be filled-out in order to achieve a 5-sequence. For example: XX XX is such a sequence for player One, however XX0XX is not, since this cannot be filled-out in order to achieve a 5-sequence.
  • c (resp. d) is the number of sequences of length 3 (resp. 2) which can be filled-out in order to achieve a 5-sequence.
  • Proper testing is essential for this function, as the AI will take decisions based on it. It will be harder to spot problems with sequences in a later stage of the project.
  • You can replace the implementation of winner with a call to this function, to make the code more compact and avoid partial re-implementations.
def sequences: Map[Int,Int] = ???
  • Please follow the Submission guidelines which are the same for all homework.
  • To solve your homework, download the Project template, import it in IntellIJ, and you are all set. Do not rename the project manually, as this may cause problems with IntellIJ.