ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/kgsueme/game.pl
(Generate patch)

Comparing kgsueme/kgsueme/game.pl (file contents):
Revision 1.104 by pcg, Sun May 30 07:24:06 2004 UTC vs.
Revision 1.107 by root, Mon May 31 02:04:40 2004 UTC

21 21
22 $self->{set} = sub { }; 22 $self->{set} = sub { };
23 $self->{format} = sub { "???" }; 23 $self->{format} = sub { "???" };
24} 24}
25 25
26sub FINALIZE_INSTANCE {
27 my $self = shift;
28
29 $self->stop;
30}
31
26sub configure { 32sub configure {
27 my ($self, $timesys, $main, $interval, $count) = @_; 33 my ($self, $timesys, $main, $interval, $count) = @_;
28 34
29 if ($timesys == TIMESYS_ABSOLUTE) { 35 if ($timesys == TIMESYS_ABSOLUTE) {
30 $self->{set} = sub { $self->{time} = $_[0] }; 36 $self->{format} = sub {
31 $self->{format} = sub { util::format_time $_[0] }; 37 if ($_[0] <= 0) {
38 "TIMEOUT";
39 } else {
40 util::format_time $_[0];
41 }
42 };
32 43
33 } elsif ($timesys == TIMESYS_BYO_YOMI) { 44 } elsif ($timesys == TIMESYS_BYO_YOMI) {
34 my $low = $interval * $count; 45 my $low = $interval * $count;
35 46
36 $self->{set} = sub { $self->{time} = $_[0] };
37
38 $self->{format} = sub { 47 $self->{format} = sub {
48 if ($_[0] <= 0) {
49 "TIMEOUT";
39 if ($_[0] > $low) { 50 } elsif ($_[0] > $low) {
40 util::format_time $_[0] - $low; 51 util::format_time $_[0] - $low;
41 } else { 52 } else {
42 sprintf "%s (%d)", 53 sprintf "%s (%d)",
43 util::format_time int (($_[0] - 1) % $interval + 1), 54 util::format_time int (($_[0] - 1) % $interval + 1),
44 ($_[0] - 1) / $interval; 55 ($_[0] - 1) / $interval;
45 } 56 }
46 }; 57 };
47 58
48 } elsif ($timesys == TIMESYS_CANADIAN) { 59 } elsif ($timesys == TIMESYS_CANADIAN) {
49 $self->{set} = sub { $self->{time} = $_[0]; $self->{moves} = $_[1] };
50
51 $self->{format} = sub { 60 $self->{format} = sub {
61 if ($_[0] <= 0) {
62 "TIMEOUT";
52 if (!$self->{moves}) { 63 } elsif (!$self->{moves}) {
53 util::format_time $_[0] - $low; 64 util::format_time $_[0] - $low;
54 } else { 65 } else {
55 my $time = int (($_[0] - 1) % $interval + 1); 66 my $time = int (($_[0] - 1) % $interval + 1);
56 67
57 sprintf "%s/%d =%d", 68 sprintf "%s/%d =%d",
63 } 74 }
64 }; 75 };
65 76
66 } else { 77 } else {
67 # none, or unknown 78 # none, or unknown
68 $self->{set} = sub { };
69 $self->{format} = sub { "---" } 79 $self->{format} = sub { "-" }
70 } 80 }
71} 81}
72 82
73sub refresh { 83sub refresh {
74 my ($self, $timestamp) = @_; 84 my ($self, $timestamp) = @_;
76 86
77 # we round the timer value slightly... the protocol isn't exact anyways, 87 # we round the timer value slightly... the protocol isn't exact anyways,
78 # and this gives smoother timers ;) 88 # and this gives smoother timers ;)
79 my $timer2 = int $timer + 0.4; 89 my $timer2 = int $timer + 0.4;
80 90
81 if ($timer2 <= 0) { 91 $self->set_text ($self->{format}->($timer2));
82 $timer2 = 0 if $timer2 < 0; 92
83 $self->set_text ("TIME OUT"); 93 $timer - int $timer;
94}
95
96sub set_time {
97 my ($self, $start, $time, $moves) = @_;
98
99 $self->{time} = $time;
100 $self->{moves} = $moves;
101
102 if ($start) {
103 $self->{start} = $start;
104 $self->start;
84 } else { 105 } else {
85 $self->set_text ($self->{format}->($timer2)); 106 $self->stop;
86 }
87
88 $timer - int $timer;
89}
90
91sub set_time {
92 my ($self, $time, $moves) = @_;
93
94 # we ignore requests to re-set the time of a running clock.
95 # this is the easiest way to ensure that commentary etc.
96 # doesn't re-set the clock. yes, this is frickle design,
97 # but I think the protocol is to blame here, which gives
98 # very little time information. (cgoban2 also has had quite
99 # a lot of small time update problems...)
100 unless ($self->{timeout}) {
101 $self->{set}->($time, $moves);
102 $self->refresh ($self->{start}); 107 $self->refresh ($self->{start});
103 } 108 }
104} 109}
105 110
106sub start { 111sub start {
107 my ($self, $when) = @_; 112 my ($self) = @_;
108 113
109 $self->stop; 114 $self->stop;
110
111 $self->{start} = $when;
112 115
113 my $timeout; $timeout = sub { 116 my $timeout; $timeout = sub {
114 my $next = $self->refresh (Time::HiRes::time) * 1000; 117 my $next = $self->refresh (Time::HiRes::time) * 1000;
115 $next += 1000 if $next < 0; 118 $next += 1000 if $next < 0;
116 $self->{timeout} = add Glib::Timeout $next, $timeout; 119 $self->{timeout} = add Glib::Timeout $next, $timeout;
180 183
181 $self->{info}->set_text ("$captures pris."); 184 $self->{info}->set_text ("$captures pris.");
182} 185}
183 186
184sub set_timer { 187sub set_timer {
185 my ($self, $when, $time, $moves) = @_; 188 my ($self, $start, $time, $moves) = @_;
186 189
187 $self->{clock}->stop unless $when;
188 $self->{clock}->set_time ($time, $moves); 190 $self->{clock}->set_time ($start, $time, $moves);
189 $self->{clock}->start ($when) if $when;
190} 191}
191 192
192package game; 193package game;
193 194
194use Scalar::Util qw(weaken); 195use Scalar::Util qw(weaken);
356 357
357 delete $self->{board_click}; 358 delete $self->{board_click};
358 359
359 if ($self->{teacher} eq $self->{app}{conn}) { 360 if ($self->{teacher} eq $self->{app}{conn}) {
360 #TODO# # teaching mode not implemented 361 #TODO# # teaching mode not implemented
361 $self->{button_pass}->set (label => "Pass", sensitive => 1, visible => 1); 362 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1);
362 $self->{button_undo}->hide; 363 $self->{button_undo}->hide;
363 $self->{button_resign}->hide; 364 $self->{button_resign}->hide;
364 $self->{board}->set (cursor => undef); 365 $self->{board}->set (cursor => undef);
365 366
366 } elsif ($running && $self->{colour} != COLOUR_NONE) { 367 } elsif ($running && $self->{colour} != COLOUR_NONE) {
368 $self->{button_undo}->show; 369 $self->{button_undo}->show;
369 $self->{button_resign}->show; 370 $self->{button_resign}->show;
370 371
371 if ($self->{cur_board}{score}) { 372 if ($self->{cur_board}{score}) {
372 # during scoring 373 # during scoring
373 $self->{button_pass}->set (label => "Done", sensitive => 1, visible => 1); 374 $self->{button_pass}->set (label => "Done", visible => 1, sensitive => 1);
374 $self->{board}->set (cursor => sub { 375 $self->{board}->set (cursor => sub {
375 $_[0] & (MARK_B | MARK_W) 376 $_[0] & (MARK_B | MARK_W)
376 ? $_[0] ^ MARK_GRAYED 377 ? $_[0] ^ MARK_GRAYED
377 : $_[0]; 378 : $_[0];
378 }); 379 });
379 $self->{board_click} = sub { 380 $self->{board_click} = sub {
380 if ($_[0] == 255) { 381 if ($_[0] == 255) {
381 $self->{button_pass}->sensitive (0); 382 $self->{button_pass}->sensitive (0);
383 warn sprintf "SEND DONE @{$self->{done}} %x\n", $self->{doneid};#d#
382 $self->done; 384 $self->done;
383 } else { 385 } else {
384 $self->send (mark_dead => 386 $self->send (mark_dead =>
385 channel => $self->{channel}, 387 channel => $self->{channel},
386 x => $_[0], 388 x => $_[0],
388 dead => !($self->{cur_board}{board}[$_[0]][$_[1]] & MARK_GRAYED), 390 dead => !($self->{cur_board}{board}[$_[0]][$_[1]] & MARK_GRAYED),
389 ); 391 );
390 } 392 }
391 }; 393 };
392 394
393 } elsif (1 - $self->{colour} == $self->{cur_board}{last}) { 395 } elsif ($self->{colour} == $self->{whosemove}) {
394 # normal move 396 # normal move
395 $self->{button_pass}->set (label => "Pass", sensitive => 1, visible => 1); 397 $self->{button_pass}->set (label => "Pass", visible => 1, sensitive => 1);
396 $self->{board}->set (cursor => sub { 398 $self->{board}->set (cursor => sub {
397 # if is_valid_move oder so#TODO# 399 # if is_valid_move oder so#TODO#
398 $_[0] & (MARK_B | MARK_W) 400 $_[0] & (MARK_B | MARK_W)
399 ? $_[0] 401 ? $_[0]
400 : $_[0] | MARK_GRAYED | ($self->{colour} == COLOUR_WHITE ? MARK_W : MARK_B); 402 : $_[0] | MARK_GRAYED | ($self->{colour} == COLOUR_WHITE ? MARK_W : MARK_B);
405 delete $self->{board_click}; 407 delete $self->{board_click};
406 $self->{button_pass}->sensitive (0); 408 $self->{button_pass}->sensitive (0);
407 }; 409 };
408 } else { 410 } else {
409 $self->{button_pass}->set (label => "Pass", sensitive => 0, visible => 1); 411 $self->{button_pass}->set (label => "Pass", sensitive => 0, visible => 1);
412 $self->{board}->set (cursor => undef);
410 } 413 }
411 } else { 414 } else {
412 $self->{button_undo}->hide; 415 $self->{button_undo}->hide;
413 $self->{button_resign}->hide; 416 $self->{button_resign}->hide;
414 $self->{button_pass}->hide; 417 $self->{button_pass}->hide;
423 my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher}; 426 my $running = $self->{showmove} == @{$self->{path}} && !$self->{teacher};
424 427
425 for my $colour (COLOUR_BLACK, COLOUR_WHITE) { 428 for my $colour (COLOUR_BLACK, COLOUR_WHITE) {
426 my $t = $timers->[$colour]; 429 my $t = $timers->[$colour];
427 $self->{userpanel}[$colour]->set_timer ( 430 $self->{userpanel}[$colour]->set_timer (
428 $running && $self->{lastmove_colour} == 1 - $colour && $t->[0], 431 $running && $colour == $self->{whosemove} && $t->[0],
429 $t->[1], $t->[2]); 432 $t->[1] || $self->{rules}{time}
433 + ($self->{rules}{timesys} == TIMESYS_BYO_YOMI
434 && $self->{rules}{interval} * $self->{rules}{count}),
435 $t->[2] || $self->{rules}{count});
430 } 436 }
431} 437}
432 438
433sub update_board { 439sub update_board {
434 my ($self) = @_; 440 my ($self) = @_;
439 $self->{cur_board} = new KGS::Game::Board $self->{size}; 445 $self->{cur_board} = new KGS::Game::Board $self->{size};
440 $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]); 446 $self->{cur_board}->interpret_path ([@{$self->{path}}[0 .. $self->{showmove} - 1]]);
441 447
442 $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_]) 448 $self->{userpanel}[$_]->set_captures ($self->{cur_board}{captures}[$_])
443 for COLOUR_WHITE, COLOUR_BLACK; 449 for COLOUR_WHITE, COLOUR_BLACK;
450
451 if ($self->{rules}{ruleset} == RULESET_JAPANESE) {
452 if ($self->{curnode}{move} == 0) {
453 $self->{whosemove} = $self->{handicap} ? COLOUR_WHITE : COLOUR_BLACK;
454 } else {
455 $self->{whosemove} = 1 - $self->{cur_board}{last};
456 }
457 } else {
458 # Chinese, Aga, NZ all have manual placement
459 if ($self->{curnode}{move} < $self->{handicap}) {
460 $self->{whosemove} = COLOUR_BLACK;
461 } elsif ($self->{curnode}{move} == $self->{handicap}) {
462 $self->{whosemove} = COLOUR_WHITE;
463 } else {
464 $self->{whosemove} = 1 - $self->{cur_board}{last};
465 }
466 }
467
468 my $start_time = $self->{rules}{time};
444 469
445 if ($self->{showmove} == @{$self->{path}}) { 470 if ($self->{showmove} == @{$self->{path}}) {
446 $self->{timers} = [ 471 $self->{timers} = [
447 [$self->{lastmove_time}, @{$self->{cur_board}{timer}[0]}], 472 [$self->{lastmove_time}, @{$self->{cur_board}{timer}[0]}],
448 [$self->{lastmove_time}, @{$self->{cur_board}{timer}[1]}], 473 [$self->{lastmove_time}, @{$self->{cur_board}{timer}[1]}],
455 ]); 480 ]);
456 } 481 }
457 482
458 $self->{board}->set_board ($self->{cur_board}); 483 $self->{board}->set_board ($self->{cur_board});
459 484
485 if ($self->{cur_board}{score}) {
486 $self->{score_inlay} ||= $self->{chat}->new_inlay;
487 $self->{score_inlay}->clear;
488 $self->{score_inlay}->append_text ("\n<header>Scoring</header>"
489 . "\n<score>"
490 . "White: $self->{cur_board}{score}[COLOUR_WHITE], "
491 . "Black: $self->{cur_board}{score}[COLOUR_BLACK]"
492 . "</score>");
493 } elsif ($self->{score_inlay}) {
494 (delete $self->{score_inlay})->clear;
495 }
496
460 $self->update_cursor; 497 $self->update_cursor;
461} 498}
462 499
463sub event_update_tree { 500sub event_update_tree {
464 my ($self) = @_; 501 my ($self) = @_;
502
503 (delete $self->{undo_inlay})->clear
504 if $self->{undo_inlay};
465 505
466 $self->{path} = $self->get_path; 506 $self->{path} = $self->get_path;
467 507
468 if ($self->{moveadj}) { 508 if ($self->{moveadj}) {
469 my $upper = $self->{moveadj}->upper; 509 my $upper = $self->{moveadj}->upper;
532 $self->destroy; 572 $self->destroy;
533} 573}
534 574
535sub event_move { 575sub event_move {
536 my ($self, $pass) = @_; 576 my ($self, $pass) = @_;
577
537 sound::play 1, $pass ? "pass" : "move"; 578 sound::play 1, $pass ? "pass" : "move";
538
539 if ($self->{undo_inlay}) {
540 (delete $self->{undo_inlay})->clear;
541 }
542} 579}
543 580
544sub event_update_game { 581sub event_update_game {
545 my ($self) = @_; 582 my ($self) = @_;
546 583
650 $self->{userpanel}[$_]->configure ($self->{app}, $self->{user}[$_], $rules) 687 $self->{userpanel}[$_]->configure ($self->{app}, $self->{user}[$_], $rules)
651 for COLOUR_BLACK, COLOUR_WHITE; 688 for COLOUR_BLACK, COLOUR_WHITE;
652 } 689 }
653 690
654 sound::play 3, "gamestart"; 691 sound::play 3, "gamestart";
655
656 $self->{rules_inlay}->refresh; 692 $self->{rules_inlay}->refresh;
657} 693}
658 694
659sub event_resign_game { 695sub event_resign_game {
660 my ($self, $player) = @_; 696 my ($self, $player) = @_;
677} 713}
678 714
679sub event_done { 715sub event_done {
680 my ($self) = @_; 716 my ($self) = @_;
681 717
718 warn sprintf "EVENT DONE @{$self->{done}} %x\n", $self->{doneid};#d#
719
682 if ($self->{done}[1 - $self->{colour}] && !$self->{done}[$self->{colour}]) { 720 if ($self->{done}[1 - $self->{colour}] && !$self->{done}[$self->{colour}]) {
721 sound::play 2, "ring" unless $inlay->{count};
683 $self->{chat}->append_text ("\n<infoblock><header>Done</header>" 722 $self->{chat}->append_text ("\n<infoblock><header>Press Done</header>"
684 . "\nYour opponent pressed done."); 723 . "\nYour opponent pressed done. Now it's up to you.");
685 } 724 }
725 if ($self->{doneid} & 0x80000000) {
726 sound::play 2, "warning" unless $inlay->{count};
727 $self->{chat}->append_text ("\n<infoblock><header>Press Done Again</header>"
728 . "\nYour opponent changed the board..");
729 }
730
731 $self->{button_pass}->sensitive (!$self->{done}[$self->{colour}]);
732
733 $self->{chat}->set_end;
686} 734}
687 735
688sub inject_final_result { 736sub inject_final_result {
689 my ($self, $msg) = @_; 737 my ($self, $msg) = @_;
690 738
701 $self->{timers} = [ 749 $self->{timers} = [
702 [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}], 750 [$msg->{NOW}, $msg->{black_time}, $msg->{black_moves}],
703 [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}], 751 [$msg->{NOW}, $msg->{white_time}, $msg->{white_moves}],
704 ]; 752 ];
705 753
706 print "SGT\n";#d#
707 $self->update_timers ($self->{timers}) 754 $self->update_timers ($self->{timers})
708 if $self->{showmove} == @{$self->{path}}; 755 if $self->{showmove} == @{$self->{path}};
709} 756}
710 757
711sub inject_req_undo { 758sub inject_req_undo {
712 my ($self, $msg) = @_; 759 my ($self, $msg) = @_;
713 760
714 my $inlay = $self->{undo_inlay} ||= $self->{chat}->new_inlay; 761 my $inlay = $self->{undo_inlay} ||= $self->{chat}->new_inlay;
715 return if $inlay->{ignore}; 762 return if $inlay->{ignore};
716 763
717 sound::play 3, "warning" unless $inlay->{count}; 764 sound::play 2, "warning" unless $inlay->{count};
718 $inlay->{count}++; 765 $inlay->{count}++;
719 766
720 $inlay->clear; 767 $inlay->clear;
721 $inlay->append_text ("\n<undo>Undo requested ($inlay->{count} times)</undo>\n"); 768 $inlay->append_text ("\n<undo>Undo requested ($inlay->{count} times)</undo>\n");
722 $inlay->append_button ("Grant", sub { 769 $inlay->append_button ("Grant", sub {
723 $inlay->clear; 770 (delete $self->{undo_inlay})->clear;
724 $self->send (grant_undo => channel => $self->{channel}); 771 $self->send (grant_undo => channel => $self->{channel});
725 }); 772 });
726 $inlay->append_button ("Ignore", sub { 773 $inlay->append_button ("Ignore", sub {
727 $inlay->clear; 774 $inlay->clear;
728 $inlay->{ignore} = 1; 775 $inlay->{ignore} = 1;
733} 780}
734 781
735sub inject_new_game { 782sub inject_new_game {
736 my ($self, $msg) = @_; 783 my ($self, $msg) = @_;
737 784
738 $self->{chat}->append_text ("\n<header>ACK from server ($msg->{cid} == $self->{cid})</header>"); 785 if ($msg->{cid} != $self->{cid}) {
786 $self->part;
787 warn "ERROR: challenge id mismatch, PLEASE REPORT, especially the circumstances (many games open? etc..)\n";#d#
788 }
789
790 $self->{chat}->append_text ("\n<header>Game successfully created on server.</header>");
739 delete $self->{cid}; 791 delete $self->{cid};
740} 792}
741 793
742sub draw_challenge { 794sub draw_challenge {
743 my ($self, $id) = @_; 795 my ($self, $id) = @_;
747 my $rules = $info->{rules}; 799 my $rules = $info->{rules};
748 800
749 my $as_black = $info->{black}{name} eq $self->{conn}{name} ? 1 : 0;; 801 my $as_black = $info->{black}{name} eq $self->{conn}{name} ? 1 : 0;;
750 my $opponent = $as_black ? $info->{white} : $info->{black}; 802 my $opponent = $as_black ? $info->{white} : $info->{black};
751 803
752 my ($size, $time, $interval, $count); 804 my ($size, $time, $interval, $count, $type);
753 805
754 if (!$self->{channel}) { 806 if (!$self->{channel}) {
755 $inlay->append_text ("\nNotes: "); 807 $inlay->append_text ("\nNotes: ");
756 $inlay->append_entry (\$info->{notes}, 20, ""); 808 $inlay->append_entry (\$info->{notes}, 20, "");
757 $inlay->append_text ("\nGlobal Offer: "); 809 $inlay->append_text ("\nGlobal Offer: ");
762 } else { 814 } else {
763 $inlay->append_text ("\nNotes: " . util::toxml $info->{notes}); 815 $inlay->append_text ("\nNotes: " . util::toxml $info->{notes});
764 } 816 }
765 817
766 $inlay->append_text ("\nType: "); 818 $inlay->append_text ("\nType: ");
767 $inlay->append_optionmenu ( 819 $type = $inlay->append_optionmenu (
768 \$info->{gametype}, 820 \$info->{gametype},
769 GAMETYPE_DEMONSTRATION , "Demonstration", 821 GAMETYPE_DEMONSTRATION , "Demonstration (not yet)",
770 GAMETYPE_DEMONSTRATION | GAMETYPE_PRIVATE, "Demonstration (P)", 822 GAMETYPE_DEMONSTRATION | GAMETYPE_PRIVATE, "Demonstration (P) (not yet)",
771 GAMETYPE_TEACHING , "Teaching", 823 GAMETYPE_TEACHING , "Teaching (not yet)",
772 GAMETYPE_TEACHING | GAMETYPE_PRIVATE, "Teaching (P)", 824 GAMETYPE_TEACHING | GAMETYPE_PRIVATE, "Teaching (P) (not yet)",
773 GAMETYPE_SIMUL , "Simul (not yet!)", 825 GAMETYPE_SIMUL , "Simul (not yet!)",
774 GAMETYPE_FREE , "Free", 826 GAMETYPE_FREE , "Free",
775 GAMETYPE_RATED , "Rated", 827 GAMETYPE_RATED , "Rated",
776 sub { 828 sub {
777 $size->set_history (2) if $_[0] eq GAMETYPE_RATED; 829 $size->set_history (2) if $_[0] eq GAMETYPE_RATED;
801 RULESET_NEW_ZEALAND, "New Zealand", 853 RULESET_NEW_ZEALAND, "New Zealand",
802 ); 854 );
803 855
804 $inlay->append_text ("\nSize: "); 856 $inlay->append_text ("\nSize: ");
805 $size = $inlay->append_optionmenu ( 857 $size = $inlay->append_optionmenu (
858 \$info->{rules}{size},
806 \$info->{rules}{size}, 9 => 9, 13 => 13, 19 => 19, map +($_, $_), 2..38 859 (9 => 9, 13 => 13, 19 => 19, map +($_, $_), 2..38),
860 sub {
861 $type->set_history (5) # reset to free
862 if $_[0] != 19 && $info->{gametype} == GAMETYPE_RATED;
863 },
807 ); 864 );
808 865
809 if ($self->{channel}) { 866 if ($self->{channel}) {
810 $inlay->append_text ("\nHandicap: "); 867 $inlay->append_text ("\nHandicap: ");
811 $inlay->append_optionmenu (\$info->{rules}{handicap}, map +($_, $_), 0..9); 868 $inlay->append_optionmenu (\$info->{rules}{handicap}, map +($_, $_), 0..9);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines