Module: Bcpm::Duel
- Defined in:
- lib/bcpm/duel.rb
Overview
Pits players against other players.
Class Method Summary collapse
-
.default_match_threads ⇒ Object
Number of threads to use for simulating matches.
-
.duel_pair(player1_name, player2_name, show_progress = false, maps = nil) ⇒ Object
Has two players fight on all maps in both positions.
-
.match_threads ⇒ Object
Number of threads to use for simulating matches.
-
.multiplex_matches(matches) ⇒ Object
Runs may matches in parallel.
-
.outcome_string(score_delta) ⇒ Object
The string to be shown for a match outcome.
-
.rank_players(player_list, show_progress = false, maps = nil) ⇒ Object
Has all players compete against each other.
-
.score_player(player, player_list, show_progress = false, maps = nil) ⇒ Object
Scores one player against the other players.
Class Method Details
.default_match_threads ⇒ Object
Number of threads to use for simulating matches.
119 120 121 |
# File 'lib/bcpm/duel.rb', line 119 def self.default_match_threads 1 end |
.duel_pair(player1_name, player2_name, show_progress = false, maps = nil) ⇒ Object
Has two players fight on all maps in both positions.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/bcpm/duel.rb', line 10 def self.duel_pair(player1_name, player2_name, show_progress = false, maps = nil) maps ||= Bcpm::Dist.maps.sort # Abort in case of typos. [player1_name, player2_name].each do |player| unless Bcpm::Player.wired? player puts "Player #{player} is not installed\n" exit 1 end end # Abort in case of compile errors. env = Bcpm::Tests::Environment.new player1_name unless env.build print env.build_log exit 1 end # Compute the matches. matches = maps.map { |map_name| [:a, :b].map do |side| Bcpm::Tests::TestMatch.new side, player2_name, map_name, env end }.flatten # Compute stats. score, wins, losses, errors = 0, [], [], [] multiplex_matches(matches) do |match| score_delta = case match.winner when :a, :b (match.winner == match.side) ? 1 : -1 else 0 end if show_progress print "#{player1_name} #{match.description}: #{outcome_string(score_delta)}\n" STDOUT.flush end score += score_delta if score_delta case score_delta when 1 wins << match when -1 losses << match when 0 errors << match end end { :score => score, :wins => wins, :losses => losses, :errors => errors } end |
.match_threads ⇒ Object
Number of threads to use for simulating matches.
114 115 116 |
# File 'lib/bcpm/duel.rb', line 114 def self.match_threads (Bcpm::Config[:match_threads] ||= default_match_threads).to_i end |
.multiplex_matches(matches) ⇒ Object
Runs may matches in parallel.
Returns the given matches. If given a block, also yields each match as it becomes available.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/bcpm/duel.rb', line 66 def self.multiplex_matches(matches) # Schedule matches. in_queue = Queue.new matches.each do |match| in_queue.push match end match_threads.times { in_queue.push nil } # Execute matches. out_queue = Queue.new old_abort = Thread.abort_on_exception Thread.abort_on_exception = true match_threads.times do Thread.new do loop do break unless match = in_queue.pop match.run false out_queue.push match end end end Thread.abort_on_exception = old_abort matches.length.times do match = out_queue.pop if Kernel.block_given? yield match end end matches end |
.outcome_string(score_delta) ⇒ Object
The string to be shown for a match outcome.
99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/bcpm/duel.rb', line 99 def self.outcome_string(score_delta) # TODO(pwnall): ANSI color codes if /mingw/ =~ RUBY_PLATFORM || (/win/ =~ RUBY_PLATFORM && /darwin/ !~ RUBY_PLATFORM) {0 => "error", 1 => "won", -1 => "lost"}[score_delta] else { 0 => "\33[33merror\33[0m", 1 => "\33[32mwon\33[0m", -1 => "\33[31mlost\33[0m" }[score_delta] end end |
.rank_players(player_list, show_progress = false, maps = nil) ⇒ Object
Has all players compete against each other.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/bcpm/duel.rb', line 124 def self.rank_players(player_list, show_progress = false, maps = nil) scores = {} 0.upto(player_list.length - 1) do |i| 0.upto(i - 1) do |j| outcome = duel_pair player_list[i], player_list[j], show_progress, maps scores[i] ||= 0 scores[i] += outcome[:score] scores[j] ||= 0 scores[j] -= outcome[:score] end end scores.map { |k, v| [v, player_list[k]] }. sort_by { |score, player| [-score, player] } end |
.score_player(player, player_list, show_progress = false, maps = nil) ⇒ Object
Scores one player against the other players.
140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/bcpm/duel.rb', line 140 def self.score_player(player, player_list, show_progress = false, maps = nil) player_list = player_list - [player] scores = player_list.map do |opponent| [ duel_pair(player, opponent, show_progress, maps)[:score], opponent ] end { :points => scores.map(&:first).inject(0) { |a, b| a + b}, :scores => scores.sort_by { |score, player| [score, player] } } end |