I took the OO approach and implemented a strategy pattern.
To see the game play out, pass in the -v flag, and -d will show the
actual command given for each move.

The output of the test file contains a frequency distribution to show
how each matchup plays out.

Here is some sample output for the second matchup in the test over 200
games:
_____________________________________
Game 2: Aggressive vs Random
3: ---------------------------------33
4:
--------------------------------------------------------------------68
5: -------------------------------------------43
6: ------------------------24
7: ---------------15
8: -----5
9: -------7
10: ----4
11: -1
Player 1: 166 wins
Player 2: 34 wins
______________________________________

In an Aggressive vs Aggressive game, the first player wins in 3 rounds
every time.  Obviously there are better
strategies that I didn't take the time to explore.

Again, I'm happy to receive any comments.  I feel like my solutions
are so clunky compared to what you guys submit.
I am here to learn!

Here's my code:

#file: game.rb
#author: Matt Hulse - www.matt-hulse.com

require 'player'

class Game
  attr_reader :p1, :p2, :winner, :rounds

  def initialize(p1_strategy = "random", p2_strategy = "random")
    @p1 = Player.new(1,p1_strategy, self)
    @p2 = Player.new(2,p2_strategy, self)
    @rounds = 0
  end

  def get_opponent(player)
    return @p1 if @p2 == player
    return @p2 if @p1 == player
  end

  def loop
    #keep going until one person has no hands left
    #after 100 rounds we're calling a draw!

    puts self if $VERBOSE
    until(game_over) do
      @rounds += 1
      p1.move
      puts self if $VERBOSE

      unless game_over then
        p2.move
        puts self if $VERBOSE
      end
      break if @rounds >= 100
    end

    if(lost?(p1)) then
      @winner = p2
    elsif(lost?(p2))
      @winner = p1
    else
      puts "Draw"
    end
  end

  def game_over
    lost?(p1) || lost?(p2)
  end

  def lost?(player)
    player.left.finger_count <= 0 and player.right.finger_count <= 0
  end

  def to_s
    "#{p1}\n#{p2}\n"
  end
end



#file: hand.rb
#author: Matt Hulse - www.matt-hulse.com

class Hand
  attr_reader :right_or_left, :finger_count

  def initialize(right_or_left, count = 1)
    @right_or_left = right_or_left
    @finger_count = count
  end

  def touch(hand)
    hand.add_fingers(self.finger_count)
  end

  def add_fingers(num)
    @finger_count += num
    if @finger_count >= 5 then
      @finger_count = 0
    end
  end

  def clap(hand,num)
    hand.add_fingers(num) #num must be <= self.finger_count
    @finger_count -= num
  end

  def to_s
    result = ""
    #print left to right
    i = 0
    (1..5).each{
      i += 1
      if(i <= @finger_count) then
        result += "|"
      else
        result += "-"
      end
    }
    return result if @right_or_left == :right
    return result.reverse
  end

end



#file: player.rb
#author: Matt Hulse - www.matt-hulse.com

require 'hand'

class Player
  attr_reader :player_num, :right, :left, :strategy, :game
  def initialize(player_num, strategy, game)
    @player_num = player_num
    @strategy = strategy
    @game = game
    @right = Hand.new(:right,1)
    @left = Hand.new(:left,1)
  end

  def move
    begin
      eval(@strategy)
    rescue NameError => e
      random #default to random
    end
  end

  def get_opponent
    @game.get_opponent(self)
  end

  def get_larger_hand
    return @right if @right.finger_count > @left.finger_count
    return @left
  end

  def min(a,b)
    return a if a <= b
    return b
  end

  def random
    #all possible moves, choose randomly among them
    opponent = get_opponent

    valid_moves = Array.new

    opp_rt_count = opponent.right.finger_count
    opp_lt_count = opponent.left.finger_count

    if(@right.finger_count > 0) then
      valid_moves << "@right.touch(opponent.right)" if opp_rt_count >
0
      valid_moves << "@right.touch(opponent.left)" if opp_lt_count > 0
      #total on hand transferred to cannot be more than 5
      #random number is between 1 and the minimum of what left can
receive and right can give
      rand_max = min(5- / left.finger_count,@right.finger_count-1)
      valid_moves << "@right.clap(@left, #{rand(rand_max) + 1})" if
rand_max > 0
    end

    if(@left.finger_count > 0) then
      valid_moves << "@left.touch(opponent.right)" if opp_rt_count > 0
      valid_moves << "@left.touch(opponent.left)" if opp_lt_count > 0
      #total on hand transferred to cannot be more than 5
      #random number is between 1 and the minimum of what right can
receive and left can give
      rand_max = min(5- / right.finger_count,@left.finger_count-1)
      valid_moves << "@left.clap(@right, #{rand(rand_max) + 1})" if
rand_max > 0
    end

    move = valid_moves[rand(valid_moves.size)]
    eval(move)
    puts "Player #{player_num}: #{move}" if $DEBUG
  end

  def aggressive
    opponent = get_opponent

    #every move is to touch the opponents largest hand with the local
