COMP 142: Project 4 --- Hogwarts Dueling Club

Introduction

In the world of Harry Potter, the students of Hogwarts School of Witchcraft and Wizardry have the opportunity to participating in a dueling club to sharpen their spellcasting skills should they ever find themselves in a hostile situation. You will write a program to simulate a duel among a group of wizards and witches taking part in the club.

The duels all take place on a ten by ten grid, as shown below.

Dueling basics

Movement on the grid

Encountering other duelers

Moving off the grid and earning points

Example of a complete tournament

Suppose Harry (Gryffindor) and Draco (Slytherin) are the only two participants in a tournament. Harry (student 0) starts with 10 energy at position (0, 5), while Draco (student 1) starts with 8 energy at position (9, 5).

Here is the grid at the beginning of the tournament (before round 1):

In this tournament, Harry always moves first and Draco second, since that is the ordering of their numbers.

In Round 1, Harry moves to (1, 5) and then Draco moves to (8, 5).

In Round 2, Harry moves to (2, 5) and then Draco moves to (7, 5).

In Round 3, Harry moves to (3, 5) and then Draco moves to (6, 5).

In Round 4, Harry moves to (4, 5) and then Draco moves to (5, 5).

In Round 5, Harry moves first, so he moves to (5, 5). He sees Draco in that square and immediately challenges him to a duel. Harry wins, since his energy of 10 is greater than Draco's of 8. Draco immediately leaves the grid (he doesn't even get a chance to move), and his energy is now at 0. Harry's energy is now 2.

After Round 5 is done, the grid looks like this:

The remaining rounds involve Harry continuing to move rightward across the board. During round 9, Harry moves to position (9, 5) --- the edge of the board. During round 10, he steps off the grid completely and earns a point for Gryffindor.

Implementing the project

You will write code to simulate a dueling club tournament. All the information about the students and the starting grid setup will be read from a file. Your code will simulate the duelers moving around, dueling each other, and you will tally up the points at the end of the game. We will introduce the idea of separate compilation in this project. This means your project will be spread over three separate files, that must be named as follows. I have separated the project into four main sections.

CLion set up

  1. Create a new CLion project. I called mine cs142proj4. This creates main.cpp for you. Cut and paste the main.cpp skeleton code from here into your main.cpp. [skeleton main.cpp]
  2. Right-click on main.cpp in the left panel, choose New, then C++ class.

  3. In the box that appears, in the Name field, type dueler and press OK. You will see two new files be created, dueler.cpp and dueler.h. Copy the skeleton code for these files into them. [skeleton dueler.h] [skeleton dueler.cpp]
  4. Compile and run the program. Your program should compile and run just fine, though it shouldn't do much of anything (it should ask you for a filename then quit).

Implementing the dueler class

As you implement the code below, write tests in main() to make sure your code is working. Do not modify main() other than to write tests. In particular, the main game loop logic should not be altered.
  1. A dueler object has six fields (see the code). They should be self explanatory.
  2. Add six getter methods for these six fields. Name them appropriately --- the one for onboard should be called is_on_board(). The one for name is already done for you. Put the declarations of the methods in dueler.h, and the definition (bodies) of the methods in dueler.cpp. This is standard C++ practice for real-world classes. Test your code in main().
  3. Uncomment and write the secondary constructor. This constructor takes five arguments corresponding to all the fields except is_on_board (which should be set to true). Test in main().
  4. Write the print() method in the dueler class. This method should print/cout a string that looks exactly like this:
    Harry (Gryffindor) has 10 energy and is at position (0, 5).
    If the dueler is not on the grid, the message should be:
    Harry (Gryffindor) has 2 energy and is not on the board.
    The print() function is the only method in your dueler class that may use cout.
  5. Write code in main() to test your print() function.
  6. Uncomment and implement the move() method. This function will be called when a dueler is supposed to move one square in their prescribed direction. Your code should update posx, posy, and on_board as needed. Test in main().
  7. Uncomment and implement the duel() method. This function will be called when a dueler encounters an opponent in their same square. Your code should update (as appropriate) the dueler's & opponent's energies and both dueler's onboard fields. This method must return an integer corresponding to if the person who initiated the duel won (1), lost (-1), or tied (0). Test in main().

Reading the input files

  1. Download game1.txt, game2.txt, and game3.txt and either put them into your cmake-build-debug folder inside of your project folder, or create those files from scratch in CLion.
  2. To create them from scratch, right-click on cmake-build-debug, choose New, then File. Type in game1.txt and paste in the text file from above. Repeat for all three files. You should end up with a structure like this:

  3. Look at the contents of game1.txt to get a feel for how the file is structured. Every line contains 5 pieces: the name of the dueler, their house (as a char), their starting magical energy, and their starting position on the board (x, y).
  4. Write the read_file() function in main(). This function should read the file specified by the string argument, and return a vector of duelers corresponding to the contents of the file. Test in main() --- see the comments there for directions.
  5. Write the print_game_state() function. This functions just loops over all the duelers in the argument and calls print() on them. So for the starting game described above, this function should print:

    Harry (Gryffindor) has 10 energy and is at position (0, 5).
    Draco (Slytherin) has 8 energy and is at position (9, 5).

  6. Test in main().

