RCRPG/Oz

From Rosetta Code
RCRPG/Oz is part of RCRPG. You may find other members of RCRPG at Category:RCRPG.

This Oz version of RCRPG implements a text interface.

It is a purely functional implementation, i.e. the state of the world is passed as an argument to functions. If a function modifies the world, a new version is returned.

It implements the same commands as the other implementations (no "alias", "name" or "help" commands, though).

Code[edit]

declare
%% Basic data structures
 
fun {CreateWorld Goal}
world(goal:Goal
position:[0 0 0]
equipped:empty
inventory:nil
status:nil
%% initially we only have one room
%% coords: X Y Z
rooms:unit(0:unit(0:unit(0:{CreateRoom sledge})))
)
end
 
fun {CreateRoom InitialItem}
room(items:[InitialItem]
north:wall
south:wall
east:wall
west:wall
up:wall
down:wall)
end
 
%% COMMANDS (and shortcuts)
fun {CreateCommandTable}
Commands =
unit(north: {Curry1of2 Go north} n:Commands.north
south: {Curry1of2 Go south} s:Commands.south
east: {Curry1of2 Go east} e:Commands.east
west: {Curry1of2 Go west} w:Commands.west
up: {Curry1of2 Go up} u:Commands.up
down: {Curry1of2 Go down} d:Commands.down
attack:Attack a:Commands.attack
drop: Drop
take: Take
inventory:Inventory i:Commands.inventory
inv: Commands.inventory
equip: Equip
)
in
Commands
end
CommandTable = {Value.byNeed CreateCommandTable}
 
%% The game loop.
proc {Loop World0}
{PrintStatus World0}
World = {SetStatus World0 nil}
in
if World.position == World.goal then
{System.showInfo "You are now in the goal room. You have won the game!"}
else
{System.printInfo ">"}
%% Read and parse user input
Tokens = {Map {String.tokens {ReadLine} & } String.toAtom}
in
if Tokens == nil then %% repeat room description when user just presses enter
{Loop World}
else
ComName|Args = Tokens
in
if {Not {HasFeature CommandTable ComName}} then
{Loop {SetStatus World "Unknown command."}}
else
ComFunction = CommandTable.ComName
in
%% check for number of args (+2: "World" in and out)
if {Procedure.arity ComFunction} \= 2 + {Length Args} then
{Loop {SetStatus World "Wrong number of arguments."}}
else
WorldAfterCommand
in
%% dynamically call ComFunction
%% (statically unknown number of arguments)
{Procedure.apply ComFunction World|{Append Args [WorldAfterCommand]}}
{Loop WorldAfterCommand}
end
end
end
end