RCRPG/Nim
This Nim version proposes the following commands:
– alias <alias name> <command>: define an alias.
– aliases: list aliases.
– attack <direction>: use sledge to dig a tunnel in the given direction.
– drop all | <item>: drop all items or a specified item.
– east: move to East.
– equip <item>: equip an item present in inventory.
– help: display the list of commands and directions.
– inventory: list items in the inventory.
– look: display location, items and exits.
– name <name>: give a name to the current room.
– north: move to North.
– south: move to South.
– quit: quit game.
– take all | <item>: take all items or a specified item.
– unequip: unequip the equipped item.
– west: move to West.
Directions are: north, east, south, west, up, down.
Code
<lang Nim> import random import strformat import strutils import tables
type
Direction = enum nowhere, north, east, south, west, up, down Item = enum none, sledge, ladder, gold, all
Position = tuple[x, y, z: int] Delta = Position
Room = ref object game: Game pos: Position items: seq[Item] passages: array[Direction, bool]
Game = ref object pos: Position rooms: Table[Position, Room] roomNames: Table[Position, string] aliases: Table[string, string] inventory: seq[Item] equipped: Item
const
IncPos: array[Direction, Delta] = [(0, 0, 0), (0, -1, 0), (1, 0, 0), (0, 1, 0), (-1, 0, 0), (0, 0, 1), (0, 0, -1)]
OppositeDir: array[Direction, Direction] = [nowhere, south, west, north, east, down, up]
# Command names and number of tokens required for this command. Commands = {"alias": 3, "aliases": 1, "quit": 1, "name": 2, "look": 1, "help": 1, "north": 1, "east": 1, "south": 1, "west": 1, "up": 1, "down": 1, "attack": 2, "inventory": 1, "take": 2, "drop": 2, "equip": 2, "unequip": 1}.toTable()
StartRoomPos: Position = (0, 0, 0) PrizeRoomPos: Position = (1, 1, 5)
- Miscellaneous.
func nextPos(oldPos: Position; direction: Direction): Position =
## Compute new coordinates from current position and direction. (oldPos.x + IncPos[direction].x, oldPos.y + IncPos[direction].y, oldPos.z + IncPos[direction].z)
- ___________________________________________________________________________________________________
proc randomItems(): seq[Item] =
## Select randomly the items for a room. ## At most one sledge, one ladder and one gold. for item in [sledge, ladder, gold]: if rand(1) != 0: result.add(item)
- ___________________________________________________________________________________________________
template toItem(token: string): Item =
## Return item from token. parseEnum[Item](token.toLower, none)
- ___________________________________________________________________________________________________
template toDirection(token: string): Direction =
## Return direction from token. parseEnum[Direction](token.toLower, nowhere)
- ___________________________________________________________________________________________________
proc displayHelp() =
## Display help about commands. echo "Commands:" echo "– alias <alias name> <command>: define an alias." echo "– aliases: list aliases." echo "– attack <direction>: use sledge to dig a tunnel in the given direction." echo "– drop all | <item>: drop all items or a specified item." echo "– east: move to East." echo "– equip <item>: equip an item present in inventory." echo "– help: display this help." echo "– inventory: list items in the inventory." echo "– look: display location, items and exits." echo "– name <name>: give a name to the current room." echo "– north: move to North." echo "– south: move to South." echo "– quit: quit game." echo "– take all | <item>: take all items or a specified item." echo "– unequip: unequip the equipped item." echo "– west: move to West." echo "\nDirections:" echo "– north, east, south, west, up, down"
- Room.
func description(room: Room): string =
## Return the description of a room.
result = "You are at " if room.pos in room.game.roomNames: result.add(room.game.roomNames[room.pos]) else: result.add(fmt"{room.pos.x}, {room.pos.y}, {room.pos.z}") if room.items.len > 0: result.add("\nOn the ground you can see: " & room.items.join(", ")) result.add("\nExits are: ") var exits: seq[string] for dir, passage in room.passages: if passage: exits.add(($dir).capitalizeAscii()) result.add(if exits.len > 0: exits.join(", ") else: "None")
- ___________________________________________________________________________________________________
proc take(room: Room; item: Item): seq[Item] =
## Take an item in a room. if item == all: result = room.items room.items.setLen(0) echo "You now have everything in the room." else: let idx = room.items.find(item) if idx >= 0: room.items.delete(idx) result = @[item] echo "Taken ", item, "." else: echo "Item not found."
- Game.
proc newGame(): Game =
## Initialize a game. new(result) # Create rooms. result.rooms[StartRoomPos] = Room(game: result, pos: StartRoomPos, items: @[sledge]) result.rooms[PrizeRoomPos] = Room(game: result, pos: PrizeRoomPos, items: @[gold, gold, gold, gold, gold]) # Create room names. result.roomNames = {StartRoomPos: "the starting room", PrizeRoomPos: "the prize room"}.toTable() # Create aliases. result.aliases = {"n": "north", "e": "east", "s": "south", "w": "west", "u": "up", "d": "down", "a": "attack", "i": "inventory", "l": "look"}.toTable()
- ___________________________________________________________________________________________________
proc createAlias(game: Game; newAlias, command: string) =
## Create an alias for a command. if command in game.aliases: echo "You cannot alias an alias." return game.aliases[newAlias] = command echo "Alias created."
- ___________________________________________________________________________________________________
proc listAliases(game: Game) =
## List the defined aliases. for alias, command in game.aliases.pairs: echo fmt"{alias}: {command}"
- ___________________________________________________________________________________________________
proc look(game: Game) =
## Look at current room and display description. echo game.rooms[game.pos].description()
- ___________________________________________________________________________________________________
proc move(game: Game; direction: Direction) =
## Move in a direction. if direction == up and ladder notin game.rooms[game.pos].items: echo "You’ll need a ladder in this room to go up." return if game.rooms[game.pos].passages[direction]: game.pos = nextPos(game.pos, direction) else: echo "Can’t go that way."
- ___________________________________________________________________________________________________
proc displayInventory(game: Game) =
## Display the inventory. if game.inventory.len == 0: echo "You aren’t carrying anything." else: echo "Carrying: ", join(game.inventory, ", "), "." if game.equipped != none: echo "Holding: ", game.equipped, "."
- ___________________________________________________________________________________________________
proc take(game: Game; item: Item) =
## Take an item. game.inventory &= game.rooms[game.pos].take(item)
- ___________________________________________________________________________________________________
proc drop(game: Game; item: Item) =
## Drop an item. if item == all: game.rooms[game.pos].items.add(game.inventory) game.inventory.setLen(0) echo "Everything dropped." else: let idx = game.inventory.find(item) if idx >= 0: game.inventory.delete(idx) game.rooms[game.pos].items.add(item) echo "Dropped ", item, "." else: echo "Could not find item in inventory."
- ___________________________________________________________________________________________________
proc unequip(game: Game) =
## Unequip an item. if game.equipped == none: echo "You aren’t equipped with anything." else: game.inventory.add(game.equipped) echo "Unequipped ", game.equipped, "." game.equipped = none
- ___________________________________________________________________________________________________
proc equip(game: Game; item: Item) =
## Equip an item. let idx = game.inventory.find(item) if idx >= 0: if game.equipped != none: game.unequip() game.inventory.delete(idx) game.equipped = item echo "Equipped ", item, "." else: echo "You aren’t carrying that."
- ___________________________________________________________________________________________________
proc name(game: Game; newRoomNameTokens: varargs[string]) =
## Name a room. game.roomNames[game.pos] = newRoomNameTokens.join(" ")
- ___________________________________________________________________________________________________
proc dig(game: Game; direction: Direction) =
## Dig in a direction. if game.equipped != sledge: echo "You don’t have a digging tool equipped." return if not game.rooms[game.pos].passages[direction]: game.rooms[game.pos].passages[direction] = true let newRoomPos = nextPos(game.pos, direction) if newRoomPos notin game.rooms: game.rooms[newRoomPos] = Room(game: game, pos: newRoomPos, items: randomItems()) game.rooms[newRoomPos].passages[OppositeDir[direction]] = true echo "You have dug a tunnel." else: echo "There’s already a tunnel that way."
- Main.
randomize() # Initialize the random generator. let game = newGame()
echo "Welcome to the dungeon!" echo "Grab the sledge and make your way to room 1,1,5 for treasure!"
while true:
game.look() if game.pos == PrizeRoomPos: echo "You have found the prize room and the treasure!" break stdout.write("> ") var line: string if not stdin.readLine(line): break # End of file. var tokens = line.strip().toLower.split()
# Replace alias by the command. if tokens[0] in game.aliases: tokens[0] = game.aliases[tokens[0]] # Check command.
if tokens[0] notin Commands: echo "Invalid command." continue if tokens.len != Commands[tokens[0]]: echo "Wrong number of parameters." continue
# Process command. case tokens[0] of "alias": game.createAlias(tokens[1], tokens[2]) of "aliases": game.listAliases() of "name": game.name(tokens[1]) of "look": game.look() of "north", "east", "south", "west", "up", "down": game.move(tokens[0].toDirection) of "inventory": game.displayInventory() of "take": game.take(tokens[1].toItem) of "drop": game.drop(tokens[1].toItem) of "equip": game.equip(tokens[1].toItem) of "unequip": game.unequip() of "attack": let dir = tokens[1].toDirection if dir == nowhere: echo "Wrong direction." else: game.dig(dir) of "help": displayHelp() of "quit": break
echo "Thanks for playing" </lang>