Requirement: Support movement on a square game-board on which movement is allowed off each edge as though the opposite edge were adjacent. A move is always a unit move, as with the king in chess. A four-by-four map and example moves are shown here.
i. 4 4 NB. show the map on which movement occurs 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 E move 5 NB. move east from location 5 6 SE move 11 NB. move south-east from location 11 12 SW move 12 3 NW move W move NW move 1 10
A natural way to solve this is by working with arrays that model the mapping.
NB. Movement on square map with toroidal wrap.
NB. (model-based algorithm)
sz =: 4 NB. size (edge-length) of square map
loc=: i. sz, sz NB. model of mapped locations
'NW N NE W E SW S SE' =: compass=: c#~ +./"1 |c=. <: 3&#.^:_1 i.9
t=. verb : '(<:sz)}. (1+2*sz)$ loc {~ y|~ #loc'
tloc=: (<:sz)}."2 t"0 i.1+2*sz NB. transit model
move =: dyad define
tloc {~<,x + 1 1 + ,4 $. $. loc = y
)
NB. x is direction of movement
NB. y is location before move
NB. output is location after move
NB. i.sz^2 is domain of both output and y-input The solution can also be obtained without creating arrays that are analogous to map positions.
NB. Movement on square map with toroidal wrap. NB. (formulaic algorithm) sz =: 4 NB. size (edge-length) of square map 'NW N NE W E SW S SE'=: compass=: c#~ +./"1 |c=. <: 3&#.^:_1 i.9 deltaEW =: dyad define xx =. }.x if. 0>xx do. xx+ sz * 0 = sz|y NB. West elseif. 0<xx do. xx+(-sz)* (sz-1)= sz|y NB. East elseif. do. 0 end. ) deltaNS =: dyad define xx =. }:x s2 =. sz^2 if. 0>xx do. (-sz)+s2* y < sz NB. North elseif. 0<xx do. sz -s2* y >:s2-sz NB. South elseif. do. 0 end. ) move =: dyad define y + +/ (x deltaNS y),(x deltaEW y) )
In the game-design classroom context where this problem arose, the locations on the four-by-four map were to be numbered from one to sixteen, and the eight possible directions of movement were to be received as particular codes. Arbitrary input-output format requirements such as this can be handled easily.
moveA=: dyad define NB. use alternate I/O domains 1+ (y-1) move~ ,compass#~ x= _5 _4 _3 _1 1 3 4 5 ) _3 moveA 12 NB. _3 means NE, as diagrammed below 5 NB. directions of movement as (non-wrapping) differential on 4-by-4 array ] 3 3 $ _5 _4 _3 _1 0 1 3 4 5 _5 _4 _3 _1 0 1 3 4 5 >: i. 4 4 NB. 1-based array 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
The difference between zero-based numbering and one-based numbering is of no consequence here.* The classroom specification for signaling direction of movement, however, is unfortunate. It binds the concept of direction to the size of the map. Change to a map of size other than 4x4 would invalidate what little meaning these numbers have, and any code that relied on those values in anything but a token manner would require rewriting. In the code shown here, these values are used as mere tokens. The elements of compass are not tokens; they denote direction of change, north-south and east-west.
compass NB. NW N NE W E SW S SE _1 _1 _1 0 _1 1 0 _1 0 1 1 _1 1 0 1 1
*On this topic, see the note by Edsger W. Dijkstra, Why numbering should start at zero.
