sw-examples: walking-ant-v2.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
-- fully updated to the version 3.1.1 language
-- NB: there is a subtle bug somewhere. In one test run, the ant stopped walking. But I haven't seen the bug since.
-- 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>
-- enable or disable slow walk mode:
-- for now, sleep for 20 milliseconds.
-- change as desired.
enable-slow-walk |*> #=>
pause |*> #=> sleep[20] |_self>
enable-fast-walk |*> #=>
pause |*> #=> |_self>
-- by default, use fast walk:
enable-fast-walk
-- 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 |*> #=>
if( is-less-than[0] push-float |__self> ):
-1 |__self>
else:
reverse-dir |__self>
end:
-- if there is food at the current cell, and not already carry food, then apply found-food branch, else do nothing:
if-find-food |*> #=>
if( and(is-greater-than[0] food current |cell>, is-equal[0] carry |food>) ):
food current |cell> => minus[1] food current |cell>
carry |food> => plus[1] carry |food>
lay |scent> => |yes>
type |walk> => |op: return-home>
end:
|>
-- the if-reach-home operator:
-- if current cell is home cell then apply reached-home branch, else do nothing:
if-reach-home |*> #=>
if( current |cell> == home |cell> ):
stored-food current |cell> => stored-food |_self> ++ carry |food>
carry |food> => |0>
lay |scent> => |no>
type |walk> => |op: random-walk>
path |home> => |home>
end:
record-scent |*> #=>
if( lay |scent> ):
value current |cell> => plus[1] value current |cell>
end:
if-find-scent-change-heading |*> #=>
if( value |__self> > |0> ):
heading |ops> => random-if-zero reverse-dir return-path |home>
end:
random-if-zero (*) #=>
if( do-you-know sdrop |__self> ):
|__self>
else:
pick-elt list-of |directions>
end:
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:
if( do-you-know apply(try |direction>, |__self>) ):
try |direction>
else:
heading |ops> => pick-elt ( turn-right + turn-right^2 ) heading |ops>
|op: id>
end:
-- 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
pause
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 | enable slow walk, ie a 20 ms delay between steps:>
print | so you can actually see the ant walking>
print | enable-slow-walk>
print
print | enable fast walk, ie no delay, which is the default:>
print | enable-fast-walk>
print
print-usage
Home