Check-in [ff0ab77d3d]
Not logged in
Overview
SHA1 Hash:ff0ab77d3d8809af945fc63b6c56a3863b5f3a2e
Date: 2012-07-15 20:17:59
User: kinaba
Comment:new game class.
Timelines: family | ancestors | descendants | both | trunk
Diffs: redesign
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified score_memo.txt from [d46da9814cb8619d] to [95f0626c958d6d31].

1 contest1 212! 1 contest1 212! 2 contest2 280? 2 contest2 280? 3 contest3 275! 3 contest3 275! 4 contest4 561? 4 contest4 561? 5 contest5 1281? 5 contest5 1281? 6 contest6 737 | 6 contest6 737 // deadend trap 7 contest7 867? 7 contest7 867? 8 contest8 1245 | 8 contest8 1245 // tricky 9 contest9 3042? 9 contest9 3042? 10 contest10 2076 | 10 contest10 2076 // * on lambda, must move * first 11 flood1 569 | 11 flood1 569 // too slow, because of 1-left danger lambda 12 flood2 280? 12 flood2 280? 13 flood3 802 | 13 flood3 802 // too slow, drown 14 flood4 970 | 14 flood4 970 // incorrect order of digging 15 flood5 561? 15 flood5 561? 16 trampoline1 291 | 16 trampoline1 291 // * on trampoline. must move * first 17 trampoline2 1728? 17 trampoline2 1728? 18 trampoline3 698 | 18 trampoline3 698 // * on trampoline target. must move * first. 19 beard1 856? 19 beard1 856? 20 beard2 2792 | 20 beard2 2792 // hutsu-ni muzui 21 beard3 811 | 21 beard3 811 // tricky. must hurry to cut hige. 22 beard4 677 | 22 beard4 677 // deadend trap

Modified src/cui_auto_main.d from [b38d60ea39d11e6e] to [80ad58f91e39ad66].

