shogi-server source
リビジョン | 0a1c409fedbbc7061dc32114740ab32d5f76735d (tree) |
---|---|
日時 | 2010-09-05 16:56:27 |
作者 | daigo <beatles@user...> |
コミッター | Daigo Moriwaki |
Enhanced the Buoy feature: Players are allowed to start buoy games with specific turns.
ex. %%GAME buoy_foo-1500-0 +
@@ -6,6 +6,8 @@ | ||
6 | 6 | + Starting a buoy game, players are notified a starting game |
7 | 7 | position with the initial position and moves, instread of a |
8 | 8 | targeting position. |
9 | + + Players are allowed to start buoy games with specific turns. | |
10 | + ex. %%GAME buoy_foo-1500-0 + | |
9 | 11 | |
10 | 12 | 2010-08-05 Daigo Moriwaki <daigo at debian dot org> |
11 | 13 |
@@ -272,8 +274,8 @@ | ||
272 | 274 | New commands: |
273 | 275 | + %%SETBUOY <game_name> <moves> [count] |
274 | 276 | Set a new buoy game. |
275 | - ex. %%SETBUOYGAME buoy_foo-900-0 +7776FU 10 | |
276 | - ex. %%SETBUOYGAME buoy_foo-1500-0 +7776FU-3334FU | |
277 | + ex. %%SETBUOY buoy_foo-900-0 +7776FU 10 | |
278 | + ex. %%SETBUOY buoy_foo-1500-0 +7776FU-3334FU | |
277 | 279 | - game_name is a valid game name with a prefix "buoy_". |
278 | 280 | ex. buoy_foo-900-0 |
279 | 281 | - moves are initial moves from the Hirate position to a |
@@ -476,6 +476,7 @@ module ShogiServer | ||
476 | 476 | @command_name = command_name |
477 | 477 | @game_name = game_name |
478 | 478 | @my_sente_str = my_sente_str |
479 | + player.set_sente_from_str(@my_sente_str) | |
479 | 480 | end |
480 | 481 | |
481 | 482 | def call |
@@ -497,7 +498,7 @@ module ShogiServer | ||
497 | 498 | end |
498 | 499 | @player.sente = nil |
499 | 500 | else |
500 | - rival = $league.find_rival(@player, @my_sente_str, @game_name) | |
501 | + rival = $league.find_rival(@player, @game_name) | |
501 | 502 | if rival.instance_of?(Symbol) |
502 | 503 | # An error happened. rival is not a player instance, but an error |
503 | 504 | # symobl that must be returned to the main routine immediately. |
@@ -543,7 +544,6 @@ module ShogiServer | ||
543 | 544 | if (@command_name == "GAME") |
544 | 545 | @player.status = "game_waiting" |
545 | 546 | @player.game_name = @game_name |
546 | - @player.set_sente_from_str(@my_sente_str) | |
547 | 547 | else # challenge |
548 | 548 | @player.write_safe(sprintf("##[ERROR] can't find rival for %s\n", @game_name)) |
549 | 549 | @player.status = "connected" |
@@ -726,15 +726,32 @@ module ShogiServer | ||
726 | 726 | @player.write_safe(sprintf("##[SETBUOY] +OK\n")) |
727 | 727 | log_info("A buoy game was created: %s by %s" % [@game_name, @player.name]) |
728 | 728 | |
729 | - # if two players, who are not @player, are waiting for a new game, start it | |
730 | - p1 = $league.get_player("game_waiting", @game_name, true, @player) | |
731 | - return :continue unless p1 | |
732 | - p2 = $league.get_player("game_waiting", @game_name, false, @player) | |
733 | - return :continue unless p2 | |
734 | - | |
729 | + # if two players are waiting for this buoy game, start it | |
730 | + candidates = $league.find_all_players do |player| | |
731 | + player.status == "game_waiting" && | |
732 | + player.game_name == @game_name && | |
733 | + player.name != @player.name | |
734 | + end | |
735 | + if candidates.empty? | |
736 | + log_info("No players found for a buoy game. Wait for players: %s" % [@game_name]) | |
737 | + return :continue | |
738 | + end | |
739 | + p1 = candidates.first | |
740 | + p2 = $league.find_rival(p1, @game_name) | |
741 | + if p2.nil? | |
742 | + log_info("No opponent found for a buoy game. Wait for the opponent: %s by %s" % [@game_name, p1.name]) | |
743 | + return :continue | |
744 | + elsif p2.instance_of?(Symbol) | |
745 | + # An error happened. rival is not a player instance, but an error | |
746 | + # symobl that must be returned to the main routine immediately. | |
747 | + return p2 | |
748 | + end | |
749 | + # found two players: p1 and p2 | |
750 | + log_info("Starting a buoy game: %s with %s and %s" % [@game_name, p1.name, p2.name]) | |
735 | 751 | buoy.decrement_count(buoy_game) |
736 | 752 | game = Game::new(@game_name, p1, p2, board) |
737 | 753 | return :continue |
754 | + | |
738 | 755 | rescue WrongMoves => e |
739 | 756 | @player.write_safe(sprintf("##[ERROR] wrong moves: %s\n", @moves)) |
740 | 757 | log_error "Received wrong moves: %s from %s. [%s]" % [@moves, @player.name, e.message] |
@@ -32,9 +32,11 @@ class Game | ||
32 | 32 | @@mutex = Mutex.new |
33 | 33 | @@time = 0 |
34 | 34 | |
35 | - # Decide turns of players according to their turn preferences. | |
35 | + # Decide an actual turn of each player according to their turn preferences. | |
36 | 36 | # p2 is a rival player of the p1 player. |
37 | 37 | # p1_sente_string must be "*", "+" or "-". |
38 | + # After this call, the sente value of each player is always true or false, not | |
39 | + # nil. | |
38 | 40 | # |
39 | 41 | def Game.decide_turns(p1, p1_sente_string, p2) |
40 | 42 | if ((p1_sente_string == "*") && (p2.sente == nil)) |
@@ -105,17 +105,17 @@ class League | ||
105 | 105 | # 2. a rival player instance found |
106 | 106 | # 3. nil if rival not found |
107 | 107 | # |
108 | - def find_rival(player, my_sente_string, game_name) | |
109 | - case my_sente_string | |
110 | - when "*" # no preference | |
108 | + def find_rival(player, game_name) | |
109 | + case player.sente | |
110 | + when nil # no preference | |
111 | 111 | if Login.handicapped_game_name?(game_name) |
112 | 112 | player.write_safe("##[ERROR] Random turn preference is not allowed for handicapped games\n") |
113 | 113 | return :continue |
114 | 114 | end |
115 | 115 | return get_player("game_waiting", game_name, nil, player) |
116 | - when "+" # rival must be gote | |
116 | + when true # rival must be gote | |
117 | 117 | return get_player("game_waiting", game_name, false, player) |
118 | - when "-" # rival must be sente | |
118 | + when false # rival must be sente | |
119 | 119 | return get_player("game_waiting", game_name, true, player) |
120 | 120 | else |
121 | 121 | write_safe("##[ERROR] bad game option: %s\n" % [my_sente_string]) |
@@ -14,6 +14,19 @@ class MockLeague | ||
14 | 14 | def initialize |
15 | 15 | @games = {} |
16 | 16 | @games["dummy_game_id"] = MockGame.new |
17 | + | |
18 | + reset_players | |
19 | + end | |
20 | + | |
21 | + def reset_players | |
22 | + $p1 = MockPlayer.new | |
23 | + $p1.name = "p1" | |
24 | + $p1.status = "game_waiting" | |
25 | + $p1.sente = true | |
26 | + $p2 = MockPlayer.new | |
27 | + $p2.name = "p2" | |
28 | + $p2.status = "game_waiting" | |
29 | + $p2.sente = false | |
17 | 30 | end |
18 | 31 | |
19 | 32 | def games |
@@ -38,12 +51,8 @@ class MockLeague | ||
38 | 51 | |
39 | 52 | def get_player(status, game_id, sente, searcher) |
40 | 53 | if sente == true |
41 | - $p1 = MockPlayer.new | |
42 | - $p1.name = "p1" | |
43 | 54 | return $p1 |
44 | 55 | elsif sente == false |
45 | - $p2 = MockPlayer.new | |
46 | - $p2.name = "p2" | |
47 | 56 | return $p2 |
48 | 57 | elsif sente == nil |
49 | 58 | return nil |
@@ -51,6 +60,23 @@ class MockLeague | ||
51 | 60 | return nil |
52 | 61 | end |
53 | 62 | end |
63 | + | |
64 | + def find_all_players | |
65 | + [$p1,$p2].each {|pp| yield pp} | |
66 | + end | |
67 | + | |
68 | + def find_rival(player, game_name) | |
69 | + case player.sente | |
70 | + when nil # no preference | |
71 | + return get_player("game_waiting", game_name, nil, player) | |
72 | + when true # rival must be gote | |
73 | + return get_player("game_waiting", game_name, false, player) | |
74 | + when false # rival must be sente | |
75 | + return get_player("game_waiting", game_name, true, player) | |
76 | + else | |
77 | + return :continue | |
78 | + end | |
79 | + end | |
54 | 80 | end |
55 | 81 | |
56 | 82 |
@@ -772,8 +798,7 @@ end | ||
772 | 798 | class BaseTestBuoyCommand < Test::Unit::TestCase |
773 | 799 | def setup |
774 | 800 | @p = MockPlayer.new |
775 | - $p1 = nil | |
776 | - $p2 = nil | |
801 | + $league = MockLeague.new | |
777 | 802 | |
778 | 803 | delete_buoy_yaml |
779 | 804 | @buoy = ShogiServer::Buoy.new |
@@ -830,8 +855,8 @@ class TestSetBuoyCommand < BaseTestBuoyCommand | ||
830 | 855 | cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoyhoge-1500-0", "+7776FU", 1 |
831 | 856 | rt = cmd.call |
832 | 857 | assert :continue, rt |
833 | - assert !$p1 | |
834 | - assert !$p2 | |
858 | + assert $p1.out.empty? | |
859 | + assert $p2.out.empty? | |
835 | 860 | assert @buoy.is_new_game?("buoy_hoge-1500-0") |
836 | 861 | end |
837 | 862 |
@@ -844,8 +869,8 @@ class TestSetBuoyCommand < BaseTestBuoyCommand | ||
844 | 869 | cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_duplicated-1500-0", "+7776FU", 1 |
845 | 870 | rt = cmd.call |
846 | 871 | assert :continue, rt |
847 | - assert !$p1 | |
848 | - assert !$p2 | |
872 | + assert $p1.out.empty? | |
873 | + assert $p2.out.empty? | |
849 | 874 | assert !@buoy.is_new_game?("buoy_duplicated-1500-0") |
850 | 875 | end |
851 | 876 |
@@ -854,8 +879,8 @@ class TestSetBuoyCommand < BaseTestBuoyCommand | ||
854 | 879 | cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_badmoves-1500-0", "+7776FU+8786FU", 1 |
855 | 880 | rt = cmd.call |
856 | 881 | assert :continue, rt |
857 | - assert !$p1 | |
858 | - assert !$p2 | |
882 | + assert $p1.out.empty? | |
883 | + assert $p2.out.empty? | |
859 | 884 | assert @buoy.is_new_game?("buoy_badmoves-1500-0") |
860 | 885 | end |
861 | 886 |
@@ -864,8 +889,8 @@ class TestSetBuoyCommand < BaseTestBuoyCommand | ||
864 | 889 | cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_badcounter-1500-0", "+7776FU", 0 |
865 | 890 | rt = cmd.call |
866 | 891 | assert :continue, rt |
867 | - assert !$p1 | |
868 | - assert !$p2 | |
892 | + assert $p1.out.empty? | |
893 | + assert $p2.out.empty? | |
869 | 894 | assert @buoy.is_new_game?("buoy_badcounter-1500-0") |
870 | 895 | end |
871 | 896 | end |
@@ -882,8 +907,8 @@ class TestDeleteBuoyCommand < BaseTestBuoyCommand | ||
882 | 907 | cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name |
883 | 908 | rt = cmd.call |
884 | 909 | assert :continue, rt |
885 | - assert !$p1 | |
886 | - assert !$p2 | |
910 | + assert $p1.out.empty? | |
911 | + assert $p2.out.empty? | |
887 | 912 | assert @buoy.is_new_game?(buoy_game.game_name) |
888 | 913 | end |
889 | 914 |
@@ -893,8 +918,8 @@ class TestDeleteBuoyCommand < BaseTestBuoyCommand | ||
893 | 918 | cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name |
894 | 919 | rt = cmd.call |
895 | 920 | assert :continue, rt |
896 | - assert !$p1 | |
897 | - assert !$p2 | |
921 | + assert $p1.out.empty? | |
922 | + assert $p2.out.empty? | |
898 | 923 | assert @buoy.is_new_game?(buoy_game.game_name) |
899 | 924 | end |
900 | 925 |