How to write web-based strategy games

A work in progress by Robert Laing

State Representation

true(T).

% include(<(5), [3,4,5,6,7], As).
% 5 < 6 ie <(5, X)
% As = [6, 7].
% exclude(<(5), [3,4,5,6,7], As).
% As = [3, 4, 5].

Game Description Language

Keywords

Wolf, Goat, Cabbage Problem

role(farmer).

init(left(wolf)).
init(left(cabbage)).
init(left(goat)).
init(left(farmer)).

legal(farmer, boat(wolf)) :- true(left(farmer)), true(left(wolf)), \+((true(left(cabbage)), true(left(goat)))).
legal(farmer, boat(wolf)) :- true(right(farmer)), true(right(wolf)), \+((true(right(cabbage)), true(right(goat)))).
legal(farmer, boat(cabbage)) :- true(left(farmer)), true(left(cabbage)), \+((true(left(wolf)), true(left(goat)))).
legal(farmer, boat(cabbage)) :- true(right(farmer)), true(right(cabbage)), \+((true(right(wolf)), true(right(goat)))).
legal(farmer, boat(goat)) :- true(left(farmer)), true(left(goat)).
legal(farmer, boat(goat)) :- true(right(farmer)), true(right(goat)).
legal(farmer, boat(empty)) :- true(left(farmer)), \+((true(left(cabbage)), true(left(goat)))).
legal(farmer, boat(empty)) :- true(left(farmer)), \+((true(left(wolf)), true(left(goat)))).
legal(farmer, boat(empty)) :- true(right(farmer)), \+((true(right(cabbage)), true(right(goat)))).
legal(farmer, boat(empty)) :- true(right(farmer)), \+((true(right(wolf)), true(right(goat)))).

next(left(X)) :- does(farmer, boat(X)), true(right(X)).
next(right(X)) :- does(farmer, boat(X)), true(left(X)).
next(left(farmer)) :- true(right(farmer)).
next(right(farmer)) :- true(left(farmer)).
next(left(X)) :- true(left(X)), \+(next(right(X))).
next(right(X)) :- true(right(X)), \+(next(left(X))).

goal(farmer, 100) :-
  true(right(wolf)),
  true(right(cabbage)),
  true(right(goat)),
  true(right(farmer)).

terminal :- goal(farmer, 100). 
% My functions

findinits(Inits) :-
  setof(Init, init(Init), Inits).

update_state(State) :-
  retractall(true(_)),
  forall(member(X, State), assertz(true(X))).

findlegals(Role, State, Legals) :-
  update_state(State),
  setof(does(Role, Legal), legal(Role, Legal), Legals).

findnext(State, does(Role, Move), Next) :-
  update_state(State),
  retractall(does(_,_)),
  assert(does(Role, Move)),
  setof(Proposition, next(Proposition), Next).

findnexts(State, Nexts) :-
  findlegals(farmer, State, Legals),
  maplist(findnext(State), Legals, Nexts).

filter_duplicates(List, X) :-
  memberchk(X, List).

solve_dfs([State|Frontier], History, Path) :-
  writeln(State),
  update_state(State),
  \+terminal,
  findnexts(State, Nexts),
  exclude(filter_duplicates(History), Nexts, Nexts1),
  append(Nexts1, Frontier, Frontier1),
  append([State], History, History1),
  solve_dfs(Frontier1, History1, [State|Path]).

solve_dfs([State|_Frontier], [_History], [State]) :-
  update_state(State),
  % writeln(State),
  goal(farmer, 100).


?- findinits(Init), solve_dfs([Init], [Init], Path).
[left(cabbage),left(farmer),left(goat),left(wolf)]
[left(cabbage),left(wolf),right(farmer),right(goat)]
[left(cabbage),left(farmer),left(wolf),right(goat)]
[left(wolf),right(cabbage),right(farmer),right(goat)]
[left(farmer),left(wolf),right(cabbage),right(goat)]
[right(cabbage),right(farmer),right(goat),right(wolf)]
false.

Markdown Cheatsheet

markdown2 --extras fenced-code-blocks game_framework.md > index.html