Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

ENGGEN 131 Semester Two – 2022

C Programming Project

An important note before we begin

Welcome to the C Programming project for ENGGEN131 2022!

This project is organized around an interactive text-based puzzle game that can be implemented as a series of related tasks.  When combined, the tasks will complete the implementation for the game.  For each task there is a problem description, and you must implement onefunction to      solve that problem.  In addition to the required function, you may define otherfunctions which   the required function calls upon (i.e. so-called helper functions).  Using helper functions is often a useful way to organize your code, as several simpler functions can be easier to read and            understand than one complex function.

Do your very best, but don’t worry if you cannot complete every task.  You will get credit for each task that you do solve.

IMPORTANT - Read carefully

This project is an assessment for the ENGGEN131 course.  It is an individual project.  You do  not need to complete all of the tasks, but the tasks you do complete should be an accurate            reflection of your capability and effort.  You may discuss ideas in general with other students,    but writing code must be done by yourself. No exceptions. You must not give any other student a copy of your code in any form – and you must not receive code from any other student in any  form.  There are absolutely NO EXCEPTIONS to this rule.

Please follow this advice while working on the project – the penalties for academic misconduct (which include your name being recorded on the misconduct register for the duration of your    degree, and/or a period of suspension from Engineering) are simply not worth the risk.


A brief background

Boulder break is a 2-dimensional puzzle game

where the goal is to help an adventurer collect

treasure and escape from a cave by pushing

boulders into holes that may block the exit.  In

the diagram shown on the right, the adventurer

(trying to escape the cave) is represented by the

red circle.  The gray coloured circles are the

boulders that the adventurer can push.  The

black circle is the hole which is currently

blocking the yellow exit, and into which the

boulders can be pushed.  The small chest

containing jewels is the treasure.

To collect treasure, the adventurer simply

needs to move onto its location.

If the adventurer steps onto a hole, they will fall in and meet an untimely end.  That will be the end of the game.

To push a boulder, the adventurer must position themselves next to the boulder and can only      push the boulder in the direction of their movement.  When the adventurer pushes a boulder, the boulder will continue to roll in a straight line until it hits an obstacle (either part of the cave, a    treasure chest or another boulder).  The position of the adventurer does not change when they    push a boulder.  After the boulder has moved, the adventurer can move.

To escape the cave, the adventurer must move onto the yellow exit.  If the exit is blocked by a hole, they must push a boulder into the hole which will fill it in, allowing them to access the   yellow exit.

Task One: Whats the story?”

(10 marks)

Every good game has an intriguing backstory!

For this task, you should write a story that provides some background to the game.  Why is the   adventurer stuck in the cave?  How did the treasure get there?  What are the boulders and holes  doing in the cave?  These are just ideas – you can write this background in any way that you like – try to be creative!

You must write a function called InitialiseStory():

void InitialiseStory(char* paragraph)

which takes a pointer to a character as input.  This pointer will refer to an array of characters into which your story should be written.

The only requirements for your story are the following:

The story must be longer than 100 printable characters (i.e. the letters that appear when

printed, excluding new lines)

The underlying array which is passed to the function will be of length 2000.  This means

that the maximum length your story can be is 1999 characters (as there must be space for the null terminating character)

The story must be broken into lines (using the new line character).  The maximum length

of any line in your story is 60 printable characters (i.e. the letters that appear when printed, excluding new lines)

To illustrate how this function should work, consider the following main() function for a short program that calls the InitialiseStory() function:

int main(void)

{

char story[2000];

InitialiseStory(story);

printf("%s\n", story);

return 0;

}

Here is one possible output that might be generated by the program above:

A brave adventurer is stuck in a cave! There is treasure

and danger! Collect the treasure and then escape!

Notice that in this example the story satisfies the requirements because:

It is longer than 100 printable characters (a total of 105 printable characters appear on the

screen, 56 on the first line beginning “A brave…” and 49 on the second line beginning “and danger!...”)

The total number of characters that are stored in the array is less than 2000 (in this case, a

total of 108 characters are stored in the array: the 105 printable characters, one new line character at the end of each of the two lines, and the null terminating character)

The maximum length of any line is 60 printable characters (in this case, the first line is 56

printable characters and the second line is 49 printable characters)          However, this example story is not very interesting!  You can surely do better...


Task Two: A birds eye view

(10 marks)

The goal of this task is to produce a printable representation of a cave.  You will need to define a function called PrintCave():

void PrintCave(int cave[CAVE_SIZE][CAVE_SIZE])

The cave is represented by a square 2-dimensional grid.  The size of the grid is given by one     constant: CAVE_SIZE.  As the name of this constant suggests, it indicates how many rows and columns the grid contains.  Initially, this constant is set to the following value:

#define CAVE_SIZE 10

To begin with, every element of the array will be one of two special values: 0 or 1.

The value 0 represents ‘empty space’ and should be displayed using the space character.  The value 1 represents a solid wall and should be displayed using the ‘#’ character.

For example, consider the two variables below that each store a 2-dimensional array representing a cave:

int caveA[CAVE_SIZE][CAVE_SIZE] = {

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

};

int caveB[CAVE_SIZE][CAVE_SIZE] = {

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

};

The first cave, caveA, is just one big solid wall!  Not much fun for exploring.  The second cave, caveB, consists just of an outer boundary of a solid wall with empty space in the middle.

Consider the following code which prints each of these two caves by calling the PrintCave() function:

printf("Printing Cave A:\n");

PrintCave(caveA);

printf("Printing Cave B:\n");

PrintCave(caveB);

The output of this code should be as follows:

Printing Cave A:

##########

##########

##########

##########

##########

##########

##########

##########

##########

##########

Printing Cave B:

##########

#

#

#

#

#

#

#

#

##########

Notice that every line of output produced by the PrintCave() function should end with a single new line character.

Task Three: Landscaping

(10 marks)

Now that you can print a text-based representation of a cave from a 2-dimensional array, it is time to find a more convenient way of initializing the array.

We will do this using a string.  The string will only contain three different characters: ‘0’, ‘1’ and ‘E’ .  Here is an example of such a string stored in a variable called layout (it is printed over     two lines below, for space reasons, but is really just one long string on a single line):

char layout[200] = "1111111111111000001111000000111000000001100000      000E10010000011100000011111000001111111001111111111111";

You will need to define a function called InitialiseCave() that takes two inputs: the 2-

dimensional array that is being initialized and the string that contains the layout information: void InitialiseCave(int cave[CAVE_SIZE][CAVE_SIZE], char *layout)

This function should initialize each element of the array using the values in the string.  The     elements of the array should be initialized from left to right, and top to bottom.   The values in the string define the layout of the cave.  The value ‘0’ represents ‘empty space’, the value ‘1’ represents a solid wall and the value ‘E’ represents an ‘exit’ .

When the cave is printed, the ‘exit’ should be displayed using the space character (this is        identical to the ‘empty space’, so the ‘exit’ will look just like an ‘empty space’ when printed).

You will need to modify your PrintCave() function to ensure the exit is printed correctly. For example, consider the code below which initializes the array and then prints the cave:

char layout[200] = "1111111111111000001111000000111000000001100000      000E10010000011100000011111000001111111001111111111111";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

The output produced by this code should be as follows:

##########

###

##

#

#    #  # ##   ###  #####

##

##

#

#

##

##

###

##########

Task Four: No more gaps

(10 marks)

Now that we can initialize the array easily, we must check that the cave we have created is valid. In order to play the game, the cave must have the following properties:

There can be no gaps or ‘empty space’ in the outside border of the cave (i.e. the outer

rows and columns).  In other words, each element of the outside border of the cave must be a solid wall or be an ‘exit’ position.

There must be exactly one exit position in the entire cave.

The exit position must be on the border of the cave (i.e. on one of the outer rows or

columns) and it must not be on a corner (i.e. not in the top left, bottom left, top right or bottom right corners).

The InitialiseCave() function does not check for these things, and so we must check them now.  We will check for each of these three conditions separately.

Start by writing a function called IsBorderComplete():

int IsBorderComplete(int cave[CAVE_SIZE][CAVE_SIZE])

