Simple FSM Game in Prolog

We have done some Prolog in my programming languages class recently, so I’ve been doing some additional reading this weekend for kicks. I actually have some background in rule-based system, primarily using Jess (look for my name in the credits of Jess In Action, I submitted a few bug reports/fixes so got to see my name in print ha).

I saw a reference to ai-junkie somewhere and read through the “Agents” section and thought I would have a go at building a simple finite state machine game in Prolog based on the Miner Bob example found here, specifically in Figure 2.2.

I’m not sure if this is the best way to do this in Prolog, this approach will eventually fail for long enough games since the stack just keeps growing.

/*
  Simple FSM based on
  http://www.ai-junkie.com/architecture/state_driven/tut_state1.html

  Player data structure looks like:
  player(wealth, thirst, banked).
*/

/* Game parameters */
goal(20).
maxThirst(3).
maxInventory(4).
rateThirst(1).
rateMine(2).

% debug helper which just dumps player information
debug(P) :-
  write(P),nl.

% The home state, where we start and end the game.
state(home, player(Wealth,Thirst,Banked)) :-
  write('Home'),nl,
  (Banked =:= 0 ->
    fire(state(home), event(rested), player(Wealth,Thirst,Banked));
    write('Retirement!'),nl,
    debug(player(Wealth,Thirst,Banked))).

% The bank state, where wealth is deposited and our banked amount checked
state(bank, player(Wealth,Thirst,Banked)) :-
  write('Bank'),nl,
  B is Wealth + Banked,
  P = player(0,Thirst,B),
  goal(G),
  (B < G ->
    fire(state(bank), event(not_wealthy), P);
    fire(state(bank), event(wealth), P)).

% The mining state where we do our work, generating wealth and thirst
state(mine, player(Wealth,Thirst,Banked)) :-
  write('Mining'),nl,
  rateMine(Rm),
  rateThirst(Rt),
  W is Wealth+Rm,
  T is Thirst+Rt,
  P = player(W,T,Banked),
  maxThirst(MaxThirst),
  maxInventory(MaxInv),
  (T >= MaxThirst -> fire(state(mine), event(thirsty), P);
    (W >= MaxInv ->
      fire(state(mine), event(deposit), P);
      fire(state(mine), event(not_wealthy), P))).

% The quenching state, wherein we slake our thirst.
state(quench, player(Wealth,_,Banked)) :-
  write('Drinking'),nl,
  fire(state(quench), event(not_thirsty), player(Wealth,0,Banked)).

% Definitions of our state transitions and event
transition(state(home),   event(rested),      state(mine)).
transition(state(mine),   event(deposit),     state(bank)).
transition(state(mine),   event(thirsty),     state(quench)).
transition(state(mine),   event(not_wealthy), state(mine)).
transition(state(quench), event(not_thirsty), state(mine)).
transition(state(bank),   event(wealth),      state(home)).
transition(state(bank),   event(not_wealthy), state(mine)).

% Fires a state transition event and transfers us to the next state.
fire(state(S), event(E), P) :-
  write('\tStatus: '), debug(P),
  transition(state(S),event(E),state(NextState)),
  state(NextState, P).

% Starts the game!
start :-
  P = player(0, 0, 0),
  state(home, P).

Running it looks like:

| ?- start.
Home
Status: player(0,0,0)
Mining
Status: player(2,1,0)
Mining
Status: player(4,2,0)
Bank
Status: player(0,2,4)
Mining
Status: player(2,3,4)
Drinking
Status: player(2,0,4)
Mining
Status: player(4,1,4)
Bank
Status: player(0,1,8)
Mining
Status: player(2,2,8)
Mining
Status: player(4,3,8)
Drinking
Status: player(4,0,8)
Mining
Status: player(6,1,8)
Bank
Status: player(0,1,14)
Mining
Status: player(2,2,14)
Mining
Status: player(4,3,14)
Drinking
Status: player(4,0,14)
Mining
Status: player(6,1,14)
Bank
Status: player(0,1,20)
Home
Retirement!
player(0,1,20)

One thought on “Simple FSM Game in Prolog”

Leave a Reply