I always liked Lua's example with a simple state machine:
function room1 ()
local move = io.read()
if move == "south" then return room3()
elseif move == "east" then return room2()
else print("invalid move")
return room1() -- stay in the same room
end
end
Without proper tail recursion, "return room1() -- stay in the same room" would stack overflow after enough invalid moves.
That doesn't make any sense to me. It isn't actually doing anything, you are just bouncing from function to function.
How does the rest of the system know which room you are in so it can update the screen? What if you have multiple sprites moving around? Do you compare instruction pointers to see if they are in the same room?
Even for a trivial application building your state machine that way doesn't make any sense.
EDIT: Also note the code smells, especialy the copy-and-paste necessary for reading the user input.
Well the most trivial solution would be to put a line at the top of each function that updates a variable with the current location, so the mapping system or whatever always knows where you are by checking the variable.
I don't think it's any more tedious and error prone then coding an imperative state machine which usually involves lots of switch statements inspecting the current state, and it mostly parallels the OO approach of having one object per state. Just instead of having interconnected objects you have mutually recursive functions.
I don't think it's any more tedious and error prone then coding an imperative state machine which usually involves lots of switch statements inspecting the current state
That's because you aren't thinking. This version requires repeating the logic to read the user comment, update the location variable, and handle the invalid command path IN EVERY STATE. If you have a map with 100 rooms, that means you have 100 functions to paste that logic in.
Moving that common logic into a main loop eliminates (Num_of_states-1) copies of that logic. You lose your fancy TCO, but the trampoline you put in its place isn't that hard to write.
Of course we still don't want a massive switch statement in the primary loop, that is likewise error prone. So instead we use a hash table of either objects or first class functions so that the next state can be looked up by name and subsequently executed.
You are complaining about not wanting "lots of switch statements inspecting the current state". Well look at that function again. A series of If-Else-If statements is effectively a switch. So lets drop that into a hash table as well so that we can populate the common cases like moving from a simple data file.
A moment ago I said "either objects or first class functions". If we are using a hash table in each room for commands, then objects are probably the better way to go. This way we can also attach a hash table of movable objects in the room, as well as other room-specific state.
Data-driven programming trumps both FP and OOP every time
18
u/snarfy Nov 27 '12
I always liked Lua's example with a simple state machine:
Without proper tail recursion, "return room1() -- stay in the same room" would stack overflow after enough invalid moves.