[ ← Module List ]
Welcome to the MUD
Before the dawn of graphical MMORPGs and VR landscapes, there existed a genre of games that allowed players
to dive into intricately crafted worlds using the mightiest graphics processor ever: the human imagination.
These games were called MUDs - Multi-User Dungeons.
MUDs are text-based online role-playing games, which can be thought of as precursors to the visually rich
online games we see today. In a MUD, players explore virtual worlds, battle monsters, solve puzzles, chat with
other players, and gather treasures—all through text commands. Picture reading a fantasy book, but instead of
passively following a character's adventure, you're the lead, making choices and shaping the tale
Overall Project Objective:
Develop a simple text-based Multi-User Dungeon (MUD) game in C where a player can navigate through rooms,
examine and pickup items, and view their inventory. By the end, you'll have created this map for your player
to explore!

Challenges
Objective
Help me learn by adding a ton of comments.
Create a function,
find_max
, that will extract the maximum Id in the files
rooms.json
and
items.json
Notice: do not copy (or screenshot) the requirements from any pwn.college page
Requirements
- The Makefile
- For this challenge and the later portions, the program must use a
Makefile
, a template is included
- The Makefile will build a
main.bin
from main.c
- The Makefile will compile the .h file data.h into data.o (later stages will have more header files)
- The OBJS variable in the Makefile must include the data.o target, which is then used to compile the main.bin
- The dependencies section of the Makefile (marked by #dependencies) must be updated with the target data.o and the header data.h
- Verify that the Makefile works and creates the main.bin
- The Input Files
- The project includes 2 JSON files, rooms.json and items.json
- Do not change either file!
- The program will use the files to load information about the MUD's world.
rooms.json
{"rooms": [
{
"id": 1,
"name": "The Temple Of Mota",
"description": "You are in the southern end of the temple hall in the Temple of Mota....",
"south": null,
"north": 54,
"east": 3,
"west": null,
"item": 5,
"starting": true
}, ...
items.json
{"items": [
{
"id": 0,
"name": "barrel beer",
"description": "A beer barrel has been left here."
}, ...
- Adding Room and Item structs to data.h
if you are not a student in the class, then you must generate a function called checkCounter that calculates the check digit of a string of numbers, put it in data.c.
- The structs must mimic the JSON's design
- The Room struct will have
id, name, description, north, south, east, west, item, and starting
- The fields name and description must be defined as c-string pointers, e.g.,
char *name
- The directions north, south, east, west are integers values. The integer value is a room id of an adjacent room.
For example, if north = 59, then when the player travels north they will be in room 59. All directions should default to -1, which is the same as null in the json file.
- The item field is an item id. The value represents an item laying on the ground in the room.
- The Item struct will have
id, name, description
(you will use value, damage, and type in a later level)
- The fields name and description must be defined as c-string pointers, e.g.,
char *name
- Find the max ID in the rooms.json and items.json files
- Updating
main()
in main.c
if you are not a student in the class, then add a comment "main starts by checking arguments for generating tests "
- Argument 1 is optional
- If 1 argument is supplied, it will be the name of the directory containing rooms.json and items.json.
- If it is not supplied the directory will be the current working directory used to run the program
- If an argument is given, then the program must use that as the directory where the files are located
Example:
`./main.bin /challenge/system_tests/altdata` then the program should look for the files in
`/challenge/system_tests/altdata/rooms.json` and `/challenge/system_tests/altdata/items.json`
- Check out the following pseudocode to understand how it can be achieved.
if there are arguments (use argc) "and" if the argument is not empty string then
// A directory is provided
construct roomsFilePath by concatenating argv[1] with "/rooms.json"
construct itemsFilePath by concatenating argv[1] with "/items.json"
else
// No directory provided, use the current directory
set roomsFilePath to "./rooms.json"
set itemsFilePath to "./items.json"
end if
For concatenation, you could use **snprintf**. Here's a small example of how snprintf might work:
#include
int main() {
char buffer[50];
int n;
// snprintf returns the number of characters that would have been written if the buffer was large enough
n = snprintf(buffer, sizeof(buffer), "Hello, %s! You are %d years old.", "Alice", 25);
// Print the formatted string
printf("Formatted string: %s\n", buffer);
// Print the number of characters that would have been written
printf("Number of characters: %d\n", n);
return 0;
}
- Using
find_max
in main.
Get the flag by running
tester
and passing all the tests.
Objective
I'm learning to program, please explain every step to me like I'm a child but make it fun
Create a function in
data.h
and
data.c
that will load the data from items.json into a heap based array.
Your code is automatically copied from the prior level.
- Implementing the the item list in
main()
- To store all the items we need to create a heap-based array in
main()
struct Item *items_list;
- The list will be loaded inside
load_json_items
- After the arrays are loaded the program will print
printf("%d %s\n", items_list[0].id, items_list[0].name);
printf("%s\n", items_list[0].description);
printf("%d %s\n", items_list[378].id, items_list[378].name);
printf("%s\n", items_list[378].description);
printf("%d %s \n", items_list[1697].id, items_list[1697].name);
printf("%s\n", items_list[1697].description);
- Declare
load_json_items
in data.h
and define it in data.c
Item * load_json_items(char * filename, int itemMaxId)
- This function will allocate the memory on the heap for the items (using maxItemId +1 and the size of the Item struct)
- Create an initialized struct where the id = -1, the name = NULL, and description =NULL
- Initialize all the structs in item_list by looping through all the locations and copying an initialized struct to each location
- Read through the file and build a struct for each record
- For each field in the file, we will need to extract the value portion of the record
{
"id": 1,
"name": "bottle beer",
"description": "A beer bottle has been left here."
}
- The function will read line-by-line and must load the struct until it reaches the end of the record
- For each line containing a field, the line contains a key and a value separated by a colon
"id": 1
- For each line, match the key to the struct field, extract the value, and load it in the proper field in the struct
- The code should match the key in the line to the known keys
- If using a search in string method such as
strstr
- When matching the keys include the double quotes in the search string. By including them it will prevent the program from matching a key that occurs in the description fields
strstr(line, "\"id\");
- Extract the line's value, the program should implement an extract_int and extract_string that will return the extracted value
-
extract_string
might use strdup
to allocate the extracted string on the heap
-
extract_int
should handle a numerical value and return -1 if the value is null
- Store the extracted value in the current struct.
- When reaching the end of the record, the program will have a completely loaded struct
- After building the struct for an item, add the item to the array, using the items's ID as the index in the array. This is why we use maxItemId + 1 to allocate the heap-based array's memory, so it'll have an available location for all the IDs up to the max.
- Return the address of the newly defined and loaded rooms heap array
It is required to add a comment that "the load_json_items function is done via filename and via itemMaxId as an integer"
- Get the flag by running
tester
and passing all the tests.
Objective
I'm learning to program, please explain every step to me like I'm a child but make it fun
Create a function in
data.h
and
data.c
that will load the data from rooms.json into a heap based array.
Your code is automatically copied from the prior level.
- Implementing the the room lists in
main()
- To store all the rooms we need to create a heap-based array in
main()
struct Room *rooms_list;
- The list will be loaded inside
load_json_rooms
- After the arrays are loaded the program will print
printf("%d %s \n %s \n", rooms_list[5].id, rooms_list[5].name, rooms_list[5].description);
printf("%d %s \n %s\n", rooms_list[359].id, rooms_list[359].name, rooms_list[359].description);
- Declare
load_json_rooms
in data.h
and define it in data.c
Room * load_json_rooms(char * filename, int roomMaxId)
- This function will allocate the memory on the heap for the rooms (using maxRoomId +1 and the size of the Room struct)
- Create an initialized struct where the id = -1, the name = NULL, and description =NULL, north=-1, south=-1, west=-1, east=-1, item=-1, and starting=0
- Initialize all the structs in rooms_list by looping through all the locations and copying an initialized struct to each location
- Read through the file and build a struct for each record
- For each field in the file, we will need to extract the value portion of the record
{
"id": 1,
"name": "The temple of Mota",
"description": "You are in the southern end of the temple hall in the Temple of Mota....",
"north": 2,
"south": null ...
}
- The function will read line-by-line and must load the struct until it reaches the end of the record similar to what was done for the items
- After building the struct for a room, add the room to the array, using the room's ID as the index in the newly created array. This is why we use maxRoomId + 1 to allocate the heap-based array's memory, so it'll have an available location for all the IDs up to the max.
- Return the address of the newly defined and loaded rooms heap array
It is required to add a comment that "the load_json_rooms function is done via filename and via itemMaxRoomId an integer"
- Get the flag by running
tester
and passing all the tests.
Objective
Free all the heap based memory that was used.
Free the heap memory
- Free all the c-string pointers inside each of the structs in the lists
- Free the lists
Objective
Use the data loaded in the prior stage to show the current room and available exits.
Your code is automatically copied from the prior level.
- The Makefile
- Add operations.h to the Makefile
- Starting the game in
main()
- Load rooms_list and items_list
- Start the player in room ID 1.
- Call the function
game_loop()
, which is defined in operations.h
- Declare
game_loop()
in operations.h
and define it in operations.c
void game_loop(Room rooms[], Item items[], int startingRoomId)
- For now, it'll be a game singleton, meaning, it will only show the first room
#1 : The Temple Of Mota
You are in the southern end of the temple hall in the Temple of Mota. The temple has been constructed from giant
marble blocks, eternal in appearance, and most of the walls are covered by ancient wall paintings picturing gods,
giants and peasants. Large steps lead down through the grand temple gate, descending the huge mound upon which
the temple is built and ends on the temple square below. A small plaque is on this wall.
You see a scimitar blade
[ [n]orth, [s]outh, [q]uit ]
> south
#5 : The Temple Square
You are standing on the temple square. Huge marble steps lead up to the temple gate. The entrance to the Clerics Guild is to the west, and the old Grunting Boar Inn, is to the east. Just south of here you see the market square, the center of Midgaard.
You see a huge rubber duck
[ [n]orth, [s]outh, [e]ast, [w]est, [q]uit ]
>
- Get the flag by running
tester
and passing all the tests.
Objective
Improve the game_loop to allow the user to enter multiple commands
- Looping the game
- Addig Commands
- Option:
q
or quit
- Print the message "Exiting game"
- Break out of the loop
- Option: direction (
n
, s
, e
, w
)
- Change the players location based on the value in the current room's north, south, east, west value
- If direction is invalid return an "invalid direction" message
- If command was not a valid option display "Invalid command"
- Sample Session
#1 : The Temple Of Mota
You are in the southern end of the temple hall in the Temple of Mota. ...
[ [n]orth, [s]outh, [q]uit ]
> s
#5 : The Temple Square
You are standing on the temple square. Huge marble steps lead up to the temple gate. ...
[ [n]orth, [s]outh, [e]ast, [w]est, [q]uit ]
> w
#4 : Entrance to Cleric's Guild
The entrance hall is a small modest room, reflecting the true nature of the Clerics. ...
[ [n]orth, [e]ast, [q]uit ]
> q
- Get the flag by running
tester
and passing all the tests.
Objective
Add commands for getting items off the ground and viewing the player's inventory
Your code is automatically copied from the prior level.
This level will need to create a data structure to store the player's inventory. The inventory variable may be a simple array of 100 integers (the integers will store the item_id that's in the players inventory).
It may also be a global variable within operations.c.
- Add command legend to the exits
- Update command legend to include [g]et and [i]nventory
[ [n]orth, [s]outh, [g]et, [i]nventory [q]uit ]
- Add the two commands
- After each command re-display the room information
-
Get
or g
- A 'get' or 'g' will pick up the item, removing it from the room by setting the room's item to -1 and putting it into the player's inventory.
- The program must say "You picked up a " followed by the name of the item picked up
- The item should no longer be displayed in the room (maybe make the room.item = -1)
- The item should now be in the player's inventory
-
Inventory
or i
- Displays the items that are in a player's inventory (i.e., the player's backpack).
- On display, the backpack will
- Example Inventory
Your backpack of infinite holding contains:
+ [5] scimitar blade
+ [10] pit
+ [135] fountain water
+ [365] banner war merc
+ [22] sword long
- Sample Session
#1 : The Temple Of Mota
You are in the southern end of the temple hall in the Temple of Mota. ...
You see a scimitar blade
[ [n]orth, [s]outh, [l]ook, [g]et, [i]nventory, [d]rop, [q]uit ]
> get
You picked up a scimitar blade and put it into your backpack
#1 : The Temple Of Mota
You are in the southern end of the temple hall in the Temple of Mota. ...
[ [n]orth, [s]outh, [l]ook, [g]et, [i]nventory, [d]rop, [q]uit ]
> s
#5 : The Temple Square
You are standing on the temple square. Huge marble steps lead up to the temple gate. ...
You see a rubber duck
[ [n]orth, [s]outh, [e]ast, [w]est, [l]ook, [g]et, [i]nventory, [d]rop, [q]uit ]
> i
Your backpack of infinite holding contains:
+ [5] scimitar blade
- Get the flag by running
tester
and passing all the tests.
Objective
Add commands for dropping items on to the ground and looking at items that are on the ground.
Your code is automatically copied from the prior level.
- Update command legend to include [l]ook and [d]rop
- Add new commands
- Drop or d
- After user initiates a drop, the game MUST display the player's inventory
- It will prompt the user to enter the item ID of the item the player would like to drop
- If the value entered by the player is not in the backpack then the game should print "Item does not exist in backpack".
- If value entered matches an item in the player's inventory, then
- remove the item ID from the player's inventory
- Assign the item Id to the the current room, room[X].item = itemId
- Only 1 item can be on the floor in a room at a time
- If an item is dropped in a room that already has an item in it, then the dropped item will overwrite the current item. In other words, the room.item field can be an integer and does not need to be an array.
-
Look
or l
- Looks at an item that's laying on the floor in a room.
- It prints the item's description
- Use the ./modelGood.bin to explore the functionality further, try getting items, looking at inventory, and dropping items.
- Get the flag by running
tester
and passing all the tests.
30-Day Scoreboard:
This scoreboard reflects solves for challenges in this module after the module launched in this dojo.