Differences From Artifact [d9bf3ea129c7cbc5]:
- File
src/game.d
- 2012-07-16 03:53:00 - part of checkin [971863e35a] on branch trunk - No-cloning death-move(). With several fixes to the simulator. (user: kinaba) [annotate]
To Artifact [6849c1cc0eb810a9]:
- File
src/game.d
- 2012-07-16 10:02:57 - part of checkin [b96971b0b6] on branch trunk - refactoring. (user: kinaba) [annotate]
1 import util; 1 import util;
2 2
3 //////////////////////////////////////////////////////////////////////////////// 3 ////////////////////////////////////////////////////////////////////////////////
4 4
> 5 bool is_spacy(char c)
> 6 {
> 7 return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O';
> 8 }
> 9
> 10 bool is_rocky(char c)
> 11 {
> 12 return c=='*' || c=='@';
> 13 }
> 14
> 15 bool is_true_space(char c)
> 16 {
> 17 return c==' ';
> 18 }
> 19
> 20 bool is_trampoline_source(char c)
> 21 {
> 22 return 'A'<=c && c<='I';
> 23 }
> 24
> 25 bool is_rocklambda(char c)
> 26 {
> 27 return is_rocky(c) || c=='\\';
> 28 }
> 29
> 30 ////////////////////////////////////////////////////////////////////////////////
> 31
5 class Pos 32 class Pos
6 { 33 {
7 public immutable int y, x; 34 public immutable int y, x;
8 mixin DeriveCreate; 35 mixin DeriveCreate;
9 mixin DeriveCompare; 36 mixin DeriveCompare;
10 mixin DeriveShow; 37 mixin DeriveShow;
11 Pos clone() const { return cast(Pos) this; } 38 Pos clone() const { return cast(Pos) this; }
................................................................................................................................................................................
37 assert( aa[new Pos(1,2)]==2 ); 64 assert( aa[new Pos(1,2)]==2 );
38 } 65 }
39 66
40 //////////////////////////////////////////////////////////////////////////////// 67 ////////////////////////////////////////////////////////////////////////////////
41 68
42 class Water 69 class Water
43 { 70 {
44 public immutable int base, pace; <
45 mixin DeriveCreate; <
46 mixin DeriveShow; 71 mixin DeriveShow;
> 72
> 73 private:
> 74 immutable int base, pace;
> 75 mixin DeriveCreate;
47 Water clone() const { return cast(Water) this; } 76 Water clone() const { return cast(Water) this; }
48 77
49 static load(string[string] params) 78 static load(string[string] params)
50 { 79 {
51 return new Water(params.get("Water", "0").to!int(), 80 return new Water(params.get("Water", "0").to!int(),
52 params.get("Flooding", "0").to!int()); 81 params.get("Flooding", "0").to!int());
53 } 82 }
................................................................................................................................................................................
83 assert( 1 == w.level(5) ); 112 assert( 1 == w.level(5) );
84 } 113 }
85 114
86 //////////////////////////////////////////////////////////////////////////////// 115 ////////////////////////////////////////////////////////////////////////////////
87 116
88 class Hige 117 class Hige
89 { 118 {
90 public immutable int pace; <
91 mixin DeriveCreate; <
92 mixin DeriveShow; 119 mixin DeriveShow;
> 120
> 121 private:
> 122 immutable int pace;
> 123 mixin DeriveCreate;
93 Hige clone() const { return cast(Hige)this; } 124 Hige clone() const { return cast(Hige)this; }
94 125
95 static load(string[string] params) 126 static load(string[string] params)
96 { 127 {
97 return new Hige(params.get("Growth", "25").to!int()); 128 return new Hige(params.get("Growth", "25").to!int());
98 } 129 }
99 130
................................................................................................................................................................................
108 } 139 }
109 } 140 }
110 141
111 //////////////////////////////////////////////////////////////////////////////// 142 ////////////////////////////////////////////////////////////////////////////////
112 143
113 class Trampoline 144 class Trampoline
114 { 145 {
115 private immutable char[] target_of_; <
116 private immutable char[][] source_of_; <
117 private immutable Pos[] position_of_; <
118 private immutable char[] source_list_; <
119 private immutable char[] target_list_; <
120 mixin DeriveShow; 146 mixin DeriveShow;
> 147
> 148 private:
> 149 immutable char[] target_of_;
> 150 immutable char[][] source_of_;
> 151 immutable Pos[] position_of_;
> 152 immutable char[] source_list_;
> 153 immutable char[] target_list_;
121 Trampoline clone() const { return cast(Trampoline) this; } 154 Trampoline clone() const { return cast(Trampoline) this; }
> 155
122 this(Map m, char[char] tramparam) 156 this(Map m, char[char] tramparam)
123 { 157 {
124 auto ta = new char['I'+1]; 158 auto ta = new char['I'+1];
125 auto sr = new char[]['9'+1]; 159 auto sr = new char[]['9'+1];
126 auto po = new Pos[max('I','9')+1]; 160 auto po = new Pos[max('I','9')+1];
127 char[] sl, tl; 161 char[] sl, tl;
128 foreach(fr,to; tramparam) { 162 foreach(fr,to; tramparam) {
................................................................................................................................................................................
144 target_of_ = cast(immutable) ta; 178 target_of_ = cast(immutable) ta;
145 source_of_ = cast(immutable) sr; 179 source_of_ = cast(immutable) sr;
146 position_of_ = cast(immutable) po; 180 position_of_ = cast(immutable) po;
147 source_list_ = cast(immutable) sl; 181 source_list_ = cast(immutable) sl;
148 target_list_ = cast(immutable) tl; 182 target_list_ = cast(immutable) tl;
149 } 183 }
150 184
151 @property const: | 185 public @property const:
152 const(char[]) source_list() { return source_list_; } 186 const(char[]) source_list() { return source_list_; }
153 const(char[]) target_list() { return target_list_; } 187 const(char[]) target_list() { return target_list_; }
154 const(char[]) source_of(char c) { return source_of_[c]; } 188 const(char[]) source_of(char c) { return source_of_[c]; }
155 char target_of(char c) { return target_of_[c]; } 189 char target_of(char c) { return target_of_[c]; }
156 Pos[] source_pos(char c) { 190 Pos[] source_pos(char c) {
157 Pos[] ps; 191 Pos[] ps;
158 foreach(s; source_of(c)) 192 foreach(s; source_of(c))
................................................................................................................................................................................
164 198
165 //////////////////////////////////////////////////////////////////////////////// 199 ////////////////////////////////////////////////////////////////////////////////
166 200
167 class Map 201 class Map
168 { 202 {
169 mixin DeriveShow; 203 mixin DeriveShow;
170 204
171 char[][] data; | 205 private char[][] data;
172 Pos robot; 206 Pos robot;
173 Pos lift; 207 Pos lift;
174 int waterproof; | 208 private int waterproof;
175 int razor; | 209 private int collected_razor;
176 int collected_lambda; 210 int collected_lambda;
177 int total_lambda; 211 int total_lambda;
178 bool cleared; | 212 private bool cleared;
179 Pos[] may_update; | 213 private Pos[] may_update;
180 214
181 Map clone() const { return new Map(this); } | 215 private Map clone() const { return new Map(this); }
182 this(in Map m) { | 216 private this(in Map m) {
183 foreach(s; m.data) 217 foreach(s; m.data)
184 this.data ~= s.dup; 218 this.data ~= s.dup;
185 this.robot = m.robot.clone(); | 219 this.robot = m.robot.clone();
186 this.lift = m.lift.clone(); | 220 this.lift = m.lift.clone();
187 this.waterproof = m.waterproof; 221 this.waterproof = m.waterproof;
188 this.razor = m.razor; | 222 this.collected_razor = m.collected_razor;
189 this.collected_lambda = m.collected_lambda; 223 this.collected_lambda = m.collected_lambda;
190 this.total_lambda = m.total_lambda; | 224 this.total_lambda = m.total_lambda;
> 225 this.cleared = m.cleared;
191 this.may_update = (cast(Map)m).may_update.dup; 226 this.may_update = (cast(Map)m).may_update.dup;
192 this.cleared = m.cleared; <
193 } 227 }
194 228
> 229 const {
> 230 @property {
> 231 int H() { return data.length; }
> 232 int W() { return data[0].length; }
> 233 int num_razor() { return collected_razor; }
> 234
> 235 Pos[] razors() { return objects('!'); }
> 236 Pos[] lambdas() { return objects('\\'); }
> 237 }
> 238
> 239 Pos[] objects(char c) {
> 240 Pos[] ans;
> 241 for(int y=1; y<=H; ++y)
> 242 for(int x=1; x<=W; ++x)
> 243 if(this[y,x] == c)
> 244 ans ~= new Pos(y,x);
> 245 return ans;
> 246 }
> 247
> 248 char opIndex(int y, int x) {
> 249 --y, --x;
> 250 if(y<0||H<=y||x<0||W<=x)
> 251 return '#';
> 252 return data[H-1-y][x];
> 253 }
> 254
> 255 char opIndex(in Pos p) {
> 256 return this[p.y, p.x];
> 257 }
> 258 }
> 259
> 260 private:
195 this(string[] raw_data, string[string] params, char[char] trampo) 261 this(string[] raw_data, string[string] params, char[char] trampo)
196 { 262 {
197 int width = 0; 263 int width = 0;
198 foreach(r; raw_data) 264 foreach(r; raw_data)
199 width = max(width, r.length); 265 width = max(width, r.length);
200 foreach(r; raw_data) { 266 foreach(r; raw_data) {
201 this.data ~= r.dup; 267 this.data ~= r.dup;
................................................................................................................................................................................
207 for(int x=1; x<=W; ++x) { 273 for(int x=1; x<=W; ++x) {
208 if(this[y,x] == 'R') 274 if(this[y,x] == 'R')
209 this.robot = new Pos(y,x); 275 this.robot = new Pos(y,x);
210 if(this[y,x] == 'L' || this[y,x] == 'O') 276 if(this[y,x] == 'L' || this[y,x] == 'O')
211 this.lift = new Pos(y,x); 277 this.lift = new Pos(y,x);
212 if(this[y,x] == '\\' || this[y,x] == '@') 278 if(this[y,x] == '\\' || this[y,x] == '@')
213 total_lambda++; 279 total_lambda++;
214 if(this[y,x] == '*' || this[y,x] == '@') | 280 if(is_rocky(this[y,x]))
215 may_update ~= new Pos(y,x); 281 may_update ~= new Pos(y,x);
216 } 282 }
217 283
218 this.waterproof = params.get("Waterproof", "5").to!int(); | 284 this.waterproof = params.get("Waterproof", "5").to!int();
219 this.razor = params.get("Razors", "0").to!int(); | 285 this.collected_razor = params.get("Razors", "0").to!int();
220 } <
221 <
222 const @property { <
223 int H() { return data.length; } <
224 int W() { return data[0].length; } <
225 } <
226 <
227 const { <
228 char opIndex(int y, int x) <
229 { <
230 // Adjust coordinate to the spec. bottom-left is (1,1). <
231 --y, --x; <
232 if(y<0||H<=y||x<0||W<=x) <
233 return '#'; <
234 return data[H-1-y][x]; <
235 } <
236 <
237 char opIndex(in Pos p) <
238 { <
239 return this[p.y, p.x]; <
240 } <
241 } 286 }
242 287
243 void opIndexAssign(char c, int y, int x) 288 void opIndexAssign(char c, int y, int x)
244 { 289 {
245 // Adjust coordinate to the spec. bottom-left is (1,1). <
246 --y, --x; 290 --y, --x;
247 if(y<0||H<=y||x<0||W<=x) 291 if(y<0||H<=y||x<0||W<=x)
248 return; 292 return;
249 data[H-1-y][x] = c; 293 data[H-1-y][x] = c;
250 } 294 }
251 295
252 void opIndexAssign(char c, in Pos p) 296 void opIndexAssign(char c, in Pos p)
253 { 297 {
254 this[p.y, p.x] = c; 298 this[p.y, p.x] = c;
255 } 299 }
256 300
257 Pos[] objects(char c) const { <
258 Pos[] ans; <
259 for(int y=1; y<=H; ++y) <
260 for(int x=1; x<=W; ++x) <
261 if(this[y,x] == c) <
262 ans ~= new Pos(y,x); <
263 return ans; <
264 } <
265 <
266 Pos[] razors() const { return objects('!'); } <
267 Pos[] lambdas() const { return objects('\\'); } <
268 <
269 bool command(char c, int turn, bool hige_day, in Trampoline tr) 301 bool command(char c, int turn, bool hige_day, in Trampoline tr)
270 { 302 {
271 assert( this[robot] == 'R' ); | 303 switch(c)
> 304 {
272 if(c=='R') return move( 0, +1, hige_day, tr); | 305 case 'R': return move( 0, +1, hige_day, tr);
273 if(c=='L') return move( 0, -1, hige_day, tr); | 306 case 'L': return move( 0, -1, hige_day, tr);
274 if(c=='U') return move(+1, 0, hige_day, tr); | 307 case 'U': return move(+1, 0, hige_day, tr);
275 if(c=='D') return move(-1, 0, hige_day, tr); | 308 case 'D': return move(-1, 0, hige_day, tr);
276 if(c=='W') return move( 0, 0, hige_day, tr); | 309 case 'W': return move( 0, 0, hige_day, tr);
277 if(c=='S') return use_razor(hige_day); | 310 case 'S': return use_razor(hige_day);
278 assert(false); | 311 default: assert(false);
> 312 }
279 } 313 }
280 314
281 bool use_razor(bool hige_day) 315 bool use_razor(bool hige_day)
282 { 316 {
283 if(razor) { | 317 if(collected_razor > 0)
> 318 {
284 razor--; | 319 collected_razor--;
285 for(int dy=-1; dy<=+1; ++dy) 320 for(int dy=-1; dy<=+1; ++dy)
286 for(int dx=-1; dx<=+1; ++dx) 321 for(int dx=-1; dx<=+1; ++dx)
287 if(this[robot.y+dy,robot.x+dx] == 'W') { 322 if(this[robot.y+dy,robot.x+dx] == 'W') {
288 emptified(new Pos(robot.y+dy,robot.x+dx) 323 emptified(new Pos(robot.y+dy,robot.x+dx)
289 this[robot.y+dy,robot.x+dx] = ' '; 324 this[robot.y+dy,robot.x+dx] = ' ';
290 } 325 }
291 } 326 }
292 <
293 return update(hige_day); 327 return update(hige_day);
294 } 328 }
295 329
296 bool rocky(char c) { return c=='*' || c=='@'; } | 330 // Register a position that may become empty in the last turn.
> 331 void emptified(Pos p)
297 | 332 {
298 void emptified(Pos p) { <
299 for(int dy=0; dy<=+1; ++dy) | 333 for(int dy=0; dy<=+1; ++dy)
300 for(int dx=-1; dx<=+1; ++dx) | 334 for(int dx=-1; dx<=+1; ++dx)
301 may_update ~= new Pos(p.y+dy, p.x+dx); | 335 may_update ~= new Pos(p.y+dy, p.x+dx);
302 } | 336 }
303 337
304 bool move(int dy, int dx, bool hige_day, in Trampoline tr) 338 bool move(int dy, int dx, bool hige_day, in Trampoline tr)
305 { 339 {
306 emptified(robot); | 340 Pos next = new Pos(robot.y+dy, robot.x+dx);
> 341 int y=robot.y, x=robot.x;
307 | 342
308 int y = robot.y; <
309 int x = robot.x; <
310 if( '\\' == this[y+dy,x+dx] ) <
311 collected_lambda++; | 343 if( '\\' == this[next] ) collected_lambda++;
312 if( '!' == this[y+dy,x+dx] ) | 344 if( '!' == this[next] ) collected_razor++;
313 razor++; <
314 if( 'O' == this[y+dy,x+dx] ) <
315 cleared = true; | 345 if( 'O' == this[next] ) cleared = true;
316 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { <
> 346
> 347 if( is_spacy(this[next]) )
> 348 {
> 349 emptified(robot);
317 this[y,x]=' '; | 350 this[y,x] = ' ';
318 this[y+dy,x+dx]='R'; <
> 351 this[next] = 'R';
319 robot = new Pos(y+dy,x+dx); | 352 robot = next;
> 353 }
320 } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+ | 354 else if(dy==0 && is_rocky(this[next]) && ' '==this[y+dy*2,x+dx*2
> 355 {
321 char rock = this[y+dy,x+dx]; | 356 char rock = this[next];
> 357 emptified(robot);
322 this[y,x]=' '; | 358 this[y,x] = ' ';
323 this[y+dy,x+dx]='R'; <
> 359 this[next] = 'R';
324 this[y+dy*2,x+dx*2]=rock; | 360 this[y+dy*2,x+dx*2] = rock;
325 robot = new Pos(y+dy,x+dx); | 361 robot = next;
326 may_update ~= new Pos(y+dy*2,x+dx*2); 362 may_update ~= new Pos(y+dy*2,x+dx*2);
327 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { <
> 363 }
> 364 else if(is_trampoline_source(this[next]))
> 365 {
> 366 emptified(robot);
328 this[y,x]=' '; | 367 this[y,x] = ' ';
329 Pos tp = tr.target_pos(this[y+dy,x+dx]); | 368 Pos tp = tr.target_pos(this[next]);
330 foreach(p; tr.source_pos(this[tp])) { | 369 foreach(p; tr.source_pos(this[tp]))
> 370 {
331 emptified(p); 371 emptified(p);
332 this[p] = ' '; 372 this[p] = ' ';
333 } 373 }
334 this[tp] = 'R'; 374 this[tp] = 'R';
335 robot = tp; | 375 robot = tp;
336 } 376 }
337 return update(hige_day); 377 return update(hige_day);
338 } 378 }
339 379
340 bool update(bool hige_day) 380 bool update(bool hige_day)
341 { 381 {
342 // Write after all the updates are processed. 382 // Write after all the updates are processed.
................................................................................................................................................................................
343 Tuple!(int,int,char)[] write_buffer; 383 Tuple!(int,int,char)[] write_buffer;
344 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); 384 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c);
345 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c 385 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c
346 scope(exit) { 386 scope(exit) {
347 may_update.length = 0; 387 may_update.length = 0;
348 foreach(wr; write_buffer) { 388 foreach(wr; write_buffer) {
349 this[wr[0],wr[1]] = wr[2]; 389 this[wr[0],wr[1]] = wr[2];
350 if(rocky(wr[2])) | 390 if(is_rocky(wr[2]))
351 may_update ~= new Pos(wr[0],wr[1]); 391 may_update ~= new Pos(wr[0],wr[1]);
352 if(wr[2]==' ') 392 if(wr[2]==' ')
353 emptified(new Pos(wr[0], wr[1])); 393 emptified(new Pos(wr[0], wr[1]));
354 } 394 }
355 } 395 }
356 396
357 if(collected_lambda == total_lambda) 397 if(collected_lambda == total_lambda)
................................................................................................................................................................................
366 may_update ~= new Pos(y,x); 406 may_update ~= new Pos(y,x);
367 } 407 }
368 408
369 sort(may_update); 409 sort(may_update);
370 foreach(p; may_update) { 410 foreach(p; may_update) {
371 int y = p.y, x = p.x; 411 int y = p.y, x = p.x;
372 char rock = this[p]; 412 char rock = this[p];
373 if(rocky(this[p])) { | 413 if(is_rocky(this[p])) {
374 if(this[p.D]==' ') { 414 if(this[p.D]==' ') {
375 writep(p, ' '); 415 writep(p, ' ');
376 writep(p.D, (rock=='@'&&this[p.D.D]!=' ' 416 writep(p.D, (rock=='@'&&this[p.D.D]!=' '
377 if(robot == p.D.D) 417 if(robot == p.D.D)
378 dead=true; 418 dead=true;
379 } 419 }
380 else if((rocky(this[p.D]) || this[p.D]=='\\') && | 420 else if((is_rocky(this[p.D]) || this[p.D]=='\\')
381 writep(p, ' '); 421 writep(p, ' ');
382 writep(p.R.D,(rock=='@'&&this[p.R.D.D]!= 422 writep(p.R.D,(rock=='@'&&this[p.R.D.D]!=
383 if(robot == p.R.D.D) 423 if(robot == p.R.D.D)
384 dead=true; 424 dead=true;
385 } 425 }
386 else if(rocky(this[p.D]) && this[p.L]==' ' && th | 426 else if(is_rocky(this[p.D]) && this[p.L]==' ' &&
387 writep(p, ' '); 427 writep(p, ' ');
388 writep(p.L.D, (rock=='@'&&this[p.L.D.D]! 428 writep(p.L.D, (rock=='@'&&this[p.L.D.D]!
389 if(robot == p.L.D.D) 429 if(robot == p.L.D.D)
390 dead=true; 430 dead=true;
391 } 431 }
392 } 432 }
393 else if(this[p]=='W') { 433 else if(this[p]=='W') {