14 fin = finished; 14 fin = finished; 15 } 15 } 16 } 16 } 17 17 18 void main(string[] args) 18 void main(string[] args) 19 { 19 { 20 Driver d = new Driver(stdin); 20 Driver d = new Driver(stdin); 21 d.addObserver!(GuardedOutput)(); | 21 // d.addObserver!(GuardedOutput)(); > 22 d.addObserver!(StdOutput)(); 22 auto c = d.addObserver!(CUI!MainSolver)(); | 23 // auto c = d.addObserver!(CUI!MainSolver)(); > 24 auto c = d.addObserver!(CUI!Solver_0)(); 23 while(!c.fin) 25 while(!c.fin) 24 d.command(c.solver.single_step()); 26 d.command(c.solver.single_step()); 25 } 27 }

Modified src/game.d from [e25c75ea96d80507] to [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 }

Modified src/gui.d from [d4577900b4db97c1] to [e84cacd6262f93a7].

4 import driver; 4 import driver; 5 5 6 class GUI(Solver) : Form, GameObserver 6 class GUI(Solver) : Form, GameObserver 7 { 7 { 8 this(in Game g) 8 this(in Game g) 9 { 9 { 10 this.solver = new Solver(g); 10 this.solver = new Solver(g); 11 setup_size(g.map.W, g.map.H); | 11 setup_size(g.W, g.H); 12 setup_resources(g); 12 setup_resources(g); 13 draw(g); 13 draw(g); 14 } 14 } 15 15 16 private void delegate(char c) fn; 16 private void delegate(char c) fn; 17 void set_fn(F)(F f) { this.fn = f; } 17 void set_fn(F)(F f) { this.fn = f; } 18 18 ................................................................................................................................................................................ 79 this.render['\\'] = "λ"; 79 this.render['\\'] = "λ"; 80 this.render['R'] = "☃"; 80 this.render['R'] = "☃"; 81 this.render['d'] = "☠"; 81 this.render['d'] = "☠"; 82 this.render['L'] = "☒"; 82 this.render['L'] = "☒"; 83 this.render['O'] = "☐"; 83 this.render['O'] = "☐"; 84 this.render['W'] = "ꔣ"; 84 this.render['W'] = "ꔣ"; 85 this.render['!'] = "✄"; 85 this.render['!'] = "✄"; 86 foreach(c,tp; g.map.tr_target) { < 87 char d = g.map[tp]; < 88 this.render[c] = [cast(dchar)('☢'+d-'1')].to!string(); | 86 foreach(char c; 'A'..'J') this.render[c] = [cast(dchar)('☢'+g.tr 89 } < 90 foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1 87 foreach(char c; '1'..':') this.render[c] = [cast(dchar)('☢'+c-'1 91 this.paint ~= (Control c, PaintEventArgs ev) { 88 this.paint ~= (Control c, PaintEventArgs ev) { 92 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientS 89 graphicContext.copyTo(ev.graphics, Rect(0,0,this.clientS 93 }; 90 }; 94 } 91 } 95 92 96 void draw(in Game g) 93 void draw(in Game g) ................................................................................................................................................................................ 102 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH) 99 graphicContext.fillRectangle(this.backColor, Rect(0,0,scrW,scrH) 103 100 104 // Fill water. 101 // Fill water. 105 int w = g.water_level(); 102 int w = g.water_level(); 106 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell 103 graphicContext.fillRectangle(this.colors['w'], Rect(0, scrH-cell 107 104 108 // Paint map. 105 // Paint map. 109 for(int y=1; y<=g.map.H; ++y) | 106 for(int y=1; y<=g.H; ++y) 110 for(int x=1; x<=g.map.W; ++x) { | 107 for(int x=1; x<=g.W; ++x) { 111 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 108 Rect r = Rect(cell*(x-1), scrH-cell*y, cell, cell); 112 char c = g.map[y,x]; | 109 char c = g[y,x]; 113 if( c != ' ' ) { 110 if( c != ' ' ) { 114 if( c == 'R' && g.dead ) 111 if( c == 'R' && g.dead ) 115 c = 'd'; 112 c = 'd'; 116 graphicContext.drawText(this.render[c], font, th 113 graphicContext.drawText(this.render[c], font, th 117 } 114 } 118 } 115 } 119 116 120 // Update textual info. 117 // Update textual info. 121 this.text = .text( 118 this.text = .text( 122 "Score: ", g.score, 119 "Score: ", g.score, 123 " Air: ", g.hp, 120 " Air: ", g.hp, 124 " Tide: ", g.water_until_rise, 121 " Tide: ", g.water_until_rise, 125 " Wadler: ", g.hige_until_rise, 122 " Wadler: ", g.hige_until_rise, 126 " Razor: ", g.map.razor); | 123 " Razor: ", g.num_razor); 127 invalidate(); 124 invalidate(); 128 } 125 } 129 126 130 private: 127 private: 131 void setup_keyhandling() 128 void setup_keyhandling() 132 { 129 { 133 noMessageFilter(); 130 noMessageFilter();

Modified src/gui_main.d from [05082d0f328d756c] to [1d7ea5dfabc56eb4].

4 import solver; 4 import solver; 5 import std.stdio; 5 import std.stdio; 6 pragma(lib, "dfl.lib"); 6 pragma(lib, "dfl.lib"); 7 7 8 void main(string[] args) 8 void main(string[] args) 9 { 9 { 10 Driver d = new Driver(stdin); 10 Driver d = new Driver(stdin); 11 d.addObserver!(GuardedOutput)(); | 11 // d.addObserver!(GuardedOutput)(); > 12 d.addObserver!(StdOutput)(); 12 auto g = d.addObserver!(GUI!MainSolver)(); | 13 // auto g = d.addObserver!(GUI!MainSolver)(); > 14 auto g = d.addObserver!(GUI!Solver_0)(); 13 g.set_fn(&d.command); 15 g.set_fn(&d.command); 14 g.run(); 16 g.run(); 15 } 17 }

Modified src/output.d from [045b845268918546] to [b301f73c74ef62f4].

14 this(in Game g) {} 14 this(in Game g) {} 15 override void on_game_changed(char c, in Game g, bool finished) 15 override void on_game_changed(char c, in Game g, bool finished) 16 { 16 { 17 stdout.write(c); 17 stdout.write(c); 18 stdout.flush(); 18 stdout.flush(); 19 } 19 } 20 } 20 } 21 < > 21 /* 22 class GuardedOutput : GameObserver 22 class GuardedOutput : GameObserver 23 { 23 { 24 this(in Game g) 24 this(in Game g) 25 { 25 { 26 setup_sigint_handling(); 26 setup_sigint_handling(); 27 score_log ~= g.score; 27 score_log ~= g.score; 28 flushed = false; 28 flushed = false; ................................................................................................................................................................................ 68 { 68 { 69 assert(g_output is null); 69 assert(g_output is null); 70 g_output = this; 70 g_output = this; 71 extern(C) static void catch_sigint(int) { g_output.flush(); appl 71 extern(C) static void catch_sigint(int) { g_output.flush(); appl 72 core.stdc.signal.signal(SIGINT, &catch_sigint); 72 core.stdc.signal.signal(SIGINT, &catch_sigint); 73 } 73 } 74 } 74 } > 75 */

Modified src/solver.d from [393baf841678f948] to [42b4ef037737dcd0].

3 3 4 class Solver_0 4 class Solver_0 5 { 5 { 6 this(in Game g) {} 6 this(in Game g) {} 7 char single_step() { return 'W'; } 7 char single_step() { return 'W'; } 8 void force(char c) {} 8 void force(char c) {} 9 } 9 } 10 < > 10 /* 11 class Solver_1 11 class Solver_1 12 { 12 { 13 int wait_count = 0; 13 int wait_count = 0; 14 int choke_count = 0; 14 int choke_count = 0; 15 15 16 Game g; 16 Game g; 17 this(in Game g) 17 this(in Game g) ................................................................................................................................................................................ 383 plan_broken = true; 383 plan_broken = true; 384 } 384 } 385 else 385 else 386 plan = plan[1..$]; 386 plan = plan[1..$]; 387 } 387 } 388 } 388 } 389 389 390 alias Solver_2!(Solver_1) MainSolver; | 390 //alias Solver_2!(Solver_1) MainSolver; 391 //alias Solver_1 MainSolver; | 391 alias Solver_1 MainSolver; > 392 */

Modified src/util.d from [41ba420d0c49ce8d] to [b76be1f6ad977d56].

3 public import std.conv; 3 public import std.conv; 4 public import std.range; 4 public import std.range; 5 public import std.stdio; 5 public import std.stdio; 6 public import std.string; 6 public import std.string; 7 public import std.typecons; 7 public import std.typecons; 8 public import std.math; 8 public import std.math; 9 import std.c.stdlib; 9 import std.c.stdlib; > 10 > 11 T[] erase(T,V)(T[] xs, V y) > 12 { > 13 foreach(i,x; xs) > 14 if(x == y) > 15 return xs[0..i]~xs[i+1..$]; > 16 return xs; > 17 } 10 18 11 // To avoide the following ICE: 19 // To avoide the following ICE: 12 // src\phobos\std\algorithm.d(4552): 20 // src\phobos\std\algorithm.d(4552): 13 // Error: function std.algorithm.count!("a == b",string,char).count 21 // Error: function std.algorithm.count!("a == b",string,char).count 14 // compiler error, parameter 'value', bugzilla 2962? 22 // compiler error, parameter 'value', bugzilla 2962? 15 // Assertion failure: '0' on line 717 in file 'glue.c' 23 // Assertion failure: '0' on line 717 in file 'glue.c' 16 int count(T,V)(T[] a, V v) 24 int count(T,V)(T[] a, V v)