# Rock Paper Scissors

**URL:** <https://www.ruby-forum.com/t/rock-paper-scissors/74568>\
**Category:** Ruby\
**Created:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/rock-paper-scissors/74568 "2006-11-07T10:48:29Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![femto\_gary](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/ba8739/32.png) [@femto\_gary](https://www.ruby-forum.com/u/femto_gary)\
**Post date:** [November 7, 2006, 10:48am UTC](https://www.ruby-forum.com/t/rock-paper-scissors/74568/1 "2006-11-07T10:48:29Z")

</div>

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([rockSize_1.0/arr.size, paperSize_1.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]

#{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
