For this assignment, we are going to be creating a program that lets you play a game of Onitama.
You will be graded on:
- Code Correctness (based on autotests -- so make sure you DO NOT modify any method names and type signatures)
- Code Design (having clean, simple code that avoids repetition)
- Documentation (having proper, complete javadocs for all your code)
- Effective use of git (making frequent commits with good log messages)
If you are unfamiliar with this game, make sure to check out these links first:
https://www.youtube.com/watch?v=IFRewjcngwU
https://www.arcanewonders.com/resources/Onitama_Rulebook.PDF
One of the first errors you may see in src/test/... (let us use OnitamaTest.java for this example.), is going to be the following:
Before you get tempted to post this on Piazza, please follow the following instructions.
First, you will see that there is an option: "More actions...", please click that. That will lead you to the following situation:
Next, we want you to click the option: Add 'JUnit5.4 to classpath', this will
do what it says it does and lets you make test cases in OnitamaTest.java
and OnitamaBoardTest.java
.
After clicking that option, you will see the following popup:
Simply, press OK, and you are good to go.
We encourage you to make test cases for each function you will have to implement, as it will let you know if you have bugs in your code. Testing is one of the most important, things you will do as a software developer! It helps you catch bugs that you may not have caught otherwise.
Important: In order to get full marks for the git usage portion of the assignment, you must at the very least commit where it tells you to do so in this README, with the EXACT same commit message, mentioned in the README. If you fail to follow these instructions, you will not get full marks for the git portion of the assignment. The excuses "I forgot to commit", "I was one letter off the correct git message", "Gamestonks!!!" will not be acceptable.
With that out of the way, you are ready to start Assignment 1!
Complete the easy methods in OnitamaBoard.java:
getDimension
,getStyles
,getToken
,setToken
,validCoordinate
Do the following to add and commit your code:
cd a1-yourgithubusername/a1-code
git add OnitamaBoard.java
git commit -m "Easy OnitamaBoard methods completed"
Complete the method constructStyles
in OnitamaBoard.java
, based on the method documentation.
In a normal Onitama game, there are 16 different styles that the players choose from. However, for simplicity we will only be using 5 of these styles (Crab, Horse, Mantis, Rooster, and Dragon), as you can see below.
Each style represents a unique movement pattern. In this pictures, the black square is the starting position, and the other shaded squares are the destinations that the token is able to reach using the respective movement style.
For example, let's consider the Crab style.
Let (r, c) represent the black square, the starting position, where r is the row, and c is the column.
Then, we are able to reach the following positions, relative to the starting position:
- ( r - 1 , c )
- ( r, c - 2 )
- ( r, c + 2 )
This method will distribute the five styles that we are using to the two players.
Normally, players would pick the styles randomly, however for this assignment, we will distribute them consistently each time.
- Player 1 (G1) should start with Crab and Horse.
- Player 2 (G2) should start with Mantis and Rooster.
- The extra style (EMPTY) should be Dragon.
This is so we can guarantee consistency when testing the program.
Git add your file and then commit your method!
git add OnitamaBoard.java
git commit -m "OnitamaBoard.constructStyles method completed"
Complete the OnitamaBoard constructors in OnitamaBoard.java
, based on the method
documentation.
You'll notice that we are using Java's method overloading feature in this class. This is because we have 2 constructors!, they have different arguments (as required by overloading).
For this constructor, we want to construct an empty Onitama board with dimension size x size.
In addition to this, we want to place the four monks and the 1 grandmaster on opposite sides of the board
for each player. We want the board to look like the following (for size = 5
):
0 1 2 3 4
+-+-+-+-+-+
0|x|x|X|x|x|0
+-+-+-+-+-+
1| | | | | |1
+-+-+-+-+-+
2| | | | | |2
+-+-+-+-+-+
3| | | | | |3
+-+-+-+-+-+
4|o|o|O|o|o|4
+-+-+-+-+-+
0 1 2 3 4
However, the grid should not be all hardcoded!
Remember, that there is a size parameter, so what would you do if size > 5?
We require that you satisfy the following 4 conditions:
- Even sizes raise exceptions (size must be odd)
- The grandmaster must be in the center column
- The monks should be placed in all other columns
- The pieces for Player X must be placed on the 0'th row. The pieces for Player O must be placed on the {size - 1}'th row
Keep these things in mind, when implementing the constructor!
Lastly, we want to distribute the 5 styles to the players.
Hint: You just completed a helper for this... USE IT!!
For this second constructor, we want to construct a preset Onitama board!
Use the given board parameter which is a size x size char array to initialize this OnitamaBoard.
Finally, we want to distribute the 5 styles to the players just like we did in the first constructor.
Git add your file and then commit your method!
git add OnitamaBoard.java
git commit -m "OnitamaBoard.constructor method completed"
Complete the method exchangeStyle
in OnitamaBoard.java
, based on the method
documentation.
In Onitama, when a player does a move with a certain style (in our case it will be one of Crab, Horse, Mantis, Rooster or Dragon), they swap the style they just used with the EMPTY/Unowned style.
Remember, that each player has 2 styles, but we have a total of 5 styles, so one of these styles will NOT have an owner (G1 or G2), rather, their owner will be EMPTY.
For this method, we want to exchange the given style with the EMPTY/Unowned style. This involves swapping their owners if possible.
Git add your file and then commit your method!
git add OnitamaBoard.java
git commit -m "OnitamaBoard.exchangeStyle method completed"
Fix any issues you find, clean up your code (about 20% of your grade will be on your
code design - avoiding repeated code, using helper functions appropriately, etc.)
and then commit and push OnitamaBoard.java
.
git add OnitamaBoard.java
git commit -m "OnitamaBoard.java completed"
git push
Complete the easy methods in Onitama.java
:
getWhoseTurn
,otherPlayer
,Onitama(int dimension)
,Onitama(Player player1, Player player2, int dimension)
The constructors should follow the 2 existing constructors, but additionally check for the dimension. The dimension is valid if it is odd, and greater than or equal to 5. If it is valid, then we set it and construct a new OnitamaBoard of that dimension.
Valid Dimensions: 5, 7, 9, ... Invalid Dimensions: 2, 3, 4, 6, 8, 10, ...
Do the following to add and commit your code:
git add Onitama.java
git commit -m "Easy Onitama methods completed"
Complete the method isLegalMove
in Onitama.java
, based on the method
documentation.
This method is going to be a helper for the next task. It checks if a move with the starting position (rowO, colO) to the target position (rowD, colD) is valid.
For a move to be valid, it must satisfy the following criteria:
- The starting and target positions must be in the bounds of the board.
- The token at the starting position must belong to the current player who is trying to make this move.
- The destination position must NOT belong to the current player. In other words, it must be EMPTY or belong to the opposing player.
IMPORTANT: This method does not check if the move follows a valid movement style
Do the following to add and commit your code:
git add Onitama.java
git commit -m "Onitama.isLegalMove completed"
Complete the move
method in Onitama.java
, based on the method documentation and the
hints provided within the comments in the file. Try to keep your code short
and clean, using helper methods from this class and the OnitamaBoard class as appropriate.
This method takes in the starting position (rowO, colO) and the target/destination position (rowD, colD) that a player is going
to 'move to' (move from starting position to the destination position), and the name of the style that they are using (styleName).
If the move is not valid from the conditions in isLegalMove
or the move does not follow the movement pattern from the given style (remember each style has a unique movement pattern), do nothing to the board and
return false.
If the move is valid, then we need to do the following (the order is not necessarily the same order that you should implement it in):
-
Move the token from starting position to the destination position.
-
Exchange the current player's styles.
-
Update whoseTurn to be the next player's turn.
-
return true, since this was a successful operation.
For example, if my board looked like below:
0 1 2 3 4
+-+-+-+-+-+
0| | |X| | |0
+-+-+-+-+-+
1| |x| | | |1
+-+-+-+-+-+
2| | | |o| |2
+-+-+-+-+-+
3| | | |o| |3
+-+-+-+-+-+
4| | |O| | |4
+-+-+-+-+-+
0 1 2 3 4
Then if I wanted to make a move (rowO = 1, colO = 1, rowD = 2, colD = 3, styleName = "dragon")
with player 'X', then this would be a valid move and we would eliminate player 'O's monk at the position (2, 3) and move player 'X's monk to the position (2, 3).
The updated board would look like the following:
0 1 2 3 4
+-+-+-+-+-+
0| | |X| | |0
+-+-+-+-+-+
1| | | | | |1
+-+-+-+-+-+
2| | | |x| |2
+-+-+-+-+-+
3| | | |o| |3
+-+-+-+-+-+
4| | |O| | |4
+-+-+-+-+-+
0 1 2 3 4
Git add your file and then commit your method!
git add Onitama.java
git commit -m "Onitama.move completed"
Complete the getWinner
method in Onitama.java
, based on the method documentation. Again, keep
your code short and clean. Use the G1, G2 and EMPTY variables from the OnitamaBoard
class to access the needed character tokens.
There are 2 winning conditions:
- A player has captured the opponent's grandmaster.
- A player has reached the starting position of the opponent's grandmaster.
Here are 4 very basic game states to represent player victories.
X wins by condition 1.
0 1 2 3 4
+-+-+-+-+-+
0| | | | | |0
+-+-+-+-+-+
1| |o| | |x|1
+-+-+-+-+-+
2| | |X| | |2
+-+-+-+-+-+
3| | | | |o|3
+-+-+-+-+-+
4| | | | | |4
+-+-+-+-+-+
0 1 2 3 4
X wins by condition 2.
0 1 2 3 4
+-+-+-+-+-+
0| | | | | |0
+-+-+-+-+-+
1| | | | | |1
+-+-+-+-+-+
2| | |O|o| |2
+-+-+-+-+-+
3| | | | | |3
+-+-+-+-+-+
4| | |X| | |4
+-+-+-+-+-+
0 1 2 3 4
O wins by condition 1.
0 1 2 3 4
+-+-+-+-+-+
0| | | | | |0
+-+-+-+-+-+
1| |x| | | |1
+-+-+-+-+-+
2| | |O| | |2
+-+-+-+-+-+
3| | | |x| |3
+-+-+-+-+-+
4| |o| | | |4
+-+-+-+-+-+
0 1 2 3 4
O wins by condition 2.
0 1 2 3 4
+-+-+-+-+-+
0| | |O| | |0
+-+-+-+-+-+
1| | | | | |1
+-+-+-+-+-+
2| |x|X| | |2
+-+-+-+-+-+
3| | | | | |3
+-+-+-+-+-+
4| | | | | |4
+-+-+-+-+-+
0 1 2 3 4
Finally, git add Onitama, commit and push!
git add Onitama.java
git commit -m "Onitama.getWinner completed"
git push
After the previous tasks have all been completed, you should be able to
run Onitama.java
to run all the test code written for you in the Onitama.main
method. The output should be exactly the text in the file onitamaMainOutput.txt
included in this repository.
Fix any issues you find, clean up your code (20% of your grade will be on your code design - avoiding repeated code, using helper functions appropriately, etc.) and then commit and push Onitama.java.
git add Onitama.java
git commit -m "Onitama.java completed"
git push
This class represents a turn in Onitama. It contains the following attributes:
- rowO: The origin row.
- colO: The origin column.
- rowD: The destination row.
- colD: The destination column.
- styleName: The style being used in this turn.
This section should not be too difficult considering everything previous to this. It is in preparation for Section 4, where you are able to play a game of Onitama between two human players!
However, please make sure to keep the code clean and concise as you are being marked for your code design!
Complete the Turn constructor in Turn.java, based on the method documentation.
Git add your file and then commit your method!
git add Turn.java
git commit -m "Turn.Turn completed"
Add the following methods in Turn.java:
getRowO
getColO
getRowD
getColD
getStyle
Git add your file and then commit your method!
git add Turn.java
git commit -m "Turn getters completed"
Create a method to represent a Turn
as a string.
When running Turn.java
, you should get the same output as displayed below.
X: (0,0,dragon) -> (1,2)
O: (3,2,crab) -> (2,2)
X: (2,2,rooster) -> (3,1)
Git add your file and then commit your method!
git add Turn.java
git commit -m "Turn string representation completed"
Open up the file OnitamaControllerHumanVSHuman.java
. If you have completed all
previous tasks correctly, you should be able to run this file and play a game
of Onitama now!
To informally test things out: The file onitamaSampleInput.txt included in this repository provides some sample input formatted as:
PLAYER makes move : (rowO,colO,styleName) -> (rowD,colD)
When you run the OnitamaControllerHumanVSHuman
file, you will be asked for input in the following order:
- styleName
- rowO
- colO
- rowD
- colD
The file onitamaSampleOutput.txt shows the output you should see if you enter all these values as input in the given order. You can try inputting the provided values and comparing the output you get to the one provided in this txt file.
Implement a PlayerRandom
class. It should follow similarly to PlayerHuman
, except it makes random valid moves.
This method should return a Turn object as defined in Player.java
.
To do this, you will have to randomly pick a valid move that this player can make.
Hint: You will need an instance of the current Onitama game.
- Try to generate a list/array of all valid moves this player can make.
- Then pick a random move from this list/array.
Note: You will not get full marks by brute-forcing this method.
These controllers should follow similarly to structure to OnitamaControllerHumanVSHuman.java
.
They will let us play a game VS a bot which makes random moves, as well as allow a game to run between 2 random bots.
This controller should have a PlayerHuman
and a PlayerRandom
and play a game of Onitama between them.
Git add your file and then commit your method!
git add OnitamaControllerHumanVSRandom.java
git commit -m "OnitamaControllerHumanVSRandom completed"
This controller should have 2 PlayerRandom
s and play a game of Onitama between them.
Git add your file and then commit your method!
git add OnitamaControllerRandomVSRandom.java
git commit -m "OnitamaControllerRandomVSRandom completed"
Note: Think about design choices you can make to keep the code clean and short and avoid repetition.
Add documentation to all the following classes and methods (and any other additional ones you made):
Turn
OnitamaControllerHumanVSHuman
OnitamaControllerHumanVSRandom
OnitamaControllerRandomVSRandom
Player
PlayerHuman
PlayerRandom
Follow the conventions of writing proper Javadocs (https://axiom.utm.utoronto.ca/~207/21s/slides/1/javadoc.html#/)
Remember that 20% of your mark is for code design. Make sure that your code is clean and concise, following all of the principles we have discussed in class.
Congratulations on finishing A1!!!
Take some time to relax and do some things you enjoy, since we know that university is stressful at times (we were all in your position not too long ago).
Go play some games, watch shows/anime, read a book, draw something, or do literally anything that you love to do so you can destress!
Here's a great video I watch to celebrate completing assignments!