Tournament logic

  1. Implement the game_is_over() function. This function detects if the game is over (all players are off the grid) and returns true if so, and false if not. This code is uses a simple loop over the duelers. Do not use any cout statements in this function. Test in main().
  2. Implement the take_turn() function. This function handles the "turn" for a dueler, which involves two steps. First, the dueler should move. (Call your move() method). Then, the player should challenge all players --- in order --- occupying their current square to a duel.

    This function must print information about where the dueler is moving to, and the state of all duels as they happen. See the sample output below for details. Test in main().

  3. Implement the calculate_statistics() function. This function prints a simple table of points for each house at the end of the game. Test in main().

Coding style

All the normal guidelines for coding from previous projects apply. Do not use any global variables.

Testing your program

You should test your program thoroughly to make sure it works correctly. In particular, you should make up your own game text files to handle situations that the sample files do not test. For instance, does your code correctly handle two players from the same house moving into the same square? (They shouldn't duel.)

Sample input and output

The program's output is in normal text; what the user types is in bold. Each test of the program is shown separately; the SAMPLE RUN parts are not part of the output. Your output must match mine exactly.
========
SAMPLE 1
========
Enter a game filename: game1.txt
At start of game: 
Harry (Gryffindor) has 10 energy and is at position (0, 5).
Draco (Slytherin) has 8 energy and is at position (9, 5).

Beginning round 1.
Harry moves to (1, 5).
Draco moves to (8, 5).

Beginning round 2.
Harry moves to (2, 5).
Draco moves to (7, 5).

Beginning round 3.
Harry moves to (3, 5).
Draco moves to (6, 5).

Beginning round 4.
Harry moves to (4, 5).
Draco moves to (5, 5).

Beginning round 5.
Harry moves to (5, 5).
Harry challenges Draco to a duel.
  Harry wins.

Beginning round 6.
Harry moves to (6, 5).

Beginning round 7.
Harry moves to (7, 5).

Beginning round 8.
Harry moves to (8, 5).

Beginning round 9.
Harry moves to (9, 5).

Beginning round 10.
Harry moves off the board.

At end of game: 
Harry (Gryffindor) has 2 energy and is not on the board.
Draco (Slytherin) has 0 energy and is not on the board.

Final score:
Gryffindor: 1
Ravenclaw: 0
Hufflepuff: 0
Slytherin: 0

========
SAMPLE 2
========
Enter a game filename: game2.txt
At start of game: 
Harry (Gryffindor) has 10 energy and is at position (0, 5).
Draco (Slytherin) has 8 energy and is at position (9, 5).
Luna (Ravenclaw) has 7 energy and is at position (7, 0).
Hannah (Hufflepuff) has 11 energy and is at position (7, 9).

Beginning round 1.
Harry moves to (1, 5).
Draco moves to (8, 5).
Luna moves to (7, 1).
Hannah moves to (7, 8).

Beginning round 2.
Harry moves to (2, 5).
Draco moves to (7, 5).
Luna moves to (7, 2).
Hannah moves to (7, 7).

Beginning round 3.
Harry moves to (3, 5).
Draco moves to (6, 5).
Luna moves to (7, 3).
Hannah moves to (7, 6).

Beginning round 4.
Harry moves to (4, 5).
Draco moves to (5, 5).
Luna moves to (7, 4).
Hannah moves to (7, 5).

Beginning round 5.
Harry moves to (5, 5).
Harry challenges Draco to a duel.
  Harry wins.
Luna moves to (7, 5).
Luna challenges Hannah to a duel.
  Hannah wins.
Hannah moves to (7, 4).

Beginning round 6.
Harry moves to (6, 5).
Hannah moves to (7, 3).

Beginning round 7.
Harry moves to (7, 5).
Hannah moves to (7, 2).

Beginning round 8.
Harry moves to (8, 5).
Hannah moves to (7, 1).

Beginning round 9.
Harry moves to (9, 5).
Hannah moves to (7, 0).

Beginning round 10.
Harry moves off the board.
Hannah moves off the board.

At end of game: 
Harry (Gryffindor) has 2 energy and is not on the board.
Draco (Slytherin) has 0 energy and is not on the board.
Luna (Ravenclaw) has 0 energy and is not on the board.
Hannah (Hufflepuff) has 4 energy and is not on the board.

Final score:
Gryffindor: 1
Ravenclaw: 0
Hufflepuff: 1
Slytherin: 0

========
SAMPLE 2
========
Enter a game filename: game3.txt
At start of game: 
Harry (Gryffindor) has 8 energy and is at position (0, 2).
Draco (Slytherin) has 8 energy and is at position (9, 2).
Luna (Ravenclaw) has 7 energy and is at position (8, 0).
Hannah (Hufflepuff) has 11 energy and is at position (8, 9).
Hermione (Gryffindor) has 9 energy and is at position (0, 4).
Pansy (Slytherin) has 6 energy and is at position (9, 4).
Marcus (Ravenclaw) has 4 energy and is at position (4, 0).
Ernie (Hufflepuff) has 5 energy and is at position (4, 9).
Ron (Gryffindor) has 9 energy and is at position (0, 6).
Vincent (Slytherin) has 1 energy and is at position (9, 6).
Cho (Ravenclaw) has 10 energy and is at position (2, 0).
Justin (Hufflepuff) has 3 energy and is at position (2, 9).

Beginning round 1.
Harry moves to (1, 2).
Draco moves to (8, 2).
Luna moves to (8, 1).
Hannah moves to (8, 8).
Hermione moves to (1, 4).
Pansy moves to (8, 4).
Marcus moves to (4, 1).
Ernie moves to (4, 8).
Ron moves to (1, 6).
Vincent moves to (8, 6).
Cho moves to (2, 1).
Justin moves to (2, 8).

Beginning round 2.
Harry moves to (2, 2).
Draco moves to (7, 2).
Luna moves to (8, 2).
Hannah moves to (8, 7).
Hermione moves to (2, 4).
Pansy moves to (7, 4).
Marcus moves to (4, 2).
Ernie moves to (4, 7).
Ron moves to (2, 6).
Vincent moves to (7, 6).
Cho moves to (2, 2).
Cho challenges Harry to a duel.
  Cho wins.
Justin moves to (2, 7).

Beginning round 3.
Draco moves to (6, 2).
Luna moves to (8, 3).
Hannah moves to (8, 6).
Hermione moves to (3, 4).
Pansy moves to (6, 4).
Marcus moves to (4, 3).
Ernie moves to (4, 6).
Ron moves to (3, 6).
Vincent moves to (6, 6).
Cho moves to (2, 3).
Justin moves to (2, 6).

Beginning round 4.
Draco moves to (5, 2).
Luna moves to (8, 4).
Hannah moves to (8, 5).
Hermione moves to (4, 4).
Pansy moves to (5, 4).
Marcus moves to (4, 4).
Marcus challenges Hermione to a duel.
  Hermione wins.
Ernie moves to (4, 5).
Ron moves to (4, 6).
Vincent moves to (5, 6).
Cho moves to (2, 4).
Justin moves to (2, 5).

Beginning round 5.
Draco moves to (4, 2).
Luna moves to (8, 5).
Luna challenges Hannah to a duel.
  Hannah wins.
Hannah moves to (8, 4).
Hermione moves to (5, 4).
Hermione challenges Pansy to a duel.
  Pansy wins.
Pansy moves to (4, 4).
Ernie moves to (4, 4).
Ernie challenges Pansy to a duel.
  Ernie wins.
Ron moves to (5, 6).
Ron challenges Vincent to a duel.
  Ron wins.
Cho moves to (2, 5).
Cho challenges Justin to a duel.
  Justin wins.
Justin moves to (2, 4).

Beginning round 6.
Draco moves to (3, 2).
Hannah moves to (8, 3).
Ernie moves to (4, 3).
Ron moves to (6, 6).
Justin moves to (2, 3).

Beginning round 7.
Draco moves to (2, 2).
Hannah moves to (8, 2).
Ernie moves to (4, 2).
Ron moves to (7, 6).
Justin moves to (2, 2).
Justin challenges Draco to a duel.
  Draco wins.

Beginning round 8.
Draco moves to (1, 2).
Hannah moves to (8, 1).
Ernie moves to (4, 1).
Ron moves to (8, 6).

Beginning round 9.
Draco moves to (0, 2).
Hannah moves to (8, 0).
Ernie moves to (4, 0).
Ron moves to (9, 6).

Beginning round 10.
Draco moves off the board.
Hannah moves off the board.
Ernie moves off the board.
Ron moves off the board.

At end of game: 
Harry (Gryffindor) has 0 energy and is not on the board.
Draco (Slytherin) has 7 energy and is not on the board.
Luna (Ravenclaw) has 0 energy and is not on the board.
Hannah (Hufflepuff) has 4 energy and is not on the board.
Hermione (Gryffindor) has 0 energy and is not on the board.
Pansy (Slytherin) has 0 energy and is not on the board.
Marcus (Ravenclaw) has 0 energy and is not on the board.
Ernie (Hufflepuff) has 4 energy and is not on the board.
Ron (Gryffindor) has 8 energy and is not on the board.
Vincent (Slytherin) has 0 energy and is not on the board.
Cho (Ravenclaw) has 0 energy and is not on the board.
Justin (Hufflepuff) has 0 energy and is not on the board.

Final score:
Gryffindor: 1
Ravenclaw: 0
Hufflepuff: 2
Slytherin: 1

What to turn in

Through Moodle, upload three files: main.cpp, dueler.h, and dueler.cpp. Do not upload the game text files.

Challenge Problem

Enhance the statistics at the end of the game to print things like total number of duels, player who won the most duels, the house(s) who won the whole tournament, or other interesting statistics.