1+ var plan = [ "############################" ,
2+ "# # # o ##" ,
3+ "# #" ,
4+ "# ##### #" ,
5+ "## # # ## #" ,
6+ "### ## # #" ,
7+ "# ### # #" ,
8+ "# #### #" ,
9+ "# ## o #" ,
10+ "# o # o ### #" ,
11+ "# # #" ,
12+ "############################" ] ;
13+
14+ function Vector ( x , y ) {
15+ this . x = x ;
16+ this . y = y ;
17+ }
18+
19+ Vector . prototype . plus = function ( other ) {
20+ return new Vector ( this . x + other . x , this . y + other . y ) ;
21+ } ;
22+
23+ function Grid ( width , height ) {
24+ this . space = new Array ( width * height ) ;
25+ this . width = width ;
26+ this . height = height ;
27+ }
28+ Grid . prototype . isInside = function ( vector ) {
29+ return vector . x >= 0 && vector . x < this . width &&
30+ vector . y >= 0 && vector . y < this . height ;
31+ } ;
32+
33+ Grid . prototype . get = function ( vector ) {
34+ return this . space [ vector . x + this . width * vector . y ] ;
35+ } ;
36+
37+ Grid . prototype . set = function ( vector , value ) {
38+ this . space [ vector . x + this . width * vector . y ] = value ;
39+ } ;
40+
41+ var directions = {
42+ "n" : new Vector ( 0 , - 1 ) ,
43+ "ne" : new Vector ( 1 , - 1 ) ,
44+ "e" : new Vector ( 1 , 0 ) ,
45+ "se" : new Vector ( 1 , 1 ) ,
46+ "s" : new Vector ( 0 , 1 ) ,
47+ "sw" : new Vector ( - 1 , 1 ) ,
48+ "w" : new Vector ( - 1 , 0 ) ,
49+ "nw" : new Vector ( - 1 , - 1 )
50+ } ;
51+
52+ function randomElement ( array ) {
53+ return array [ Math . floor ( Math . random ( ) * array . length ) ] ;
54+ }
55+
56+ var directionNames = "n ne e se s sw w nw" . split ( " " ) ;
57+
58+ function BouncingCritter ( ) {
59+ this . direction = randomElement ( directionNames ) ;
60+ } ;
61+
62+ BouncingCritter . prototype . act = function ( view ) {
63+ if ( view . look ( this . direction ) != " " )
64+ this . direction = view . find ( " " ) || "s" ;
65+ return { type : "move" , direction : this . direction } ;
66+ } ;
67+
68+ function elementFromChar ( legend , ch ) {
69+ if ( ch == " " )
70+ return null ;
71+ var element = new legend [ ch ] ( ) ;
72+ element . originChar = ch ;
73+ return element ;
74+ }
75+
76+ function World ( map , legend ) {
77+ var grid = new Grid ( map [ 0 ] . length , map . length ) ;
78+ this . grid = grid ;
79+ this . legend = legend ;
80+
81+ map . forEach ( function ( line , y ) {
82+ for ( var x = 0 ; x < line . length ; x ++ )
83+ grid . set ( new Vector ( x , y ) ,
84+ elementFromChar ( legend , line [ x ] ) ) ;
85+ } ) ;
86+ }
87+
88+ function charFromElement ( element ) {
89+ if ( element == null )
90+ return " " ;
91+ else
92+ return element . originChar ;
93+ }
94+
95+ World . prototype . toString = function ( ) {
96+ var output = "" ;
97+ for ( var y = 0 ; y < this . grid . height ; y ++ ) {
98+ for ( var x = 0 ; x < this . grid . width ; x ++ ) {
99+ var element = this . grid . get ( new Vector ( x , y ) ) ;
100+ output += charFromElement ( element ) ;
101+ }
102+ output += "\n" ;
103+ }
104+ return output ;
105+ } ;
106+
107+ function Wall ( ) { }
108+
109+ var world = new World ( plan , { "#" : Wall ,
110+ "o" : BouncingCritter } ) ;
111+
112+ Grid . prototype . forEach = function ( f , context ) {
113+ for ( var y = 0 ; y < this . height ; y ++ ) {
114+ for ( var x = 0 ; x < this . width ; x ++ ) {
115+ var value = this . space [ x + y * this . width ] ;
116+ if ( value != null )
117+ f . call ( context , value , new Vector ( x , y ) ) ;
118+ }
119+ }
120+ } ;
121+
122+ World . prototype . turn = function ( ) {
123+ var acted = [ ] ;
124+ this . grid . forEach ( function ( critter , vector ) {
125+ if ( critter . act && acted . indexOf ( critter ) == - 1 ) {
126+ acted . push ( critter ) ;
127+ this . letAct ( critter , vector ) ;
128+ }
129+ } , this ) ;
130+ } ;
131+
132+ World . prototype . letAct = function ( critter , vector ) {
133+ var action = critter . act ( new View ( this , vector ) ) ;
134+ if ( action && action . type == "move" ) {
135+ var dest = this . checkDestination ( action , vector ) ;
136+ if ( dest && this . grid . get ( dest ) == null ) {
137+ this . grid . set ( vector , null ) ;
138+ this . grid . set ( dest , critter ) ;
139+ }
140+ }
141+ } ;
142+
143+ World . prototype . checkDestination = function ( action , vector ) {
144+ if ( directions . hasOwnProperty ( action . direction ) ) {
145+ var dest = vector . plus ( directions [ action . direction ] ) ;
146+ if ( this . grid . isInside ( dest ) )
147+ return dest ;
148+ }
149+ } ;
150+
151+ function View ( world , vector ) {
152+ this . world = world ;
153+ this . vector = vector ;
154+ }
155+
156+ View . prototype . look = function ( dir ) {
157+ var target = this . vector . plus ( directions [ dir ] ) ;
158+ if ( this . world . grid . isInside ( target ) )
159+ return charFromElement ( this . world . grid . get ( target ) ) ;
160+ else
161+ return "#" ;
162+ } ;
163+
164+ View . prototype . findAll = function ( ch ) {
165+ var found = [ ] ;
166+ for ( var dir in directions )
167+ if ( this . look ( dir ) == ch )
168+ found . push ( dir ) ;
169+ return found ;
170+ } ;
171+
172+ View . prototype . find = function ( ch ) {
173+ var found = this . findAll ( ch ) ;
174+ if ( found . length == 0 ) return null ;
175+ return randomElement ( found ) ;
176+ } ;
177+
178+ for ( var i = 0 ; i < 5 ; i ++ ) {
179+ world . turn ( ) ;
180+ console . log ( world . toString ( ) ) ;
181+ }
182+
183+ //animateWorld(world);
0 commit comments