COMP104: Programming

EXTRA14: The Lord of the Rings


Implement a maze game base on the movie The Lord of the Rings. In the game, the hero Frodo must safely cross the Black Forest without being caught by the Black Riders. To reach the exit of the forest, he must cross 8 different stages of the trail. Frodo must race against the clock too, he must cross the Black Forest in less than 80 seconds.
Below is a representation of the board.  You begin your journey as Frodo from the upper-left corner of the board (represented by "F"). You must reach the exit at the lower-right corner (represented by "E" unless the square is occupied by a Black Rider). After you reach the exit, you will advance to stage 2. Frodo also begins stage 2 from the upper-left corner, with the exit in the lower-right corner. Then you must successfully cross this to stage 3. The player  must complete 8 stages to exit the Black Forest and win the game. On each level, the evil Black Riders (represented by "B") start from random locations (but not from the upper-left where Frodo starts) and move about at random, ready to attack Frodo. After each level, the Black Riders should start from different random locations. The number of BlackRiders is equal to 3 times the stage number: 3 BlackRiders on stage 1, 6 on stage 2, 9 on stage 3, ... . Finally, there will be 24 BlackRiders on stage 8! (Impossible!!!)
The Lord of the Rings
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F| | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | |B| | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | | | | | | | | | | | | | | |E|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Stage 1
Time remaining: 80
Which way to move (1-9)? Press x to exit:

In every step, the user can press one of the keypad numbers to move Frodo left, right, up, down, or diagonally. Use the keypad numbers to determine which direction to move Frodo (e.g., 1 means move downward to the left, 2 means move downward, 3 means move downward to the right, ...). [When you are playing, enable the keypad with the "Num Lock" key above the keypad numbers.] For each move of Frodo, the Black Riders move one square in a random direction. If two Black Riders move into the same square, only display one "B", and afterwards they should continue their movement. If a Black Rider moves into the same square as Frodo, only display a "B" and show the message "Frodo attacked by Black RIder!" and the program should end. Do not allow Black Riders to move off the board. If Frodo moves off the board, GAME OVER!, he dies. The user can also press ' x' to exit the program. Frodo has 80 seconds to complete all 8 stages. After each move, display the stage and the number of remaining seconds. If the time remaining reaches zero, GAME OVER!, the user loses (update the time only after each move). If the player finishes stage 8, print a special congratulations message because Frodo has finally left the Black Forest and wins.

Implement the game using a linked list of Black Riders. Each time a new level is reached, allocate new Black Riders and attach them to the list (so, the fields of BlackRider will include the current row, current column, and a pointer to another BlackRider). For displaying the board, follow the linked list of Black Riders, displaying each of them on the board. You should also have a Board struct that contains the stage, Frodo's position, and a pointer to the first Black RIder.

To make the game more fun to play, include the library <conio.h>, and use the getch() function to read the input. It does not wait for the user to press the enter key, but gets one character immediately.
#include <conio.h>  // contains getch()
 ...
char dir = getch();     // get a character from keyboard without waiting for enter key

Another way to make the game more fun to play is to use the function:
    system("cls");
to clear the screen. It is in the <cstdlib> library.

Below is a template of the game. Fill in the missing functions.

//--------------------------------------------------------------------------
// yourName yourLabSection
// lab10.cpp (model answer)
// The Lord of the Rings
#include <iostream> // contains cout and cin
#include <cstdlib>  // contains the random number generator rand()
#include <ctime>    // contains time() to seed random number
#include <conio.h>  // contains getch()
using namespace std;

struct BlackRider{
    int row;            // current row number of Black Rider
    int col;            // current col number of Black Rider
    BlackRider* next;   // pointer to next Black Rider
};

struct Board{
    int stage;               // current stage number
    int frodoRow;            // current row number of Frodo
    int frodoCol;            // current col number of Frodo
    BlackRider* bhead;       // pointer to Black Rider linked list
};

// initialize the game board with stage=1, Frodo at upper-left, and 3 BlackRiders at random
void initGame(Board& board);

// game logic
void playGame(Board& board);

// display the game information
void display(Board board, int timeRemaining);

// Frodo makes a move(left, right, up, down or diagonal)
void moveFrodo(Board& board);

//BlackRider makes a move (left, right, up, down or diagonal)
void moveBlackRiders(Board& board);

// check if game ends
bool gameEnd(Board board, int timeRemaining);

// check to see if Frodo at exit
bool FrodoAtExit(Board board);

// check if any BlackRider and Frodo located in the same position
bool blackRiderAttackFrodo(Board board);

// increment the stage of game
void incrementStage(Board& stage, int timeremain);

// set the number of Black Riders to 3*stage number
void addBlackRiders(Board& board);

// delete linked list of Black Riders
void deleteBlackRiders(Board& board);
 

void main(){
    Board board;

    srand(time(0));
    initGame(board);
    playGame(board);
}

// game logic
void playGame(Board& board){
    int startTime;
    int timeRemaining = 80; // start with 80 seconds to play game

    startTime = time(0);
    display(board, timeRemaining);
    while(true){
        //move Frodo and Black Riders
        moveFrodo(board);
        moveBlackRiders(board);

        //check if game ends. If yes, return to the caller function
        timeRemaining = 80 - (time(0) - startTime);
        if(gameEnd(board, timeRemaining)){
            deleteBlackRiders(board);
            return;
        }

        //advance to next stage
        display(board, timeRemaining);
        if(FrodoAtExit(board)){
            deleteBlackRiders(board);
            addBlackRiders(board);
            incrementStage(board, timeRemaining);
        }
    }
}

// Frodo makes a move(left, right, up, down or diagonal)
void moveFrodo(Board& board){
    char dir;
    cout << "Which way to move (1-9)? Press x to exit: ";
    dir = getch();
    if      (dir == '1'){ board.frodoRow++; board.frodoCol--; }
    else if (dir == '2'){ board.frodoRow++;                   }
    else if (dir == '3'){ board.frodoRow++; board.frodoCol++; }
    else if (dir == '4'){                   board.frodoCol--; }
    else if (dir == '5'){                                }
    else if (dir == '6'){                   board.frodoCol++; }
    else if (dir == '7'){ board.frodoRow--; board.frodoCol--; }
    else if (dir == '8'){ board.frodoRow--;                   }
    else if (dir == '9'){ board.frodoRow--; board.frodoCol++; }
    else if (dir == 'x'){
        cout << endl << "Exiting!" << endl << "GAME OVER!" << endl;
        deleteBlackRiders(board);
        exit(0);
    }
    if(board.frodoRow<0 || board.frodoRow>7 || board.frodoCol<0 || board.frodoCol>15){
        cout << endl << "Frodo falls off the board!!" << endl << "GAME OVER!" << endl;
        deleteBlackRiders(board);
        exit(0);
    }
}