Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
pp:2023:scala:l06 [2023/04/07 15:49] alexandra.udrescu01 |
pp:2023:scala:l06 [2023/04/08 07:49] (current) pdmatei |
||
---|---|---|---|
Line 3: | Line 3: | ||
==== 5-Tic-Tac-Toe ==== | ==== 5-Tic-Tac-Toe ==== | ||
- | **Tic Tac Toe** is usually played on a 3x3 board, marking positions by each player in rounds. Our game is slightly different: | + | **Tic Tac Toe** is usually played on a 3x3 board, marking positions by each player in rounds. Our game is slightly different (usually called 5-in-a-row): |
* it can be played on a square board of any size **larger or equal to 5**. | * it can 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. | * A player wins if it has marked a line, column or diagonal of **5 consecutive positions** in a row. | ||
Line 30: | Line 30: | ||
* In your project template, ''X'' is encoded as the **first** player (''One''), and ''0'', as ''Two''. | * In your project template, ''X'' is encoded as the **first** player (''One''), and ''0'', as ''Two''. | ||
+ | <code scala> | ||
+ | trait Player {} | ||
+ | case object One extends Player { | ||
+ | override def toString: String = "X" | ||
+ | } | ||
+ | case object Two extends Player { | ||
+ | override def toString: String = "0" | ||
+ | } | ||
+ | case object Empty extends Player { | ||
+ | override def toString: String = "." | ||
+ | } | ||
+ | </code> | ||
* 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, although ''Empty'' cannot be seen as a valid player. This makes the code slightly easier to write. | * 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, although ''Empty'' cannot be seen as a valid player. This makes the code slightly easier to write. | ||
+ | <code scala> | ||
+ | type Line = List[Player] | ||
+ | type BoardList = List[Line] | ||
+ | |||
+ | case class Board(b: BoardList) { | ||
+ | override def toString: String = ??? | ||
+ | } | ||
+ | </code> | ||
==== Tasks ==== | ==== Tasks ==== | ||
+ | The following functions have a given signature. However, it is up to the student to decide whether these will be methods of a class or just simple functions. | ||
**6.1.1.** Write a function which converts a string into a ''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: | **6.1.1.** Write a function which converts a string into a ''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: | ||
Line 47: | Line 68: | ||
} | } | ||
??? | ??? | ||
+ | } | ||
</code> | </code> | ||
**6.1.2.** Write a function which checks if a position on the board is free. Recall that list indexing can be done using ''l(_)''. Positions are numbered from 0. | **6.1.2.** Write a function which checks if a position on the board is free. Recall that list indexing can be done using ''l(_)''. Positions are numbered from 0. | ||
<code scala> | <code scala> | ||
- | def isFree(x:Int, y:Int, b:Board):Boolean = ??? | + | def isFree(x:Int, y:Int):Boolean = ??? |
</code> | </code> | ||
**6.1.3.** Write a function which returns the //opponent// of a player: | **6.1.3.** Write a function which returns the //opponent// of a player: | ||
<code scala> | <code scala> | ||
- | def complement(p: Player): Player = | + | def complement(p: Player): Player = ??? |
</code> | </code> | ||
- | **6.1.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 string doesn't end with '\n'. Hint: instead of ''foldRight'', you can use ''reduce'' which works quite similarly, but without requiring an accumulator. | + | **6.1.4.** We want to write a function which converts a board to a string, following the same strategy. Complete the ''toString'' in the Board class. Hint: instead of ''foldRight'', you can use ''reduce'' which works quite similarly, but without requiring an accumulator. |
- | + | ||
- | <code scala> | + | |
- | def show(b: Board): String = ??? | + | |
- | </code> | + | |
**6.1.5.** Write a function which returns the //columns// of a board: | **6.1.5.** Write a function which returns the //columns// of a board: | ||
<code scala> | <code scala> | ||
- | def getColumns(b:Board): Board = ??? | + | def getColumns: Board = ??? |
</code> | </code> | ||
**6.1.6.** Implement the following two functions for extracting the first and second diagonal, as lines, from a board. Hint: use for comprehensions. | **6.1.6.** Implement the following two functions for extracting the first and second diagonal, as lines, from a board. Hint: use for comprehensions. | ||
<code scala> | <code scala> | ||
- | def getFstDiag(b:Board): Line = ??? | + | def getFstDiag(): Line = ??? |
- | def getSndDiag(b:Board): Line = ??? | + | def getSndDiag(): Line = ??? |
</code> | </code> | ||
**6.1.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. | **6.1.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. | ||
<code scala> | <code scala> | ||
- | def getAboveFstDiag(b: Board): List[Line] = ??? | + | def getAboveFstDiag: List[Line] = ??? |
- | def getBelowFstDiag(b: Board): List[Line] = ??? | + | def getBelowFstDiag: List[Line] = ??? |
- | def getAboveSndDiag(b: Board): List[Line] = ??? | + | def getAboveSndDiag: List[Line] = ??? |
- | def getBelowSndDiag(b: Board): List[Line] = ??? | + | def getBelowSndDiag: List[Line] = ??? |
</code> | </code> | ||
**6.1.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. | **6.1.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. | ||
<code scala> | <code scala> | ||
- | def winner(p: Player)(b: Board): Boolean = | + | def winner(p: Player): Boolean = ??? |
</code> | </code> | ||
**6.1.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''. | **6.1.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''. | ||
<code scala> | <code scala> | ||
- | def update(p: Player)(ln: Int, col: Int, b: Board) : Board = ??? | + | def update(p: Player)(ln: Int, col: Int) : Board = ??? |
</code> | </code> | ||
- | **6.1.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. | + | **6.1.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. |
<code scala> | <code scala> | ||
- | def next(p: Player)(b: Board): List[Board] = ??? | + | def next(p: Player): List[Board] = ??? |
</code> | </code> | ||
Line 103: | Line 121: | ||
Use the following board configurations to test your solutions: | Use the following board configurations to test your solutions: | ||
<code scala> | <code scala> | ||
- | todo | + | val t1 = |
+ | """X0X0X0 | ||
+ | |0X0X0X | ||
+ | |X0X0X0 | ||
+ | |.XX0.. | ||
+ | |X00... | ||
+ | |X0X0X0""".stripMargin | ||
+ | |||
+ | val t2 = | ||
+ | """...... | ||
+ | |...... | ||
+ | |...... | ||
+ | |.XX... | ||
+ | |.0000. | ||
+ | |......""".stripMargin | ||
+ | |||
+ | val t3 = | ||
+ | """0X0X0. | ||
+ | |000.X0 | ||
+ | |0.0X.. | ||
+ | |0..0.. | ||
+ | |0X..0X | ||
+ | |...X..""".stripMargin | ||
</code> | </code> |