Differences From Artifact [e25c75ea96d80507]:
- File
src/game.d
- 2012-07-15 06:47:16 - part of checkin [6d497011d6] on branch trunk - Fixed judgement order of water-death and stage-clear. This makes flood2 solved. (user: kinaba) [annotate]
- 2012-07-15 12:14:10 - part of checkin [e02668367d] on branch trunk - Revert redesign in the trunk. (user: kinaba) [annotate]
To Artifact [9428bbab7d2bc9a8]:
- File
src/game.d
- 2012-07-15 11:17:59 - part of checkin [ff0ab77d3d] on branch trunk - new game class. (user: kinaba) [annotate]
346 } 346 }
347 data = next; 347 data = next;
348 return dead; 348 return dead;
349 } 349 }
350 } 350 }
351 351
352 //////////////////////////////////////////////////////////////////////////////// 352 ////////////////////////////////////////////////////////////////////////////////
353 <
> 353 /*
354 class Game 354 class Game
355 { 355 {
356 mixin DeriveShow; 356 mixin DeriveShow;
357 357
358 static Game load(File input) 358 static Game load(File input)
359 { 359 {
360 string[] raw_data; 360 string[] raw_data;
................................................................................................................................................................................
440 long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L) 440 long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L)
441 int water_level() { return water.level(turn); } 441 int water_level() { return water.level(turn); }
442 int water_until_rise() { return water.until_rise(turn); } 442 int water_until_rise() { return water.until_rise(turn); }
443 int hige_until_rise() { return map.hige.until_rise(turn); } 443 int hige_until_rise() { return map.hige.until_rise(turn); }
444 int hp() { return map.waterproof - under_water; } 444 int hp() { return map.waterproof - under_water; }
445 } 445 }
446 } 446 }
> 447 */
> 448
> 449 ////////////////////////////////////////////////////////////////////////////////
> 450
> 451 class Game
> 452 {
> 453 public:
> 454 this(File input)
> 455 {
> 456 // Read map data
> 457 string[] map_data_lines;
> 458 for(string line; !(line=input.readln().chomp()).empty; )
> 459 map_data_lines ~= line;
> 460
> 461 // H*W
> 462 H_ = map_data_lines.length;
> 463 W_ = 0;
> 464 foreach(mdl; map_data_lines)
> 465 W_ = max(W_, mdl.length);
> 466
> 467 // Copy to modifiable buffer and adjust coordinates.
> 468 raw_data_ = new char[][H_+1];
> 469 foreach(i,mdl; map_data_lines) {
> 470 char[] buf = new char[mdl.length+1];
> 471 buf[0] = '#';
> 472 buf[1..$] = mdl[];
> 473 raw_data_[H_-i] = buf;
> 474 }
> 475
> 476 // Detect objects
> 477 for(int y=1; y<=H_; ++y)
> 478 for(int x=1; x<raw_data_[y].length; ++x)
> 479 {
> 480 char c = raw_data_[y][x];
> 481 switch(c)
> 482 {
> 483 case '#':
> 484 case '.':
> 485 case ' ':
> 486 break;
> 487 case 'L':
> 488 case 'O':
> 489 lift_pos_ = new Pos(y,x);
> 490 break;
> 491 case 'A': .. case 'I':
> 492 case '1': .. case '9':
> 493 trampoline_pos_[c] = new Pos(y,x);
> 494 break;
> 495 case '!':
> 496 razor_pos_ ~= new Pos(y,x);
> 497 break;
> 498 case '\\':
> 499 lambda_pos_ ~= new Pos(y,x);
> 500 break;
> 501
> 502 // Moving objects are erased from raw_data_
> 503 case 'R':
> 504 robot_pos_ = new Pos(y,x);
> 505 raw_data_[y][x] = ' ';
> 506 break;
> 507 case '*':
> 508 case 'W':
> 509 dynamic_objects_[new Pos(y,x)] = c;
> 510 raw_data_[y][x] = ' ';
> 511 if(c=='*')
> 512 may_update_[new Pos(y,x)] = true;
> 513 break;
> 514 default:
> 515 assert(false);
> 516 }
> 517 }
> 518
> 519 // Read other parameters
> 520 for(string line; !(line=input.readln()).empty; )
> 521 {
> 522 string[] ss = line.split();
> 523 if( ss.length == 2 )
> 524 switch(ss[0])
> 525 {
> 526 case "Water": water_base_ = ss[1].to!int();
> 527 case "Flooding": water_pace_ = ss[1].to!int();
> 528 case "Waterproof": max_air_ = ss[1].to!int();
> 529 case "Growth": hige_pace_ = ss[1].to!int();
> 530 case "Razors": num_razor_ = ss[1].to!int();
> 531 default: assert(false);
> 532 }
> 533 if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="tar
> 534 {
> 535 char fr=ss[1][0], to=ss[3][0];
> 536 trampoline_[fr] = to;
> 537 if(to !in trampoline_rev_) trampoline_rev_[to] =
> 538 trampoline_rev_[to] ~= fr;
> 539 }
> 540 }
> 541
> 542 air_left_ = max_air_;
> 543 }
> 544
> 545 @property const {
> 546 int H() { return H_; }
> 547 int W() { return W_; }
> 548 char trampoline(char c) { return (c in trampoline_ ? trampoline_
> 549 int water_level() {
> 550 return water_pace_ ? water_base_ + turn_/water_pace_ : w
> 551 }
> 552 int water_until_rise() {
> 553 return water_pace_ ? water_pace_ - turn_%water_pace_ : i
> 554 }
> 555 int hige_until_rise() {
> 556 return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.
> 557 }
> 558 bool is_hige_turn() {
> 559 return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : f
> 560 }
> 561 int hp() { return air_left_; }
> 562 int num_razor() { return num_razor_; }
> 563 bool cleared() { return cleared_; }
> 564 bool dead() { return dead_; }
> 565 long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L
> 566 }
> 567 const {
> 568 char opIndex(in Pos p) { return opIndex(p.y, p.x); }
> 569 char opIndex(int y, int x) { return map_get(y, x); }
> 570 }
> 571
> 572 public:
> 573 void command(char c)
> 574 {
> 575 if(dead || cleared)
> 576 return;
> 577
> 578 if(c == 'U') command_move(+1, 0);
> 579 if(c == 'D') command_move(-1, 0);
> 580 if(c == 'L') command_move(0, -1);
> 581 if(c == 'R') command_move(0, +1);
> 582 if(c == 'S') use_razor();
> 583 if(c == 'W') {}
> 584
> 585 if(cleared)
> 586 return;
> 587
> 588 map_update();
> 589 water_update();
> 590 turn_ ++;
> 591 }
> 592
> 593 void command_move(int dy, int dx)
> 594 {
> 595 int y = robot_pos_.y, x = robot_pos_.x;
> 596 char c = this[y+dy, x+dx];
> 597 Pos p = new Pos(y+dy, x+dx);
> 598
> 599 switch(c){
> 600 case 'O':
> 601 cleared_ = true;
> 602 move_robot_to(p);
> 603 break;
> 604 case '\\':
> 605 take_lambda_at(p);
> 606 move_robot_to(p);
> 607 break;
> 608 case '!':
> 609 take_razor_at(p);
> 610 move_robot_to(p);
> 611 break;
> 612 case 'A': .. case 'I':
> 613 enter_trampoline_at(p, c);
> 614 break;
> 615 case ' ':
> 616 case '.':
> 617 move_robot_to(p);
> 618 break;
> 619 case '*':
> 620 if(dy!=0 || this[y,x+dx*2]!=' ')
> 621 break;
> 622 move_robot_to(p);
> 623 push_rock(p, new Pos(y,x+dx*2));
> 624 break;
> 625 default:
> 626 break;
> 627 }
> 628 }
> 629
> 630 void use_razor()
> 631 {
> 632 if(num_razor_ == 0)
> 633 return;
> 634 num_razor_ --;
> 635
> 636 for(int dy=-1; dy<=+1; ++dy)
> 637 for(int dx=-1; dx<=+1; ++dx) if(dy||dx)
> 638 {
> 639 Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx);
> 640 if(auto it = p in dynamic_objects_)
> 641 if(*it == 'W') {
> 642 something_gone(p);
> 643 dynamic_objects_.remove(p);
> 644 }
> 645 }
> 646 }
> 647
> 648 void take_lambda_at(Pos p)
> 649 {
> 650 map_set_empty(p);
> 651 num_lambda_ ++;
> 652 lambda_pos_ = lambda_pos_.erase(p);
> 653 }
> 654
> 655 void take_razor_at(Pos p)
> 656 {
> 657 map_set_empty(p);
> 658 num_razor_ ++;
> 659 razor_pos_ = razor_pos_.erase(p);
> 660 }
> 661
> 662 void enter_trampoline_at(Pos p, char c)
> 663 {
> 664 char d = trampoline(c);
> 665 foreach(cc; trampoline_rev_[d]) {
> 666 Pos pp = trampoline_pos_[cc];
> 667 something_gone(pp);
> 668 map_set_empty(pp);
> 669 }
> 670 move_robot_to(trampoline_pos_[d]);
> 671 }
> 672
> 673 void move_robot_to(Pos p)
> 674 {
> 675 something_gone(robot_pos_);
> 676 map_set_empty(p.y, p.x);
> 677 robot_pos_ = p;
> 678 }
> 679
> 680 void push_rock(Pos fr, Pos to)
> 681 {
> 682 dynamic_objects_.remove(fr);
> 683 dynamic_objects_[to] = '*';
> 684 may_update_[to] = true;
> 685 }
> 686
> 687 void something_gone(Pos p)
> 688 {
> 689 for(int dy=0; dy<=+1; ++dy)
> 690 for(int dx=-1; dx<=+1; ++dx) if(dy||dx)
> 691 may_update_[new Pos(p.y+dy,p.x+dx)] = true;
> 692 }
> 693
> 694 void map_update()
> 695 {
> 696 Pos[] may_update_list;
> 697 foreach(p,_; may_update_)
> 698 if(this[p] == '*')
> 699 may_update_list ~= p;
> 700 may_update_ = null;
> 701
> 702 if( is_hige_turn() )
> 703 foreach(p,c; dynamic_objects_)
> 704 if(c == 'W')
> 705 may_update_list ~= p;
> 706
> 707 sort(may_update_list);
> 708 char[Pos] to_be_written;
> 709 foreach(p; may_update_list)
> 710 if(is_hige_turn() && this[p]=='W')
> 711 {
> 712 for(int dy=-1; dy<=+1; ++dy)
> 713 for(int dx=-1; dx<=+1; ++dx) {
> 714 Pos q = new Pos(p.y+dy,p.x+dx);
> 715 if( this[q] == ' ' )
> 716 to_be_written[q] = 'W';
> 717 }
> 718 }
> 719 else
> 720 {
> 721 int y = p.y;
> 722 int x = p.x;
> 723 char below = this[y-1,x];
> 724 // *
> 725 // _
> 726 if(below==' ') {
> 727 Pos q = new Pos(y-1,x);
> 728 to_be_written[p] = ' ';
> 729 to_be_written[q] = '*';
> 730 may_update_[q] = true;
> 731 }
> 732 // *_ *_
> 733 // *_ or \_
> 734 else if((below=='*'||below=='\\')&&this[y-1,x+1]
> 735 Pos q = new Pos(y-1,x+1);
> 736 to_be_written[p] = ' ';
> 737 to_be_written[q] = '*';
> 738 may_update_[q] = true;
> 739 }
> 740 // _*
> 741 // _*
> 742 else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x
> 743 Pos q = new Pos(y-1,x-1);
> 744 to_be_written[p] = ' ';
> 745 to_be_written[q] = '*';
> 746 may_update_[q] = true;
> 747 }
> 748 }
> 749
> 750 foreach(p,c; to_be_written) {
> 751 dynamic_objects_[p] = c;
> 752 if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x)
> 753 dead_ = true;
> 754 }
> 755
> 756 if(lambda_pos_.empty)
> 757 raw_data_[lift_pos_.y][lift_pos_.x] = 'O';
> 758 }
> 759
> 760 void water_update()
> 761 {
> 762 if( robot_pos_.y <= water_level() )
> 763 air_left_ --;
> 764 else
> 765 air_left_ = max_air_;
> 766 if( air_left_ < 0 )
> 767 dead_ = true;
> 768 }
> 769
> 770 private:
> 771 char map_get(int y, int x) const
> 772 {
> 773 if( y<1 || H<y || x<1 || W<x ) return '#';
> 774 Pos p = new Pos(y,x);
> 775 if(p == robot_pos_)
> 776 return 'R';
> 777 if(auto it = (p in dynamic_objects_))
> 778 return *it;
> 779 if( x<0 || raw_data_[y].length<=x ) return ' ';
> 780 return raw_data_[y][x];
> 781 }
> 782
> 783 void map_set_empty(in Pos p)
> 784 {
> 785 return map_set_empty(p.y, p.x);
> 786 }
> 787
> 788 void map_set_empty(int y, int x)
> 789 {
> 790 if( y<1 || H<y || x<1 || W<x ) return;
> 791 if( x<0 || raw_data_[y].length<=x ) return;
> 792 raw_data_[y][x] = ' ';
> 793 }
> 794
> 795 private:
> 796 int H_;
> 797 int W_;
> 798 char[][] raw_data_;
> 799 Pos[char] trampoline_pos_;
> 800 Pos[] razor_pos_;
> 801 Pos[] lambda_pos_;
> 802 Pos lift_pos_;
> 803 Pos robot_pos_;
> 804 char[Pos] dynamic_objects_;
> 805 char[char] trampoline_;
> 806 char[][char] trampoline_rev_;
> 807 int water_base_ = 0;
> 808 int water_pace_ = 0;
> 809 int max_air_ = 10;
> 810 int hige_pace_ = 25;
> 811 int num_razor_ = 0;
> 812 int num_lambda_ = 0;
> 813
> 814 int turn_ = 0;
> 815 int air_left_ = 0;
> 816 bool cleared_ = false;
> 817 bool dead_ = false;
> 818 bool[Pos] may_update_;
> 819 }