Diff
Not logged in

Differences From Artifact [e25c75ea96d80507]:

To Artifact [9428bbab7d2bc9a8]:


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 +}