Overview
SHA1 Hash: | b96971b0b690ff1d9131f55f360391b19472b3cb |
---|---|
Date: | 2012-07-16 19:02:57 |
User: | kinaba |
Comment: | refactoring. |
Timelines: | family | ancestors | descendants | both | trunk |
Diffs: | redesign |
Downloads: | Tarball | ZIP archive |
Other Links: | files | file ages | manifest |
Tags And Properties
- branch=trunk inherited from [16f0b5784f]
- sym-trunk inherited from [16f0b5784f]
Changes
Modified maps/static.map from [c02e46733b9bb4b5] to [256615d4a896c7e1].
Modified src/game.d from [d9bf3ea129c7cbc5] to [6849c1cc0eb810a9].
1 import util; 1 import util; 2 2 3 //////////////////////////////////////////////////////////////////////////////// 3 //////////////////////////////////////////////////////////////////////////////// 4 4 > 5 bool is_spacy(char c) > 6 { > 7 return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O'; > 8 } > 9 > 10 bool is_rocky(char c) > 11 { > 12 return c=='*' || c=='@'; > 13 } > 14 > 15 bool is_true_space(char c) > 16 { > 17 return c==' '; > 18 } > 19 > 20 bool is_trampoline_source(char c) > 21 { > 22 return 'A'<=c && c<='I'; > 23 } > 24 > 25 bool is_rocklambda(char c) > 26 { > 27 return is_rocky(c) || c=='\\'; > 28 } > 29 > 30 //////////////////////////////////////////////////////////////////////////////// > 31 5 class Pos 32 class Pos 6 { 33 { 7 public immutable int y, x; 34 public immutable int y, x; 8 mixin DeriveCreate; 35 mixin DeriveCreate; 9 mixin DeriveCompare; 36 mixin DeriveCompare; 10 mixin DeriveShow; 37 mixin DeriveShow; 11 Pos clone() const { return cast(Pos) this; } 38 Pos clone() const { return cast(Pos) this; } ................................................................................................................................................................................ 37 assert( aa[new Pos(1,2)]==2 ); 64 assert( aa[new Pos(1,2)]==2 ); 38 } 65 } 39 66 40 //////////////////////////////////////////////////////////////////////////////// 67 //////////////////////////////////////////////////////////////////////////////// 41 68 42 class Water 69 class Water 43 { 70 { 44 public immutable int base, pace; < 45 mixin DeriveCreate; < 46 mixin DeriveShow; 71 mixin DeriveShow; > 72 > 73 private: > 74 immutable int base, pace; > 75 mixin DeriveCreate; 47 Water clone() const { return cast(Water) this; } 76 Water clone() const { return cast(Water) this; } 48 77 49 static load(string[string] params) 78 static load(string[string] params) 50 { 79 { 51 return new Water(params.get("Water", "0").to!int(), 80 return new Water(params.get("Water", "0").to!int(), 52 params.get("Flooding", "0").to!int()); 81 params.get("Flooding", "0").to!int()); 53 } 82 } ................................................................................................................................................................................ 83 assert( 1 == w.level(5) ); 112 assert( 1 == w.level(5) ); 84 } 113 } 85 114 86 //////////////////////////////////////////////////////////////////////////////// 115 //////////////////////////////////////////////////////////////////////////////// 87 116 88 class Hige 117 class Hige 89 { 118 { 90 public immutable int pace; < 91 mixin DeriveCreate; < 92 mixin DeriveShow; 119 mixin DeriveShow; > 120 > 121 private: > 122 immutable int pace; > 123 mixin DeriveCreate; 93 Hige clone() const { return cast(Hige)this; } 124 Hige clone() const { return cast(Hige)this; } 94 125 95 static load(string[string] params) 126 static load(string[string] params) 96 { 127 { 97 return new Hige(params.get("Growth", "25").to!int()); 128 return new Hige(params.get("Growth", "25").to!int()); 98 } 129 } 99 130 ................................................................................................................................................................................ 108 } 139 } 109 } 140 } 110 141 111 //////////////////////////////////////////////////////////////////////////////// 142 //////////////////////////////////////////////////////////////////////////////// 112 143 113 class Trampoline 144 class Trampoline 114 { 145 { 115 private immutable char[] target_of_; < 116 private immutable char[][] source_of_; < 117 private immutable Pos[] position_of_; < 118 private immutable char[] source_list_; < 119 private immutable char[] target_list_; < 120 mixin DeriveShow; 146 mixin DeriveShow; > 147 > 148 private: > 149 immutable char[] target_of_; > 150 immutable char[][] source_of_; > 151 immutable Pos[] position_of_; > 152 immutable char[] source_list_; > 153 immutable char[] target_list_; 121 Trampoline clone() const { return cast(Trampoline) this; } 154 Trampoline clone() const { return cast(Trampoline) this; } > 155 122 this(Map m, char[char] tramparam) 156 this(Map m, char[char] tramparam) 123 { 157 { 124 auto ta = new char['I'+1]; 158 auto ta = new char['I'+1]; 125 auto sr = new char[]['9'+1]; 159 auto sr = new char[]['9'+1]; 126 auto po = new Pos[max('I','9')+1]; 160 auto po = new Pos[max('I','9')+1]; 127 char[] sl, tl; 161 char[] sl, tl; 128 foreach(fr,to; tramparam) { 162 foreach(fr,to; tramparam) { ................................................................................................................................................................................ 144 target_of_ = cast(immutable) ta; 178 target_of_ = cast(immutable) ta; 145 source_of_ = cast(immutable) sr; 179 source_of_ = cast(immutable) sr; 146 position_of_ = cast(immutable) po; 180 position_of_ = cast(immutable) po; 147 source_list_ = cast(immutable) sl; 181 source_list_ = cast(immutable) sl; 148 target_list_ = cast(immutable) tl; 182 target_list_ = cast(immutable) tl; 149 } 183 } 150 184 151 @property const: | 185 public @property const: 152 const(char[]) source_list() { return source_list_; } 186 const(char[]) source_list() { return source_list_; } 153 const(char[]) target_list() { return target_list_; } 187 const(char[]) target_list() { return target_list_; } 154 const(char[]) source_of(char c) { return source_of_[c]; } 188 const(char[]) source_of(char c) { return source_of_[c]; } 155 char target_of(char c) { return target_of_[c]; } 189 char target_of(char c) { return target_of_[c]; } 156 Pos[] source_pos(char c) { 190 Pos[] source_pos(char c) { 157 Pos[] ps; 191 Pos[] ps; 158 foreach(s; source_of(c)) 192 foreach(s; source_of(c)) ................................................................................................................................................................................ 164 198 165 //////////////////////////////////////////////////////////////////////////////// 199 //////////////////////////////////////////////////////////////////////////////// 166 200 167 class Map 201 class Map 168 { 202 { 169 mixin DeriveShow; 203 mixin DeriveShow; 170 204 171 char[][] data; | 205 private char[][] data; 172 Pos robot; 206 Pos robot; 173 Pos lift; 207 Pos lift; 174 int waterproof; | 208 private int waterproof; 175 int razor; | 209 private int collected_razor; 176 int collected_lambda; 210 int collected_lambda; 177 int total_lambda; 211 int total_lambda; 178 bool cleared; | 212 private bool cleared; 179 Pos[] may_update; | 213 private Pos[] may_update; 180 214 181 Map clone() const { return new Map(this); } | 215 private Map clone() const { return new Map(this); } 182 this(in Map m) { | 216 private this(in Map m) { 183 foreach(s; m.data) 217 foreach(s; m.data) 184 this.data ~= s.dup; 218 this.data ~= s.dup; 185 this.robot = m.robot.clone(); | 219 this.robot = m.robot.clone(); 186 this.lift = m.lift.clone(); | 220 this.lift = m.lift.clone(); 187 this.waterproof = m.waterproof; 221 this.waterproof = m.waterproof; 188 this.razor = m.razor; | 222 this.collected_razor = m.collected_razor; 189 this.collected_lambda = m.collected_lambda; 223 this.collected_lambda = m.collected_lambda; 190 this.total_lambda = m.total_lambda; | 224 this.total_lambda = m.total_lambda; > 225 this.cleared = m.cleared; 191 this.may_update = (cast(Map)m).may_update.dup; 226 this.may_update = (cast(Map)m).may_update.dup; 192 this.cleared = m.cleared; < 193 } 227 } 194 228 > 229 const { > 230 @property { > 231 int H() { return data.length; } > 232 int W() { return data[0].length; } > 233 int num_razor() { return collected_razor; } > 234 > 235 Pos[] razors() { return objects('!'); } > 236 Pos[] lambdas() { return objects('\\'); } > 237 } > 238 > 239 Pos[] objects(char c) { > 240 Pos[] ans; > 241 for(int y=1; y<=H; ++y) > 242 for(int x=1; x<=W; ++x) > 243 if(this[y,x] == c) > 244 ans ~= new Pos(y,x); > 245 return ans; > 246 } > 247 > 248 char opIndex(int y, int x) { > 249 --y, --x; > 250 if(y<0||H<=y||x<0||W<=x) > 251 return '#'; > 252 return data[H-1-y][x]; > 253 } > 254 > 255 char opIndex(in Pos p) { > 256 return this[p.y, p.x]; > 257 } > 258 } > 259 > 260 private: 195 this(string[] raw_data, string[string] params, char[char] trampo) 261 this(string[] raw_data, string[string] params, char[char] trampo) 196 { 262 { 197 int width = 0; 263 int width = 0; 198 foreach(r; raw_data) 264 foreach(r; raw_data) 199 width = max(width, r.length); 265 width = max(width, r.length); 200 foreach(r; raw_data) { 266 foreach(r; raw_data) { 201 this.data ~= r.dup; 267 this.data ~= r.dup; ................................................................................................................................................................................ 207 for(int x=1; x<=W; ++x) { 273 for(int x=1; x<=W; ++x) { 208 if(this[y,x] == 'R') 274 if(this[y,x] == 'R') 209 this.robot = new Pos(y,x); 275 this.robot = new Pos(y,x); 210 if(this[y,x] == 'L' || this[y,x] == 'O') 276 if(this[y,x] == 'L' || this[y,x] == 'O') 211 this.lift = new Pos(y,x); 277 this.lift = new Pos(y,x); 212 if(this[y,x] == '\\' || this[y,x] == '@') 278 if(this[y,x] == '\\' || this[y,x] == '@') 213 total_lambda++; 279 total_lambda++; 214 if(this[y,x] == '*' || this[y,x] == '@') | 280 if(is_rocky(this[y,x])) 215 may_update ~= new Pos(y,x); 281 may_update ~= new Pos(y,x); 216 } 282 } 217 283 218 this.waterproof = params.get("Waterproof", "5").to!int(); | 284 this.waterproof = params.get("Waterproof", "5").to!int(); 219 this.razor = params.get("Razors", "0").to!int(); | 285 this.collected_razor = params.get("Razors", "0").to!int(); 220 } < 221 < 222 const @property { < 223 int H() { return data.length; } < 224 int W() { return data[0].length; } < 225 } < 226 < 227 const { < 228 char opIndex(int y, int x) < 229 { < 230 // Adjust coordinate to the spec. bottom-left is (1,1). < 231 --y, --x; < 232 if(y<0||H<=y||x<0||W<=x) < 233 return '#'; < 234 return data[H-1-y][x]; < 235 } < 236 < 237 char opIndex(in Pos p) < 238 { < 239 return this[p.y, p.x]; < 240 } < 241 } 286 } 242 287 243 void opIndexAssign(char c, int y, int x) 288 void opIndexAssign(char c, int y, int x) 244 { 289 { 245 // Adjust coordinate to the spec. bottom-left is (1,1). < 246 --y, --x; 290 --y, --x; 247 if(y<0||H<=y||x<0||W<=x) 291 if(y<0||H<=y||x<0||W<=x) 248 return; 292 return; 249 data[H-1-y][x] = c; 293 data[H-1-y][x] = c; 250 } 294 } 251 295 252 void opIndexAssign(char c, in Pos p) 296 void opIndexAssign(char c, in Pos p) 253 { 297 { 254 this[p.y, p.x] = c; 298 this[p.y, p.x] = c; 255 } 299 } 256 300 257 Pos[] objects(char c) const { < 258 Pos[] ans; < 259 for(int y=1; y<=H; ++y) < 260 for(int x=1; x<=W; ++x) < 261 if(this[y,x] == c) < 262 ans ~= new Pos(y,x); < 263 return ans; < 264 } < 265 < 266 Pos[] razors() const { return objects('!'); } < 267 Pos[] lambdas() const { return objects('\\'); } < 268 < 269 bool command(char c, int turn, bool hige_day, in Trampoline tr) 301 bool command(char c, int turn, bool hige_day, in Trampoline tr) 270 { 302 { 271 assert( this[robot] == 'R' ); | 303 switch(c) > 304 { 272 if(c=='R') return move( 0, +1, hige_day, tr); | 305 case 'R': return move( 0, +1, hige_day, tr); 273 if(c=='L') return move( 0, -1, hige_day, tr); | 306 case 'L': return move( 0, -1, hige_day, tr); 274 if(c=='U') return move(+1, 0, hige_day, tr); | 307 case 'U': return move(+1, 0, hige_day, tr); 275 if(c=='D') return move(-1, 0, hige_day, tr); | 308 case 'D': return move(-1, 0, hige_day, tr); 276 if(c=='W') return move( 0, 0, hige_day, tr); | 309 case 'W': return move( 0, 0, hige_day, tr); 277 if(c=='S') return use_razor(hige_day); | 310 case 'S': return use_razor(hige_day); 278 assert(false); | 311 default: assert(false); > 312 } 279 } 313 } 280 314 281 bool use_razor(bool hige_day) 315 bool use_razor(bool hige_day) 282 { 316 { 283 if(razor) { | 317 if(collected_razor > 0) > 318 { 284 razor--; | 319 collected_razor--; 285 for(int dy=-1; dy<=+1; ++dy) 320 for(int dy=-1; dy<=+1; ++dy) 286 for(int dx=-1; dx<=+1; ++dx) 321 for(int dx=-1; dx<=+1; ++dx) 287 if(this[robot.y+dy,robot.x+dx] == 'W') { 322 if(this[robot.y+dy,robot.x+dx] == 'W') { 288 emptified(new Pos(robot.y+dy,robot.x+dx) 323 emptified(new Pos(robot.y+dy,robot.x+dx) 289 this[robot.y+dy,robot.x+dx] = ' '; 324 this[robot.y+dy,robot.x+dx] = ' '; 290 } 325 } 291 } 326 } 292 < 293 return update(hige_day); 327 return update(hige_day); 294 } 328 } 295 329 296 bool rocky(char c) { return c=='*' || c=='@'; } | 330 // Register a position that may become empty in the last turn. > 331 void emptified(Pos p) 297 | 332 { 298 void emptified(Pos p) { < 299 for(int dy=0; dy<=+1; ++dy) | 333 for(int dy=0; dy<=+1; ++dy) 300 for(int dx=-1; dx<=+1; ++dx) | 334 for(int dx=-1; dx<=+1; ++dx) 301 may_update ~= new Pos(p.y+dy, p.x+dx); | 335 may_update ~= new Pos(p.y+dy, p.x+dx); 302 } | 336 } 303 337 304 bool move(int dy, int dx, bool hige_day, in Trampoline tr) 338 bool move(int dy, int dx, bool hige_day, in Trampoline tr) 305 { 339 { 306 emptified(robot); | 340 Pos next = new Pos(robot.y+dy, robot.x+dx); > 341 int y=robot.y, x=robot.x; 307 | 342 308 int y = robot.y; < 309 int x = robot.x; < 310 if( '\\' == this[y+dy,x+dx] ) < 311 collected_lambda++; | 343 if( '\\' == this[next] ) collected_lambda++; 312 if( '!' == this[y+dy,x+dx] ) | 344 if( '!' == this[next] ) collected_razor++; 313 razor++; < 314 if( 'O' == this[y+dy,x+dx] ) < 315 cleared = true; | 345 if( 'O' == this[next] ) cleared = true; 316 if( " \\!.O".count(this[y+dy,x+dx])==1 ) { < > 346 > 347 if( is_spacy(this[next]) ) > 348 { > 349 emptified(robot); 317 this[y,x]=' '; | 350 this[y,x] = ' '; 318 this[y+dy,x+dx]='R'; < > 351 this[next] = 'R'; 319 robot = new Pos(y+dy,x+dx); | 352 robot = next; > 353 } 320 } else if(dy==0 && rocky(this[y+dy,x+dx]) && ' '==this[y+dy*2,x+ | 354 else if(dy==0 && is_rocky(this[next]) && ' '==this[y+dy*2,x+dx*2 > 355 { 321 char rock = this[y+dy,x+dx]; | 356 char rock = this[next]; > 357 emptified(robot); 322 this[y,x]=' '; | 358 this[y,x] = ' '; 323 this[y+dy,x+dx]='R'; < > 359 this[next] = 'R'; 324 this[y+dy*2,x+dx*2]=rock; | 360 this[y+dy*2,x+dx*2] = rock; 325 robot = new Pos(y+dy,x+dx); | 361 robot = next; 326 may_update ~= new Pos(y+dy*2,x+dx*2); 362 may_update ~= new Pos(y+dy*2,x+dx*2); 327 } else if('A'<=this[y+dy,x+dx] && this[y+dy,x+dx]<='I') { < > 363 } > 364 else if(is_trampoline_source(this[next])) > 365 { > 366 emptified(robot); 328 this[y,x]=' '; | 367 this[y,x] = ' '; 329 Pos tp = tr.target_pos(this[y+dy,x+dx]); | 368 Pos tp = tr.target_pos(this[next]); 330 foreach(p; tr.source_pos(this[tp])) { | 369 foreach(p; tr.source_pos(this[tp])) > 370 { 331 emptified(p); 371 emptified(p); 332 this[p] = ' '; 372 this[p] = ' '; 333 } 373 } 334 this[tp] = 'R'; 374 this[tp] = 'R'; 335 robot = tp; | 375 robot = tp; 336 } 376 } 337 return update(hige_day); 377 return update(hige_day); 338 } 378 } 339 379 340 bool update(bool hige_day) 380 bool update(bool hige_day) 341 { 381 { 342 // Write after all the updates are processed. 382 // Write after all the updates are processed. ................................................................................................................................................................................ 343 Tuple!(int,int,char)[] write_buffer; 383 Tuple!(int,int,char)[] write_buffer; 344 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); 384 void write(int y, int x, char c) { write_buffer ~= tuple(y,x,c); 345 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c 385 void writep(Pos p, char c) { write_buffer ~= tuple(0+p.y,0+p.x,c 346 scope(exit) { 386 scope(exit) { 347 may_update.length = 0; 387 may_update.length = 0; 348 foreach(wr; write_buffer) { 388 foreach(wr; write_buffer) { 349 this[wr[0],wr[1]] = wr[2]; 389 this[wr[0],wr[1]] = wr[2]; 350 if(rocky(wr[2])) | 390 if(is_rocky(wr[2])) 351 may_update ~= new Pos(wr[0],wr[1]); 391 may_update ~= new Pos(wr[0],wr[1]); 352 if(wr[2]==' ') 392 if(wr[2]==' ') 353 emptified(new Pos(wr[0], wr[1])); 393 emptified(new Pos(wr[0], wr[1])); 354 } 394 } 355 } 395 } 356 396 357 if(collected_lambda == total_lambda) 397 if(collected_lambda == total_lambda) ................................................................................................................................................................................ 366 may_update ~= new Pos(y,x); 406 may_update ~= new Pos(y,x); 367 } 407 } 368 408 369 sort(may_update); 409 sort(may_update); 370 foreach(p; may_update) { 410 foreach(p; may_update) { 371 int y = p.y, x = p.x; 411 int y = p.y, x = p.x; 372 char rock = this[p]; 412 char rock = this[p]; 373 if(rocky(this[p])) { | 413 if(is_rocky(this[p])) { 374 if(this[p.D]==' ') { 414 if(this[p.D]==' ') { 375 writep(p, ' '); 415 writep(p, ' '); 376 writep(p.D, (rock=='@'&&this[p.D.D]!=' ' 416 writep(p.D, (rock=='@'&&this[p.D.D]!=' ' 377 if(robot == p.D.D) 417 if(robot == p.D.D) 378 dead=true; 418 dead=true; 379 } 419 } 380 else if((rocky(this[p.D]) || this[p.D]=='\\') && | 420 else if((is_rocky(this[p.D]) || this[p.D]=='\\') 381 writep(p, ' '); 421 writep(p, ' '); 382 writep(p.R.D,(rock=='@'&&this[p.R.D.D]!= 422 writep(p.R.D,(rock=='@'&&this[p.R.D.D]!= 383 if(robot == p.R.D.D) 423 if(robot == p.R.D.D) 384 dead=true; 424 dead=true; 385 } 425 } 386 else if(rocky(this[p.D]) && this[p.L]==' ' && th | 426 else if(is_rocky(this[p.D]) && this[p.L]==' ' && 387 writep(p, ' '); 427 writep(p, ' '); 388 writep(p.L.D, (rock=='@'&&this[p.L.D.D]! 428 writep(p.L.D, (rock=='@'&&this[p.L.D.D]! 389 if(robot == p.L.D.D) 429 if(robot == p.L.D.D) 390 dead=true; 430 dead=true; 391 } 431 } 392 } 432 } 393 else if(this[p]=='W') { 433 else if(this[p]=='W') {
Modified src/gui.d from [2b6041f7525bfa95] to [91ff36ba7e144853].
117 117 118 // Update textual info. 118 // Update textual info. 119 this.text = .text( 119 this.text = .text( 120 "Score: ", g.score, 120 "Score: ", g.score, 121 " Air: ", g.hp, 121 " Air: ", g.hp, 122 " Tide: ", g.water_until_rise, 122 " Tide: ", g.water_until_rise, 123 " Wadler: ", g.hige_until_rise, 123 " Wadler: ", g.hige_until_rise, 124 " Razor: ", g.map.razor); | 124 " Razor: ", g.map.num_razor); 125 invalidate(); 125 invalidate(); 126 } 126 } 127 127 128 private: 128 private: 129 void setup_keyhandling(void delegate(char c) command) 129 void setup_keyhandling(void delegate(char c) command) 130 { 130 { 131 noMessageFilter(); 131 noMessageFilter();
Modified src/solver.d from [da568e3b806540de] to [97e58dfa28df65c7].
7 interface Solver 7 interface Solver 8 { 8 { 9 // this(in Game g); 9 // this(in Game g); 10 char single_step(); 10 char single_step(); 11 void force(char c); 11 void force(char c); 12 } 12 } 13 13 14 < 15 bool is_spacy(char c) < 16 { < 17 return c==' ' || c=='.' || c=='R' || c=='!' || c=='\\' || c=='O'; < 18 } < 19 < 20 bool is_rocky(char c) < 21 { < 22 return c=='*' || c=='@'; < 23 } < 24 < 25 bool is_true_space(char c) < 26 { < 27 return c==' '; < 28 } < 29 < 30 bool is_trampoline_source(char c) < 31 { < 32 return 'A'<=c && c<='I'; < 33 } < 34 < 35 bool is_rocklambda(char c) < 36 { < 37 return is_rocky(c) || c=='\\'; < 38 } < 39 < 40 Tuple!(string,int) death_move(in Game g) 14 Tuple!(string,int) death_move(in Game g) 41 { 15 { 42 // TODO: S 16 // TODO: S 43 17 44 string death; 18 string death; 45 int breath; 19 int breath; 46 int y = g.map.robot.y; 20 int y = g.map.robot.y; ................................................................................................................................................................................ 186 if( g.map.collected_lambda == g.map.total_lambda ) { 160 if( g.map.collected_lambda == g.map.total_lambda ) { 187 cand = search(g, ro, [li], death); 161 cand = search(g, ro, [li], death); 188 } else if( !la.empty ){ 162 } else if( !la.empty ){ 189 cand ~= search(g, ro, la~ra, death); 163 cand ~= search(g, ro, la~ra, death); 190 } 164 } 191 165 192 // 'higesori' mode 166 // 'higesori' mode 193 if( !hi.empty && g.map.razor>0 ) { | 167 if( !hi.empty && g.map.num_razor>0 ) { 194 int his = 0; 168 int his = 0; 195 for(int dy=-1; dy<=+1; ++dy) 169 for(int dy=-1; dy<=+1; ++dy) 196 for(int dx=-1; dx<=+1; ++dx) 170 for(int dx=-1; dx<=+1; ++dx) 197 if(g.map[ro.y+dy,ro.x+dx] == 'W') 171 if(g.map[ro.y+dy,ro.x+dx] == 'W') 198 his++; 172 his++; 199 173 200 if(his>=2 || his==hi.length) 174 if(his>=2 || his==hi.length)