Last active
December 25, 2024 21:40
-
-
Save rhmoller/00d92aa81f7a4a07ac8ba70a34cf52cd to your computer and use it in GitHub Desktop.
A small adventure game written to explore the C3 language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// compile and run with | |
// c3c compile-run adventure.c3 | |
import std::ascii; | |
import std::collections; | |
import std::io; | |
struct Item | |
{ | |
String name; | |
String description; | |
} | |
def ListItem = List(<Item>); | |
struct Room | |
{ | |
String name; | |
String description; | |
int[4] doors; | |
ListItem items; | |
} | |
const Room[] ROOMS = | |
{ | |
{ | |
"The Void", | |
"You should not be able to get here", | |
{0, 0, 0, 0}, | |
{} | |
}, | |
{ | |
"Room 1", | |
"There is a door to the north.", | |
{2, 0, 0, 0}, | |
{} | |
}, | |
{ | |
"Room 2", | |
"There is a door to the south.", | |
{0, 1, 0, 0}, | |
{} | |
} | |
}; | |
const Item[][] ROOM_ITEMS = { | |
{}, | |
{ | |
{"key", "A rusty old key"}, | |
{"torchlight", "A neat torchlight"} | |
}, | |
{} | |
}; | |
int current_room = 1; | |
ListItem inventory; | |
fn void initialize_world() | |
{ | |
foreach (i, &room : ROOMS) | |
{ | |
Item[] items = ROOM_ITEMS[i]; | |
foreach (item : items) | |
{ | |
room.items.push(item); | |
} | |
} | |
} | |
fn void enter_room(int room) | |
{ | |
current_room = room; | |
describe_room(); | |
} | |
fn void describe_room() | |
{ | |
Room* room = &ROOMS[current_room]; | |
io::printfn("You are in %s", room.name); | |
io::printn(room.description); | |
ListItem items = room.items; | |
if (items.len() > 0) | |
{ | |
io::printn("You see:"); | |
for (int i = 0; i < items.len(); i++) | |
{ | |
io::printfn(" %s", items[i].name); | |
} | |
} else { | |
io::printn("There is nothing here."); | |
} | |
} | |
fn void enter_door(int direction) | |
{ | |
Room* room = &ROOMS[current_room]; | |
int door = room.doors[direction]; | |
if (door != 0) | |
{ | |
enter_room(door); | |
} | |
else | |
{ | |
io::printn("You can't go that way."); | |
} | |
} | |
fn void take_item(String name) | |
{ | |
Room* room = &ROOMS[current_room]; | |
foreach (i, item : room.items) | |
{ | |
if (item.name == name) | |
{ | |
inventory.push(item); | |
room.items.remove_at(i); | |
io::printfn("You take the %s", name); | |
return; | |
} | |
} | |
io::printfn("There is no %s here.", name); | |
} | |
fn void examine_item(String name) { | |
foreach (i, item : inventory) | |
{ | |
if (item.name == name) | |
{ | |
io::printn(item.description); | |
return; | |
} | |
} | |
Room* room = &ROOMS[current_room]; | |
foreach (i, item : room.items) | |
{ | |
if (item.name == name) | |
{ | |
io::printn(item.description); | |
return; | |
} | |
} | |
} | |
fn void drop_item(String name) { | |
foreach (i, item : inventory) | |
{ | |
if (item.name == name) | |
{ | |
Room* room = &ROOMS[current_room]; | |
room.items.push(item); | |
inventory.remove_at(i); | |
io::printfn("You drop the %s", name); | |
return; | |
} | |
} | |
io::printfn("You are not carrying a %s.", name); | |
} | |
fn void describe_inventory() | |
{ | |
if (inventory.len() == 0) | |
{ | |
io::printn("You are not carrying anything."); | |
} | |
else | |
{ | |
io::printn("You are carrying:"); | |
for (int i = 0; i < inventory.len(); i++) | |
{ | |
io::printfn(" %s", inventory[i].name); | |
} | |
} | |
} | |
fn void help() | |
{ | |
io::printn("Available Commands: go <direction>, north, south, east, west, look, examine, take <item>, drop <item>, inventory, exit"); | |
} | |
fn bool! next_cmd() | |
{ | |
io::print("> "); | |
String command = io::treadline()!; | |
// todo: figure out how to convert command to lowercase | |
String[] tokens = command.tsplit(" "); | |
for (int i = 0; i < tokens.len; i++) | |
{ | |
switch (tokens[i]) | |
{ | |
case "help": | |
help(); | |
case "go": | |
continue; | |
case "north": | |
enter_door(0); | |
case "south": | |
enter_door(1); | |
case "east": | |
enter_door(2); | |
case "west": | |
enter_door(3); | |
case "look": | |
describe_room(); | |
case "examine": | |
if (tokens.len < i + 2) | |
{ | |
io::printn("You must specify an item to examine."); | |
continue; | |
} | |
examine_item(tokens[i + 1]); | |
i++; | |
case "take": | |
if (tokens.len < i + 2) | |
{ | |
io::printn("You must specify an item to take."); | |
continue; | |
} | |
take_item(tokens[i + 1]); | |
i++; | |
case "drop": | |
if (tokens.len < i + 2) | |
{ | |
io::printn("You must specify an item to drop."); | |
continue; | |
} | |
drop_item(tokens[i + 1]); | |
i++; | |
case "inventory": | |
describe_inventory(); | |
case "exit": | |
case "quit": | |
case "bye": | |
io::printn("Goodbye!"); | |
return false; | |
default: | |
io::printn("I don't understand that command."); | |
} | |
} | |
return true; | |
} | |
fn void! main() | |
{ | |
mem::@report_heap_allocs_in_scope() | |
{ | |
io::printn("Welcome to the Adventure Game!"); | |
initialize_world(); | |
enter_room(1); | |
bool running = true; | |
while (running) | |
{ | |
@pool() | |
{ | |
running = next_cmd()!; | |
}; | |
} | |
inventory.free(); | |
foreach (&room : ROOMS) | |
{ | |
room.items.free(); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment