Programming Principles Semester 1, 2023 Object -Orientated Design and Implementation
Weighting: 50% Assessment Type: Individual
Overview Thank you for agreeing to work on this project for our organisation. I will give a little bit of a backstory, then get right into the details of what we want. In the past few years, chess has had a bit of a resurgence, with a lot of people playing online against others and watching their favourite players stream. As you know, our company has a board game, Advance , which is a little bit similar to chess and we believe that this is a good time to test the waters and see if it can become success ful online as well. We already have a team of developers putting together an online portal for playing Advance a gainst other players around the world, but what we need from you is to create a bot that will play games automatically. This will allow players to practice before playing other humans, as well as being a valuable source of testing data for the online servi ce. What we need from you is to create a C# .NET Core 6.0 console application that will read in a board state from a text file, make a move, then write out the board state with that move made. We will pass information to your program in the form of command- line arguments and invoke it multiple times to result in it playing a game. In the next section we will go over the rules of Advance. The rules of ‘Advance’ Advance is played on a 9x9 board, with two sets of pieces : one set white, the other set black. One player is in charge of each set of pieces, and the player playing white goes first. On each turn, the current player gets to move a piece according to the rules for that particular piece. Different pieces have different rules as to how they can move and w hat they can do.
The initial board state The initial board state looks like this:
Each player starts with the following pieces: • 7 Zombies : (represented with ‘Z ’ or ‘z’ in the text format) • 2 Builders: (represented with ‘B’ or ‘b’ in the text format) • 2 Miners: (represented with ‘M’ or ‘m’ in the text format) • 2 Jesters: (represented with ‘J’ or ‘j’ in the text format) • 2 Sentinels: (represented with ‘S’ or ‘s’ in the text format) • 1 Catapult: (represented with ‘C’ or ‘c’ in the text format) • 1 Dragon: (represented with ‘D’ or ‘d’ in the text format) • 1 General: (represented with ‘G’ or ‘g’ in the text format)
Winning the game There are two ways to win the game. The first is to trap the opponent by removing all possible ways of making a move. If it is a player’s turn and they are unable to make a legal move, they lose the game. The other is that, after 100 full turns (that is, after both players have made 100 moves) the player with t he greatest material advantage remaining wins. This is calculated based on the following formula: 1 point for each zombie, 2 points for each builder, 3 points for each jester, 4 points for each miner, 5 points for each sentinel, 6 points for each catapult and 7 points for each dragon. The player with the highest score wins. If both players have the exact same score, the game ends in a tie. In the next section we will describe how each of the pieces move. How the pieces move Zombie (Z)
Score: 1 Zombies can move to and capture pieces on any of the three adjoining squares in front of the Zombie (that is, facing upwards for white and downwards for black) like this:
In addition, if there is an enemy piece two squares away in any of those three directions and the intermediate square is empty, a Zombie can perform a leaping attack, capturing the piece on that square :
However, it can only perform this move if there is an enemy piece there that can be legally captured. As the Zombie can only advance, once it reaches the back row (the top row for white, the bottom row for black) it will no longer be able to make any moves.
In this example, there is an enemy Dragon, but because there is a friendly Miner in the way, the Zombie cannot make the leaping attack and capture the Dragon:
However, if the Miner is gone, the Zombie can capture the Dragon as follows:
The Zombie can also capture a piece that is within its normal movement range as well – the leap attack is merely optional. Builder (B)
Score: 2 The Builder can move and capture on any of the 8 adjoining squares:
Builders can also build walls on any of the 8 adjoining squares as well, as long as there is nothing occupying that square . The builder does this without moving:
Walls are special pieces. They do not belong to either player and they do not move. However, they do obstruct other pieces as neither player can move a piece into a square that is being occupied by a wall. The only way to get rid of a wall is to capture it with a Miner. Walls can be used strategically, in order to limit the path of movement for enemy pieces. For example:
Here, the white General is under attack from an enemy Dragon. The Builder cannot move to block the Dragon because this would place the General in danger f rom the other Dragon. However, the Builder can build a wall to the right of the General, protecting the General from the Dragon on the right. Jester (J)
Score: 3 The Jester is the only piece that cannot capture other pieces. It can move to any of the 8 adjoining squares, and it has two special abilities that make it a versatile, useful piece.
The first ability is that the Jester is nimble and can exchange places with a friendly piece, if it is on one of the adjoining squares. The only limitation here i s that the Jester cannot exchange places with another Jester (as this would result in no change to the board state.) This means Jesters can quickly move throughout your ranks as you do not need to make room for them. In this example, a Jester swaps places with a friendly Zombie to move to the front row:
The other ability a Jester has is to convince enemy pieces to change to your side. This ability can be used on an enemy piece ( other than the enemy General ) in one of the 8 adjoining squares and changes that piece into one of your pieces . The Jester performs this action without moving:
This is a very powerful ability, and can allow you to gain multiple Catapults and Dragons on your side. Miner (M)
Score: 4 The Miner moves like a Rook does in chess; it can move any number of square s in one of the 4 cardinal directions (up, down, left and right) and can capture at any of those positions as well :
In addition, the Miner is able to capture walls, which can make it a useful piece to use in your offensiv e if the enemy has used Builders to place fortifications. The Miner captures walls in the same way it captures pieces, and it is subject to the same limitations: it can only capture one piece (or wall) in a move and there must be an unobstructed path to that piece in one of the cardinal directions.
In this example, the enemy General is protected by walls. The Builder can move in and capture a wall, trapping the enemy General and winning the game:
Score: 5 The Sentinel is a strong protective piece. It moves and captures similar ly to a Knight in the game of chess, moving two squares in one cardinal direction and then one square in a perpendicular direction, jumping over any intervening pieces (or walls). In addition to this, the Sent inel protects any friendly pieces ( including other Sentinels) on the 4 adjoining squares in cardinal directions, preventing enemy pieces from capturing your pieces on those square s:
(The circles represent squares the Sentinel can jump to. The shields re present the Sentinel’s protection range.)
The Sentinel’s protection effect comes with the following rules: • A Sentinel will protect any piece of the same colour on those 4 squares, including other Sentinels . • Enemy pieces will not be able to capture a piece protected by a Sentinel. This includes the Catapult’s ranged attack. However, it does not include the Jester’s conversion move, which can be used even if the piece is protected by a Sentinel:
In this example, the enemy Dragon can be converted despite being protected by the enemy Sentinel. • The General is not in danger if it is protected by a friendly Sentinel:
In this example, the General is not in danger from the Miner due to the presence of a Sentinel, and therefore we can move the Catapult into position to threaten the Miner.
Score: 6 The Catapult can only move 1 square at a time, and only in the 4 cardinal directions. Also, it can only move to those squares – it cannot capture enemy pieces on those squares. However, the C atapult is able to capture pieces that are either 3 squares away in a cardinal direction or 2 squares away in two perpendicular cardinal directions:
The Catapult’s attack is special, in that it can remove an enemy piece on one of its capture squares, but it does not itself move when doing so. It also does not matter if there are other pieces in the way, as the C atapult’s projectile flies over the battlefield.
In this example, the catapult can capture the enemy Dragon even though it is surr ounded by walls.
Score: 7 The Dragon is a powerful piece that can move any number of squares in a straight line in any of the 8 directions. It is most similar to a Queen in the game of chess, except for one downside: the Dragon cannot capture any piece it is immediately next to.
The Dragon can move to the squares indicated by the circles, but cannot capture pieces on them. In addition, the Dragon moves in a straight line, and cannot move to or capture a piece if there are pieces or walls in the way.
In this example, the Dragon cannot take the enemy Miner as it is too close. It can, however, capture the enemy Catapult.
Score: N/A The General functions almost identically to the King in chess. It can move and capture on any of the 8 adjoining squares, like the Buil der.
However, the General is not allowed to be captured. Moving the General to a square where an enemy piece could capture it (moving it into danger) is an illegal move. In addition, if your opponent makes a move that places your General in the attacking range of one of their pieces (putting your General in danger ), you must get your General out of danger on the next move (e.g. by moving your General, capturing the threatening piece or obstructing it from being able to attack your General by moving a piec e into its way or building a wall) – any move that does not achieve this is an illegal move. For this reason, targeting the enemy General is usually the key to winning games – once the General is in danger, the player controlling that General usually has a very limited selection of moves, and can be led into a situation where they have no possible moves at all and lose as a result. Your software Basic operation Your program will read in a file path containing a board state, play a single legal move as either the white or black player (depending on what is passed as the first command- line argument), then write out the board state resulting from that move to a file . In this way, your program will play one turn each time it is run. We will pass your program three command -line arguments : • The text ‘white’ or ‘black’ depending on whether the bot is playing white or black this turn. Alternatively, this argument could con tain ‘name’ instead, in which case your program is to output the bot’s name and exit. See naming your bot . If ‘name’ is passed to your program, no other arguments will be. • The filename path to the text file that contains the current board state.
• The filename path to the file where the new board state is to be written after making a move. This could be the same as the previous path, so you will have to make sure to close that file after op ening it. Your program will just make a single move, then write to the file. We will invoke your program multiple times to get it to play a game. Your program will be given the board state in the form of a text file consisting of 9 lines of text, each 9 ch aracters long. The original board state looks like this in text format: mjdsgscjm bzzzzzzzb ......... ......... ......... ......... ......... BZZZZZZZB MJCSGSDJM Lowercase letters are black pieces. Uppercase letters are white pieces. There are two other characters: . and #. The . character indicates an empty square, while the # character indicates a wall (a piece that does not belong to either player but is placed by the Builder.) Your program needs to analyse the board state, determine a legal move and then make that move. For example, if your program is playing white and chooses to advance one of the zombies by one square, your program will write this to the output file: mjdsgscjm bzzzzzzzb ......... ......... ......... ......... ...Z..... BZZ.ZZZZB MJCSGSDJM We will then invoke your program repeatedly in order to get it to play a game. You can do this yourself during testing, and even play your bot against itself to make sure things are working correctly. Your program does not need to check that the board state given to it is legal. For instance, your program will never be given an input file where black has a piece that is putting white’s General in danger and it’s black’s turn to play – because then black could take white’s General and this is not something that can happen in a game of Advance (just like you can never take a King in chess .) However, your program does need to perform a legal move for the specified colour. There will always be a legal move that your bot can play. If there is no
legal move available for that player, the player will lose the game and your program will not be invoked. Levels of functionality Based on the grade level you are hoping to achieve for the ‘Functionality’ marking criterion, you will need to implement a certa in amount of game logic into your program. The most basic level required for a passing grade against this criterion simply requires that your program know the rules of Advance and be able to play legal moves, while later levels require that your program be able to employ certain levels of reasoning to produce better moves. Note that the functionality described is only what is necessary to get the minimum percentage score for that grade level. If you want a higher score, you will need to make some progress towards a higher functionality level. For example, if you meet all of the requirements for a functionality grade of 4 and none of the higher requirement s, you will receive exactly 50% for functionality. Functionality grade 4: Plays legal moves To meet this level of functionality, your program must always produce a legal move if given a legal Advance board state. This means your program needs to know how e very piece moves and the restrictions that pieces must follow when moving. This includes following rules like keeping the General out of danger. Here is one of the tests your program will be tested with (playing as white):
In this example, the white General is in danger due to being attacked by a Dragon. The General cannot move out of the way due to the walls (the only exit is still in the Dragon’s path). Therefore the only legal move that can be made here is to use the Zombie to capture the Dragon.
Functionality grade 5: Must make winning move if possible To meet this level of functionality, your program must not only always make legal moves, but if there is a move it can make that will result in the current player immediately winning the game, that move must be made. (If there are multiple such moves, one of them must be made.)
b#g.S.cmb M......sj ..m.B..## ......... ........z .Jz.#.... ..Z#.z..# C..#z.JZB .G......s In this example (playing as white) we can win the game in one move by moving the Builder in the 3 rd row one square up and to the left. This places the enemy General in danger. The General can’t move out of the way and it can’t capture the Builder either, as the Builder is protected by the Miner. In order to achieve a grade of 5 your program must successfully play the winning move if given a board state where such a move exists. Functionality grade 6: Obtaining material advantage Materia l advantage is important in Advance; more pieces puts you in a better position to defeat your opponent, and the alternate win condition is to have a greater material score than your opponent after both players have each made 100 moves. Accordingly, your program needs to try and maximise material. Your program must still function as described previously - only making legal moves and making winning moves if any are available, but when determining which non- winning move to play, you must take the one that maxim ises your material score – in other words, by capturing enemy pieces (or better yet, converting them with the Jester.) Use the same scoring table used to determine the winner (Zombie=1, Builder=2, Jester=3, Miner=4, Sentinel=5, Catapult=6 and Dragon=7) and, out of the available legal moves, pick the one that maximises your advantage over your opponent. (If there are multiple such moves that give the maximum score advantage, pick one of them.)
In this example there is no way for white to win this turn. As a result, we then look for the way we can best improve our material position over the opponent. Converting an enemy piece with the Jester is usually the best choice, as this essentially means double points (we remove an enemy piece and we obtain a new piece of the same value) - however, this is not currently possible. The Dragon is the best target, at 7 points, but we cannot attack it (remember Dragons cannot attack adjacent squares.) Next is the Catapult (6) but it is safe. Next is the Sentinels (5), but it is protected from our Zombie by a wall. Finally, the Miner (4) on the left is vulnerable - we can capture it with our Miner in the bottom left. This is the only move that can increase our relat ive position by 4 points and this is the highest score we can get, so we must make this move. Note that this is not necessarily a good move to make – we should probably retreat our Dragon so the enemy Jester does not convert it – but it is the best move under this rule. Functionality grade 7: Prediction To get a grade of 7 your program must implement the functionality required for a 6, but when choosing between multiple moves at the same level of relative material advantage improvement (for example, if ther e is no way to capture or convert any of the opponent’s pieces this turn, every possible move has an improvement score of 0 so they are all equal), your program must evaluate these moves by predicting what the opponent will do if you made this move, and then predicting what your program will do in response to the opponent’s move, and choosing the outcome that has the greatest material advantage. To do this, your program must assume that your opponent will be using the functionality grade 6 algorithm to make its move, and that your program will also use the functionality grade 6 algorithm in its response.
In this example, white cannot capture any enemy pieces, and so must make a move that will put white into a good position next time. There are 20 legal moves white can make from here: moving the General to one of the 4 surrounding squares and moving the Builder to either one of the 8 available squares on the bottom row or one of the 8 available squares in the sixth column. Most of these moves are material -advantage -neutra l because the only enemy piece that can attack with range is the Catapult in the top- right corner. In order for any of those pieces to t ake our Builder we would have to move the Builder up to them, allowing either the Catapult or General to capture it. Obviously we do not want to do that - it cannot possibly result in a material advantage for us because we have no pieces that can take advan tage of this to capture something better. However, let’s say we move the Builder to the very top row. This allows it to attack both the Catapult and Jester. The opponent is assumed to use the functionality level 6 program, which could do anything because e very move the opponent could make in response to this is materially neutral. However, what the opponent cannot do is save both the Jester and Catapult, so we will be taking one of those in the next turn. This means the only move we can take, if we have a functionality level 7 bot, is to move the Builder to the top row . No other move guarantees the taking of an enemy piece on the next turn. Some other things to note: • You might predict that, if you make a particular move, your opponent will be able to immediately win. In that case, apply a large penalty such that you will not make that move (unless there is no choice). • You might also predict that, if you make a particular move and your opponent responds as predicted, that you will be able to immediately win on the next turn. In that case, apply a large bonus to that move to ensure that you pick it.
Functionality grade 100%: Higher order reasoning If your program implements functionality level 7 perfectly (that is, it passes all 200 test cases) you will get at least a score of 85% against the functionality criterion. Achieving a higher score here requires you to make more improvements to your bot wh ile still following the rules for functionality level 6 and earlier – in other words, you will need to add your own logic to break ties when there are multiple equally good moves to make at functionality level 7. (Otherwise your program will not succeed in passing the earlier levels and will therefore not even be tested against this higher level.) If your program passes all 200 of the earlier test cases, we will have your program play 50 games against a bot implementing functionality level 7. Your bot is ex pected to win 25 of those games, but winning more often will result in a higher % in the functionality criterion. The exact way you will be marked for this is described in the How you will be marked.