Rock Paper Scissors

Hello all, I’m doing Rock Paper Scissors from Ruby Q. book.
the answer (without cheating) gives example of CNBiasInverter,

CNBiasInverter vs. JEGQueuePlayer
CNBiasInverter: 653.5
JEGQueuePlayer: 346.5
CNBiasInverter Wins

while I agree that if oponent has some weight bias on giving out
position,
but if he has repeatable cycle, you can do better than that.

so I do following
#file cycle.rb
class CycleDetecter
CYCLE_MAX_LENGTH = 6
def self.detect_cycle(arr)
1.upto(CYCLE_MAX_LENGTH) do |i|
if isCyclic arr,i
return Cycle.new(i)
end
end
return Cycle.new(-1)
end
def self.isCyclic(arr, cycle)
#puts arr.inspect
cycle.times do |i|
n = 1
while i+n*cycle < arr.size
if arr[i] != arr[i + n* cycle]
return false
end
n += 1
end

end
return true

end
end

class Cycle
attr_accessor :cycle
def initialize(cycle)
@cycle = cycle
end
def to_s
cycle.to_s
end
def == (other)
cycle == other.cycle
end

end
#file weight.rb
class WeightedDetecter
WEIGHT_MAX_LENGTH = 6
def self.detect_weight(arr)
rockSize=paperSize=scissorsSize=0
arr.each do |x|
if x == :rock
rockSize+=1
elsif x==:paper
paperSize +=1
elsif x== :scissors
scissorsSize += 1
end
end
Weight.new([rockSize1.0/arr.size, paperSize1.0/arr.size,
scissorsSize*1.0/arr.size])
end

end

class Weight
attr_accessor :weight
def initialize(weight)
@weight = weight
end
def == (other)
weight == other.weight
end

end
arr = [:rock,:rock,:paper,:scissors]
puts WeightedDetecter.detect_weight(arr).inspect

#file femto_stragety_player.rb
require ‘player/stragety/cycle’
require ‘player/stragety/weight’
class FemtoStragetyPlayer < Player
QUEUE = [ :rock, :paper, :scissors ]
CYCLE = “CYCLE”
QUEUE_TYPE = “QUEUE_HAND”
def initialize( opponent_name )
super
@myIndex = 0
@oponent_choices = []
end

def choose
oponentStragety = judgeOponent
#puts oponentStragety.class
if oponentStragety.class == Cycle
result = competeCycle(oponentStragety)
elsif oponentStragety.class == Weight

    r = rand
    weight = oponentStragety.weight
    if r<weight[0]
      result = QUEUE[1]
    elsif r<weight[0] + weight[1]
      result = QUEUE[2]
    else # r<weight[0] + weight[1] + weight[2] = 1
      result = QUEUE[0]
    end
 else
    #puts "fallback to random choice"
    #fallback to random choice
    result = QUEUE[Integer(rand*3)]
  end
@myIndex += 1 #add myIndex for next run turn
#puts "#{oponentStragety},#{@oponent_choices.inspect}, 

#{result.inspect}"
result
end
def judgeOponent

if @oponent_choices.size > 0
  startIndex = @myIndex - CycleDetecter::CYCLE_MAX_LENGTH * 2
  startIndex =  0 if startIndex < 0
  arr = @oponent_choices[startIndex, CycleDetecter::CYCLE_MAX_LENGTH 
  • 2]

    result = CycleDetecter.detect_cycle(arr)
    #puts "#{@oponent_choices.inspect}, #{startIndex},
    

#{arr.inspect}, #{result.inspect} \n"
if result == Cycle.new(-1)
result = WeightedDetecter.detect_weight(arr)
end
return result
end
end

def competeCycle(cycle)
findWinHand(@oponent_choices[@myIndex-cycle.cycle])
end
def findWinHand(hand)
if hand == :rock then
return :paper
end
if hand == :paper then
return :scissors
end
if hand == :scissors then
return :rock
end
end

def result( your_choice, opponents_choice, win_lose_or_draw )
@oponent_choices << opponents_choice
# (optional) called after each choice you make to give feedback
# your_choice = your choice
# oppenents_choice = opponent’s choice
# win_lose_or_draw = :win, :lose or :draw, your result
end
end

and get the following result, better than CNBiasInverter

FemtoStragetyPlayer vs. JEGQueuePlayer
FemtoStragetyPlayer: 998
JEGQueuePlayer: 2
FemtoStragetyPlayer Wins

(file femto_stragety_player.rb is under subdir ‘player’
cycle.rb and weight.rb is under ‘player/stragety’
because the main file dynamic requires in femto_stragety_player,
so the working dir is dir up 1 level than ‘player’ , so in file
femto_stragety_player.rb , I write require ‘player/stragety/cycle.rb’
rather than ‘stragety/cycle.rb’ , do anyone knows how to handle this?)


compare to random player:
several runs: can see from the number, that sometimes
FemtoStragetyPlayer beats FemtoRandomPlayer, sometime
be beaten by FemtoRandomPlayer (score up or down around 20)
cause when compared to RandomPlayer, the computing of weight
also make FemtoStragetyPlayer back to Random.

FemtoStragetyPlayer vs. FemtoRandomPlayer
FemtoStragetyPlayer: 482.0
FemtoRandomPlayer: 518.0
FemtoRandomPlayer Wins

FemtoStragetyPlayer vs. FemtoRandomPlayer
FemtoStragetyPlayer: 510.0
FemtoRandomPlayer: 490.0
FemtoStragetyPlayer Wins

FemtoStragetyPlayer vs. FemtoRandomPlayer
FemtoStragetyPlayer: 482.5
FemtoRandomPlayer: 517.5
FemtoRandomPlayer Wins

FemtoStragetyPlayer vs. FemtoRandomPlayer
FemtoStragetyPlayer: 483.0
FemtoRandomPlayer: 517.0
FemtoRandomPlayer Wins

FemtoStragetyPlayer vs. FemtoRandomPlayer
FemtoStragetyPlayer: 513.0
FemtoRandomPlayer: 487.0
FemtoStragetyPlayer Wins

Regards
femto