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