Differences From Artifact [eaa7866c864bed8a]:
- File
src/game.d
- 2012-07-15 12:01:04 - part of checkin [a03584f1c6] on branch trunk - Refactored. (user: kinaba) [annotate]
To 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]
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 const(Pos)[] trampoline_rev(char c) { <
550 const(Pos)[] pp; <
551 if(c in trampoline_rev_) { <
552 foreach(ch; trampoline_rev_[c]) <
553 pp ~= trampoline_pos_[ch]; <
554 } <
555 return pp; <
556 } <
557 int water_level() { <
558 return water_pace_ ? water_base_ + turn_/water_pace_ : w <
559 } <
560 int water_until_rise() { <
561 return water_pace_ ? water_pace_ - turn_%water_pace_ : i <
562 } <
563 int hige_until_rise() { <
564 return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int. <
565 } <
566 bool is_hige_turn() { <
567 return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : f <
568 } <
569 int hp() { return air_left_; } <
570 int num_razor() { return num_razor_; } <
571 bool cleared() { return cleared_; } <
572 bool dead() { return dead_; } <
573 long score() { return num_lambda_*(dead_ ? 25L : cleared_ ? 75L <
574 const(Pos) robot() { return robot_pos_; } <
575 const(Pos) lift() { return lift_pos_; } <
576 Pos[] lambdas() { <
577 Pos[] pp; <
578 foreach(p; lambda_pos_) <
579 pp ~= p.clone(); <
580 return pp; <
581 } <
582 Pos[] razors() { <
583 Pos[] pp; <
584 foreach(p; razor_pos_) <
585 pp ~= p.clone(); <
586 return pp; <
587 } <
588 const(Pos)[] higes() { <
589 const(Pos)[] pp; <
590 foreach(p,c; dynamic_objects_) <
591 if(c=='W') <
592 pp ~= p; <
593 return pp; <
594 } <
595 } <
596 const { <
597 char opIndex(in Pos p) { return opIndex(p.y, p.x); } <
598 char opIndex(int y, int x) { return map_get(y, x); } <
599 } <
600 <
601 public: <
602 void command(char c) <
603 { <
604 if(dead || cleared) <
605 return; <
606 <
607 if(c == 'U') command_move(+1, 0); <
608 if(c == 'D') command_move(-1, 0); <
609 if(c == 'L') command_move(0, -1); <
610 if(c == 'R') command_move(0, +1); <
611 if(c == 'S') use_razor(); <
612 if(c == 'W') {} <
613 <
614 if(!cleared) <
615 { <
616 map_update(); <
617 water_update(); <
618 } <
619 turn_ ++; <
620 } <
621 <
622 void command_move(int dy, int dx) <
623 { <
624 int y = robot_pos_.y, x = robot_pos_.x; <
625 char c = this[y+dy, x+dx]; <
626 Pos p = new Pos(y+dy, x+dx); <
627 <
628 switch(c){ <
629 case 'O': <
630 cleared_ = true; <
631 move_robot_to(p); <
632 break; <
633 case '\\': <
634 take_lambda_at(p); <
635 move_robot_to(p); <
636 break; <
637 case '!': <
638 take_razor_at(p); <
639 move_robot_to(p); <
640 break; <
641 case 'A': .. case 'I': <
642 enter_trampoline_at(p, c); <
643 break; <
644 case ' ': <
645 case '.': <
646 move_robot_to(p); <
647 break; <
648 case '*': <
649 if(dy!=0 || this[y,x+dx*2]!=' ') <
650 break; <
651 move_robot_to(p); <
652 push_rock(p, new Pos(y,x+dx*2)); <
653 break; <
654 default: <
655 break; <
656 } <
657 } <
658 <
659 void use_razor() <
660 { <
661 if(num_razor_ == 0) <
662 return; <
663 num_razor_ --; <
664 <
665 for(int dy=-1; dy<=+1; ++dy) <
666 for(int dx=-1; dx<=+1; ++dx) if(dy||dx) <
667 { <
668 Pos p = new Pos(robot_pos_.y+dy, robot_pos_.x+dx); <
669 if(auto it = p in dynamic_objects_) <
670 if(*it == 'W') { <
671 something_gone(p); <
672 dynamic_objects_.remove(p); <
673 } <
674 } <
675 } <
676 <
677 void take_lambda_at(Pos p) <
678 { <
679 map_set_empty(p); <
680 num_lambda_ ++; <
681 lambda_pos_ = lambda_pos_.erase(p); <
682 } <
683 <
684 void take_razor_at(Pos p) <
685 { <
686 map_set_empty(p); <
687 num_razor_ ++; <
688 razor_pos_ = razor_pos_.erase(p); <
689 } <
690 <
691 void enter_trampoline_at(Pos p, char c) <
692 { <
693 char d = trampoline(c); <
694 foreach(cc; trampoline_rev_[d]) { <
695 Pos pp = trampoline_pos_[cc]; <
696 something_gone(pp); <
697 map_set_empty(pp); <
698 } <
699 move_robot_to(trampoline_pos_[d]); <
700 } <
701 <
702 void move_robot_to(Pos p) <
703 { <
704 something_gone(robot_pos_); <
705 map_set_empty(p.y, p.x); <
706 robot_pos_ = p; <
707 } <
708 <
709 void push_rock(Pos fr, Pos to) <
710 { <
711 dynamic_objects_.remove(fr); <
712 dynamic_objects_[to] = '*'; <
713 may_update_[to] = true; <
714 } <
715 <
716 void something_gone(Pos p) <
717 { <
718 for(int dy=0; dy<=+1; ++dy) <
719 for(int dx=-1; dx<=+1; ++dx) if(dy||dx) <
720 may_update_[new Pos(p.y+dy,p.x+dx)] = true; <
721 } <
722 <
723 void map_update() <
724 { <
725 Pos[] may_update_list; <
726 foreach(p,_; may_update_) <
727 if(this[p] == '*') <
728 may_update_list ~= p; <
729 may_update_ = null; <
730 <
731 if( is_hige_turn() ) <
732 foreach(p,c; dynamic_objects_) <
733 if(c == 'W') <
734 may_update_list ~= p; <
735 <
736 sort(may_update_list); <
737 char[Pos] to_be_written; <
738 foreach(p; may_update_list) <
739 if(is_hige_turn() && this[p]=='W') <
740 { <
741 for(int dy=-1; dy<=+1; ++dy) <
742 for(int dx=-1; dx<=+1; ++dx) { <
743 Pos q = new Pos(p.y+dy,p.x+dx); <
744 if( this[q] == ' ' ) <
745 to_be_written[q] = 'W'; <
746 } <
747 } <
748 else <
749 { <
750 int y = p.y; <
751 int x = p.x; <
752 char below = this[y-1,x]; <
753 // * <
754 // _ <
755 if(below==' ') { <
756 Pos q = new Pos(y-1,x); <
757 to_be_written[p] = ' '; <
758 to_be_written[q] = '*'; <
759 may_update_[q] = true; <
760 } <
761 // *_ *_ <
762 // *_ or \_ <
763 else if((below=='*'||below=='\\')&&this[y-1,x+1] <
764 Pos q = new Pos(y-1,x+1); <
765 to_be_written[p] = ' '; <
766 to_be_written[q] = '*'; <
767 may_update_[q] = true; <
768 } <
769 // _* <
770 // _* <
771 else if(below=='*'&&this[y-1,x-1]==' '&&this[y,x <
772 Pos q = new Pos(y-1,x-1); <
773 to_be_written[p] = ' '; <
774 to_be_written[q] = '*'; <
775 may_update_[q] = true; <
776 } <
777 } <
778 <
779 foreach(p,c; to_be_written) { <
780 dynamic_objects_[p] = c; <
781 if(c=='*' && p.y==robot_pos_.y+1 && p.x==robot_pos_.x) <
782 dead_ = true; <
783 } <
784 <
785 if(lambda_pos_.empty) <
786 raw_data_[lift_pos_.y][lift_pos_.x] = 'O'; <
787 } <
788 <
789 void water_update() <
790 { <
791 if( robot_pos_.y <= water_level() ) <
792 air_left_ --; <
793 else <
794 air_left_ = max_air_; <
795 if( air_left_ < 0 ) <
796 dead_ = true; <
797 } <
798 <
799 private: <
800 char map_get(int y, int x) const <
801 { <
802 if( y<1 || H<y || x<1 || W<x ) return '#'; <
803 Pos p = new Pos(y,x); <
804 if(p == robot_pos_) <
805 return 'R'; <
806 if(auto it = (p in dynamic_objects_)) <
807 return *it; <
808 if( x<0 || raw_data_[y].length<=x ) return ' '; <
809 return raw_data_[y][x]; <
810 } <
811 <
812 void map_set_empty(in Pos p) <
813 { <
814 return map_set_empty(p.y, p.x); <
815 } <
816 <
817 void map_set_empty(int y, int x) <
818 { <
819 if( y<1 || H<y || x<1 || W<x ) return; <
820 if( x<0 || raw_data_[y].length<=x ) return; <
821 raw_data_[y][x] = ' '; <
822 } <
823 <
824 public: <
825 Game clone() const { return new Game(this); } <
826 this(in Game g) { <
827 H_ = g.H_; <
828 W_ = g.W_; <
829 raw_data_ = new char[][g.raw_data_.length]; <
830 foreach(i,d; g.raw_data_) raw_data_[i] = d.dup; <
831 trampoline_pos_ = cast(Pos[char]) g.trampoline_pos_; <
832 razor_pos_ = (cast(Game)g).razor_pos_.dup; <
833 lambda_pos_ = (cast(Game)g).lambda_pos_.dup; <
834 lift_pos_ = g.lift_pos_.clone(); <
835 robot_pos_ = g.robot_pos_.clone(); <
836 dynamic_objects_ = dup(g.dynamic_objects_); <
837 trampoline_ = (cast(Game)g).trampoline_; <
838 trampoline_rev_ = (cast(Game)g).trampoline_rev_; <
839 water_base_ = g.water_base_; <
840 water_pace_ = g.water_pace_; <
841 max_air_ = g.max_air_; <
842 hige_pace_ = g.hige_pace_; <
843 num_razor_ = g.num_razor_; <
844 num_lambda_ = g.num_lambda_; <
845 turn_ = g.turn_; <
846 air_left_ = g.air_left_; <
847 cleared_ = g.cleared_; <
848 dead_ = g.dead_; <
849 may_update_ = dup(g.may_update_); <
850 } <
851 <
852 V[K] dup(V,K)(in V[K] aa) { <
853 V[K] aa2; <
854 foreach(k,v; aa) aa2[k] = v; <
855 return aa2; <
856 } <
857 <
858 private: <
859 int H_; <
860 int W_; <
861 char[][] raw_data_; <
862 Pos[char] trampoline_pos_; <
863 Pos[] razor_pos_; <
864 Pos[] lambda_pos_; <
865 Pos lift_pos_; <
866 Pos robot_pos_; <
867 char[Pos] dynamic_objects_; <
868 char[char] trampoline_; <
869 char[][char] trampoline_rev_; <
870 int water_base_ = 0; <
871 int water_pace_ = 0; <
872 int max_air_ = 10; <
873 int hige_pace_ = 25; <
874 int num_razor_ = 0; <
875 int num_lambda_ = 0; <
876 <
877 int turn_ = 0; <
878 int air_left_ = 0; <
879 bool cleared_ = false; <
880 bool dead_ = false; <
881 bool[Pos] may_update_; <
882 } <