Diff
Not logged in

Differences From Artifact [e25c75ea96d80507]:

To Artifact [9428bbab7d2bc9a8]:


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 }