sw-examples: walking-ant.sw3
Raw file here.
-- learn and randomly walk a grid
-- keep a record of the pathway home, so we can walk directly towards home (a kind of path integration)
-- if find food return home, leaving a scent trail
-- once home, follow scent trail back to food (approximately)
-- if find food again, return home, adding to the scent trail
-- when reach home, store the food, switch off scent trail, and start randomly walking again
-- minimally updated to the version 3.1.1 language
-- define our ant symbol:
-- the |ant> => |###>
the |ant> => |@##@>
-- learn the grid:
learn-grid[30, 30]
-- define max steps per invocation of "walk":
max |steps> => |400>
-- learn current location:
current |cell> => |grid: 10: 22>
-- learn home location:
home |cell> => current |cell>
-- learn ant location:
location |ant> => home |cell>
-- start with no food at home:
stored-food home |cell> => |0>
-- learn the list of directions:
list-of |directions> => |op: N> + |op: NE> + |op: E> + |op: SE> + |op: S> + |op: SW> + |op: W> + |op: NW>
-- the learn path home operator:
-- NB: we use add-learn instead of seq-learn so that directions can add up
-- Ie, a type of path integration
store-direction (*) #=>
path |home> +=> |__self>
-- find return path:
-- "invert-direction" and "expand" operators are defined down lower:
return-path |home> #=>
invert-direction expand path |home>
-- choose a heading when leaving the nest:
heading |ops> => pick-elt list-of |directions>
-- start by not carrying any food:
carry |food> => |0>
-- start with scent trail off:
lay |scent> => |no>
-- start with random walk type:
type |walk> => |op: random-walk>
-- place some food:
food |grid: 2: 2> => |3>
food |grid: 2: 3> => |3>
food |grid: 2: 4> => |3>
food |grid: 2: 5> => |3>
food |grid: 3: 5> => |3>
food |grid: 4: 5> => |3>
food |grid: 5: 6> => |3>
food |grid: 6: 6> => |3>
food |grid: 29: 29> => |20>
food |grid: 28: 3> => |20>
-- show food operator:
show-food |*> #=>
display-grid[30, 30, food] |>
-- show stored-food operator:
show-stored-food |*> #=>
display-grid[30, 30, stored-food] |>
-- show grid operator:
-- dg |*> #=> display-grid[30, 30] |>
dg |*> #=> display-grid[30, 30, value, " "] |>
-- define a collection of direction related operators:
-- define identity direction operator:
id |*> #=> |_self>
-- define no operation operator:
nop |*> #=> |>
-- define negate direction operator:
negate |*> #=> -1 |_self>
-- define turn-right operators:
turn-right |op: S> => |op: SW>
turn-right |op: SW> => |op: W>
turn-right |op: W> => |op: NW>
turn-right |op: NW> => |op: N>
turn-right |op: N> => |op: NE>
turn-right |op: NE> => |op: E>
turn-right |op: E> => |op: SE>
turn-right |op: SE> => |op: S>
-- define turn-left operators:
turn-left |op: S> => |op: SE>
turn-left |op: SW> => |op: S>
turn-left |op: W> => |op: SW>
turn-left |op: NW> => |op: W>
turn-left |op: N> => |op: NW>
turn-left |op: NE> => |op: N>
turn-left |op: E> => |op: NE>
turn-left |op: SE> => |op: E>
-- define reverse operators:
reverse-dir |op: S> => |op: N>
reverse-dir |op: SW> => |op: NE>
reverse-dir |op: W> => |op: E>
reverse-dir |op: NW> => |op: SE>
reverse-dir |op: N> => |op: S>
reverse-dir |op: NE> => |op: SW>
reverse-dir |op: E> => |op: W>
reverse-dir |op: SE> => |op: NW>
-- define expand operators:
expand |op: S> => -1 |op: N>
expand |op: SW> => -1 |op: N> -1 |op: E>
expand |op: W> => -1 |op: E>
expand |op: NW> => |op: N> -1 |op: E>
expand |op: N> => |op: N>
expand |op: NE> => |op: N> + |op: E>
expand |op: E> => |op: E>
expand |op: SE> => -1 |op: N> + |op: E>
-- invert the given direction:
invert-direction |*> #=>
op-if(is-less-than[0] push-float |__self>, |op: negate>, |op: reverse-dir>) |__self>
-- not sure we use carry-the |food> and drop-the |food> anywhere
-- So potentially delete them
-- carry the food operator:
-- carry-the |food> #=>
-- food current |cell> => minus[1] food current |cell>
-- carry |food> => plus[1] carry |food>
-- drop the food operator:
-- drop-the |food> #=>
-- stored-food current |cell> => arithmetic(stored-food |_self>, |+>, carry |food>) |>
-- carry |food> => |0>
-- if there is food at the current cell, and not already carry food, then apply |op: found-food>, else do nothing:
if-find-food |*> #=>
op-if( and(is-greater-than[0] food current |cell>, is-equal[0] carry |food>) |>, |op: found-food>, |op: not-found-food>) |>
found-food |*> #=>
food current |cell> => minus[1] food current |cell>
carry |food> => plus[1] carry |food>
lay |scent> => |yes>
type |walk> => |op: return-home>
not-found-food |*> #=> |>
-- the if-reach-home operator:
-- if current cell is home cell then apply |op: reached-home>, else do nothing:
if-reach-home |*> #=>
op-if( is-equal(current |cell>, home |cell>) |>, |op: reached-home>, |op: not-reached-home>) |>
-- drop and store any food you are carrying:
reached-home |*> #=>
stored-food current |cell> => arithmetic(stored-food |_self>, |+>, carry |food>) |>
carry |food> => |0>
lay |scent> => |no>
type |walk> => |op: random-walk>
path |home> => |home>
not-reached-home |*> #=> |>
record-scent |*> #=>
op-if(lay |scent>, |op: apply-scent>, |op: nop>) |>
apply-scent |*> #=>
value current |cell> => plus[1] value current |cell>
if-find-scent-change-heading |*> #=>
op-if(is-greater-than[0] value |__self>, |op: found-scent>, |op: nop>) |>
found-scent |*> #=>
heading |ops> => random-if-zero reverse-dir return-path |home>
random-if-zero (*) #=>
op-if(do-you-know sdrop |__self>, |op: id>, |op: pick-random-direction>) |__self>
pick-random-direction |*> #=> pick-elt list-of |directions>
switch-on-random |*> #=>
type |walk> => |op: random-walk>
switch-on-return |*> #=>
type |walk> => |op: return-home>
take-a-step |*> #=>
current |direction> => apply( type |walk>, current |cell>) |>
path |home> +=> current |direction>
current |cell> => apply( current |direction>, current |cell>) |>
location |ant> => current |cell>
if-find-food |>
if-reach-home |>
-- random-walk input is a grid location:
-- random-walk has to return a direction:
random-walk |*> #=>
if-find-scent-change-heading |__self>
--
-- blur heading:
heading |ops> => normalize ( 0.1 turn-left^2 + 0.25 turn-left + 15 + 0.25 turn-right + 0.1 turn-right^2 ) heading |ops>
--
-- try a direction:
try |direction> => clean weighted-pick-elt heading |ops>
--
-- if valid direction, step, else turn right:
op-if( do-you-know apply(try |direction>, |__self>) |>, |op: valid-step>, |op: not-valid-step>) |>
valid-step |*> #=>
try |direction>
not-valid-step |*> #=>
heading |ops> => pick-elt ( turn-right + turn-right^2 ) heading |ops>
|op: id>
-- return-home input is a grid location (which we ignore, instead making use of return-path |home>):
-- return-home returns a direction one step closer to home:
return-home |*> #=> clean weighted-pick-elt return-path |home>
-- single map update:
update |*> #=>
record-scent
take-a-step
dg
|>
-- walk max steps:
walk |*> #=> update (|1> .. max |steps>)
-- walk given steps:
walk-steps |*> #=> update (|1> .. |_self>)
print-usage |*> #=>
print | >
print | Usage:>
print | make the ant walk max steps:>
print | walk>
print
print | make the ant walk the given number of steps:>
print | walk-steps ket(500)>
print
print | show all the available food:>
print | show-food>
print
print | show all the stored food:>
print | show-stored-food>
print
print | display grid:>
print | dg>
print
print-usage
Home