largest hand
    move = "get_larger_hand.touch(opponent.get_larger_hand)"

    eval(move)
    puts "Player #{player_num}: #{move}" if $DEBUG
  end

  def to_s
    "#{player_num}: #{@left} #{@right}"
  end
end



#file: test.rb
#author: Matt Hulse - www.matt-hulse.com

require 'game'

puts "Game 1: Random vs Random"

num_rounds = Hash.new(0)
wins = Hash.new(0)

(1..200).each{
  game = Game.new("random","random")
  game.loop
  if(game.winner) then
    puts "Player #{game.winner.player_num} won in #{game.rounds}
rounds using #{game.winner.strategy} strategy." if $VERBOSE
    num_rounds[game.rounds] += 1
    wins[game.winner.player_num] +=1
  end
}

num_rounds.keys.sort{|a,b| a<=>b}.each{|i|
  puts "#{i}: #{'-'*num_rounds[i]}#{num_rounds[i]}"
}

wins.each_pair{|key,value|
  puts "Player #{key}: #{value} wins"
}



puts
puts "Game 2: Aggressive vs Random"

num_rounds = Hash.new(0)
wins = Hash.new(0)

(1..200).each{
  game = Game.new("aggressive", "random")
  game.loop
  if(game.winner) then
    puts "Player #{game.winner.player_num} won in #{game.rounds}
rounds using #{game.winner.strategy} strategy." if $VERBOSE
    num_rounds[game.rounds] += 1
    wins[game.winner.player_num] +=1
  end
}

num_rounds.keys.sort{|a,b| a<=>b}.each{|i|
  puts "#{i}: #{'-'*num_rounds[i]}#{num_rounds[i]}"
}

wins.each_pair{|key,value|
  puts "Player #{key}: #{value} wins"
}


puts
puts "Game 3: Aggressive vs Aggressive"

num_rounds = Hash.new(0)
wins = Hash.new(0)

(1..200).each{
  game = Game.new("aggressive","aggressive")
  game.loop
  if(game.winner) then
    puts "Player #{game.winner.player_num} won in #{game.rounds}
rounds using #{game.winner.strategy} strategy." if $VERBOSE
    num_rounds[game.rounds] += 1
    wins[game.winner.player_num] +=1
  end
}

num_rounds.keys.sort{|a,b| a<=>b}.each{|i|
  puts "#{i}: #{'-'*num_rounds[i]}#{num_rounds[i]}"
}

wins.each_pair{|key,value|
  puts "Player #{key}: #{value} wins"
}



Thanks,

__________
Matt Hulse
matt.hulse / gmail.com
http://www.matt-hulse.com






On Apr 13, 5:48 am, Ruby Quiz <j... / grayproductions.net> wrote:
> The three rules of Ruby Quiz:
>
> 1.  Please do not post any solutions or spoiler discussion for this quiz until
> 48 hours have passed from the time on this message.
>
> 2.  Support Ruby Quiz by submitting ideas as often as you can:
>
> http://www.rubyquiz.com/
>
> 3.  Enjoy!
>
> Suggestion:  A [QUIZ] in the subject of emails about the problem helps everyone
> on Ruby Talk follow the discussion.  Please reply to the original quiz message,
> if you can.
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
>
> We have a foreign exchange student from Korea staying with us.  The best part of
> that is the intended exchange of cultures.  For example, to kill time on a
> recent plane trip, the student taught us a common finger game children play in
> Korea.
>
> The rules are very easy:
>
>         1.  Both players start by holding up one finger on each hand.
>         2.  On each turn a player must do one of the following:
>           a.  Touch one of their hands to an opponent's hand, adding the finger
>               count on their hand to the touched hand.  The player keeps the same
>               number of fingers, but the opponent must add the player's finger
>               count in addition to the fingers already on that hand.
>           b.  Clap their hands together to "transfer" one or more fingers from
>               one hand to the other.  You cannot transfer all the fingers off of
>               a hand.
>         3.  A hand with five or more fingers is eliminated, which is shown by
>             making a fist.  An opponent can not add fingers to an eliminated
>             hand and an it cannot be used in touches, but players may transfer
>             fingers to it, "reviving" it.  The first player with two eliminated
>             hands loses the game.
>
> For example, here is how a quick game might play out:
>
>         1:  ----|  |----  Starting fingers.
>         2:  ----|  |----
>
>         1:  ----|  |----  Player 1's left hand touches player 2's right hand.
>         2:  ----|  ||---
>
>         1:  ----|  |||--  2's right touches 1's right hand.
>         2:  ----|  ||---
>
>         1:  ----|  |||--  1's right touches 2's right hand.
>         2:  ----|  -----
>
>         1:  ----|  ||||-  2's left touches 1's right hand.
>         2:  ----|  -----
>
>         1:  ----|  |||--  1's right touches 2's left hand.
>         2:  -----  -----
>
> Of course, as a programmer, I immediately tried to solve this game.  I suck the
> fun right out of everything, but at least it gave us another quiz topic.
>
> This week's Ruby Quiz is to programmatically solve Magic Fingers.  Is it a win
> for the first or second player with perfect play, or can you always force a draw
> with repeating counts?  Have your program print some output that would convince
> anyone beyond the shadow of a doubt what the game's outcome will be.