This function returns true if every element of the outer border of the maze consists only of solid walls or ‘exit’ positions – in other words, no element on the outer border is ‘empty space’ .  For example, consider the following code that creates and prints a cave and then calls this function:

char layout[200] = "1111111111E00000000110000000011000000001            100000000110000000011000000001100000000110000000011111111111";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Complete? %d\n", IsBorderComplete(cave));

The output should be as follows:

##########

#

#

#

#

#

#

#

#

##########

Complete? 1

In this case, the gap that appears near the top left of the cave is an ‘exit’ position, so this is valid.

In contrast, now consider this example:

char layout[200] = "1111111111000000000110000000011000000001            100000000110000000011000000001100000000110000000011111111111";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Complete? %d\n", IsBorderComplete(cave));

This time, the exit position has been replaced with an empty space .  The output now is:

##########

#

#

#

#

#

#

#

#

##########

Complete? 0

Even though the printed cave looks the same as before, this time the gap near the top left corner is actually an ‘empty space’ (not an ‘exit’) and so the cave is invalid.

Task Five: The one and only

(10 marks)

Next, a valid cave must have only one exit.  Define a function called IsExitUnique() which checks that there is a single ‘exit’ position in the 2-dimensional array:

int IsExitUnique(int cave[CAVE_SIZE][CAVE_SIZE])

If there is exactly one ‘exit’ position, then the function should return true, otherwise it should return false.  Consider the following example:

char layout[200] = "1111111111100000000110000000011000000001            1EEEEEEEE110000000011000000001100000000110000000011111111111";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Unique? %d\n", IsExitUnique(cave));

The output of this code is:

##########

#        #

#        #

#        #

#        #

#        #

#        #

#        #

#        #

##########

Unique? 0

This is because there are many ‘exit’ positions on row 4 of the cave (see the ‘E’ characters in the string).   In contrast, consider the following example:

char layout[200] = "1111111111100000000110000000011000000001            1000E0000110000000011000000001100000000110000000011111111111";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Unique? %d\n", IsExitUnique(cave));

This time, there is only one ‘exit’ position in     the entire 2-dimensional array.  Even though     the output of the cave looks exactly the same as before (due to the way that ‘exit’ positions        appear), this time the exit is unique and so the   output is as shown on the right:

##########

#        #

#        #

#        #

#        #

#        #

#        #

#        #

#        #

##########

Unique? 1

Task Six: Exit this way please

(10 marks)

Finally, the cave for the game is only valid if the single ‘exit’ position is positioned on the          outside border of the cave. It cannot be internal to the cave.  In addition, the ‘exit’ position must be accessible to the player who moves horizontally and vertically, and so it cannot be positioned in one of the four corners.

Define a function called IsExitAccessible():

int IsExitAccessible(int cave[CAVE_SIZE][CAVE_SIZE])

which checks the location of the ‘exit’ .  If the ‘exit’ is on the outside border and is not on a corner, then the function should return true, otherwise it should return false.  For example, consider the following code:

char layout[200] = "1111111111100000000110000000011000000001            10000000011000000001100000000110000000011000000001111111111E";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Accessible? %d\n", IsExitAccessible(cave));

In this case, the ‘exit’ position is in the bottom right corner and so is not accessible:

##########

#        #

#        #

#        #

#        #

#        #

#        #

#        #

#        #

#########

Accessible? 0

In contrast, consider the following example where the ‘exit’ position is on the lower border and so is accessible:

char layout[200] = "1111111111100000000110000000011000000001            1000000001100000000110000000011000000001100000000111111111E1";

int cave[CAVE_SIZE][CAVE_SIZE] = {0};

InitialiseCave(cave, layout);

PrintCave(cave);

printf("Accessible? %d\n", IsExitAccessible(cave));

In this case, the output would be as follows:

##########

#        #

#        #

#        #

#        #

#        #

#        #

#        #

#        #

######## #

Accessible? 1

Task Seven: Treasure and danger

(10 marks)

Now that we have a valid cave, with a solid border, and one accessible ‘exit’ positioned on the

border, we can add the remaining elements to the cave.