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