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 347 data = next;
348 348 return dead;
349 349 }
350 350 }
351 351
352 352 ////////////////////////////////////////////////////////////////////////////////
353 -/*
353 +
354 354 class Game
355 355 {
356 356 mixin DeriveShow;
357 357
358 358 static Game load(File input)
359 359 {
360 360 string[] raw_data;
................................................................................
440 440 long score() { return lambda*(dead ? 25L : cleared ? 75L : 50L) - turn; }
441 441 int water_level() { return water.level(turn); }
442 442 int water_until_rise() { return water.until_rise(turn); }
443 443 int hige_until_rise() { return map.hige.until_rise(turn); }
444 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(); break;
527 - case "Flooding": water_pace_ = ss[1].to!int(); break;
528 - case "Waterproof": max_air_ = ss[1].to!int(); break;
529 - case "Growth": hige_pace_ = ss[1].to!int(); break;
530 - case "Razors": num_razor_ = ss[1].to!int(); break;
531 - default: assert(false);
532 - }
533 - if( ss.length == 4 && ss[0]=="Trampoline" && ss[2]=="targets" )
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_[c] : 0); }
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_ : water_base_;
559 - }
560 - int water_until_rise() {
561 - return water_pace_ ? water_pace_ - turn_%water_pace_ : int.max;
562 - }
563 - int hige_until_rise() {
564 - return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.max;
565 - }
566 - bool is_hige_turn() {
567 - return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : false;
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 : 50L) - turn_; }
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]==' '&&this[y,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-1]==' ') {
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 -}