This is an old revision of the document!


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. 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. Write a function 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.

def show(b: Board): String = ???

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

def getColumns(b:Board): 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(b:Board): Line = ???
def getSndDiag(b:Board): 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(b: Board): List[Line] = ???
def getBelowFstDiag(b: Board): List[Line] = ???
def getAboveSndDiag(b: Board): List[Line] = ???
def getBelowSndDiag(b: Board): List[Line] = ???

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

def winner(p: Player)(b: Board): 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(p: Player)(ln: Int, col: Int, b: Board) : 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(p: Player)(b: Board): 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(p: Player)(b: Board): 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.