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 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 + int water_level() {
550 + return water_pace_ ? water_base_ + turn_/water_pace_ : water_base_;
551 + }
552 + int water_until_rise() {
553 + return water_pace_ ? water_pace_ - turn_%water_pace_ : int.max;
554 + }
555 + int hige_until_rise() {
556 + return hige_pace_ ? hige_pace_ - turn_%hige_pace_ : int.max;
557 + }
558 + bool is_hige_turn() {
559 + return hige_pace_ ? turn_%hige_pace_ == hige_pace_-1 : false;
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 : 50L) - turn_; }
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]==' '&&this[y,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-1]==' ') {
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 +}