ジャン拳 V.S. ジャジャン拳

Powered by dKingyo Visual Basic | コンパイラ | Cisco技術者 | アルゴリズム | オープンソース


http://satoshi.blogs.com/life/2007/03/post_16.html
より・・・
自分でも解けそうだったのでやってみました。


このルールを見る限り



  • 強い方>弱い方
    賞金比率
    といった形で表すと

    チョ>パ>グ>チョ>パ ...
    2 :5:0:2 :5 ...
    といった関係
  • 負けてもペナルティー(マイナス)がないという事
  • 賞金の合計額は相手との競争でない事
  • 問題中の条件で「大切なのは試合中に見えるのは相手が何を出したかだけです。」
が要点だと感じました。


賞金の比率を見ると500:200なので
パーで50%の確率で勝ちつづけた場合とチョキで勝ちつづけた場合
250:200
となるのでチョキで1回勝つより賞金額が高い。
それを2回も続けないとパーで50%の確率で勝った賞金額に届かない。
よって、チョキは絶対に出さない。
という戦略をとります。(名付けてグーパー交互戦略)


相手も自分も最高額の賞金を手に入れたいと思うならば

自分がパーで1000回勝つ。 自分は500000円。相手は0円
両者ともパーで500回勝つ。 自分は250000円。相手は250000円
自分がチョキで1000回勝つ。自分は200000円。相手は0円
自分がグーで1000回勝つ。 自分は0円。 相手は0円
からこの戦略が最もであるのは明白でしょう。
強いて問題を挙げるならばこの条件を相手サイドもルールから理解しているかと言う事です。


だけど、この手の問題を考える時必ず、抜け穴があるはずだ!!!と考えてしまうのです。


ちょっと考えた結果

  • 相手が賞金なんて関係ナシにランダムに手を選ぶような機械であったり
  • 相手がずっとチョキだけを出す主催者サイドの手先であったり
  • 負けると挽回不可能なペナルティーがあったり
  • 賞金の合計額は相手との競争で相手より賞金が多くないとその賞金は帳消しであったり
  • 「試合中に見えるのは相手が何を出したかだけです。」から何を出したかという結果を見ても相手が戦略の意図を理解できなかったり
  • 相手が何を出したか知ることが出来なかったり
  • 自分がパーのときに相手がチョキを出してペースを乱してしまったり

した場合はこの戦略は使えません。


ちなみにこの問題は
http://d.hatena.ne.jp/yaneurao/20070326
のような問題を思い出して、この手の考え方を使用してみました。


前回行った「かめかめ算」の時にはC++のプログラムを掲載したので今回はRubyで掲載してみます。
続きを読む

#usr/local/bin/ruby
=begin
一番高い金額の手で交互に勝ち負けをするといったアルゴリズム
=end

paper = 500
scissors = 200
stone = 0

count = 1000


arr = Array.new
win_score = Array.new

class Element
 def initialize(_id,_value)
  @id = _id
  @value = _value
 end
 attr_accessor :id, :value
 def print_name
  case(id)
  when 0
   print "パー" 
  when 1
   print "チョキ"
  when 2
   print "グー"
  end
 end
end

et = Array.new
t = Element.new(0,paper)
et.push(t)
t = Element.new(1,scissors)
et.push(t)
t = Element.new(2,stone)
et.push(t)

arr =[paper,scissors,stone]
score_rank = [0,1,2]
win_score = [paper * count,scissors * count,stone * count]

#0:paper 1:scissors 2:stone
arr.sort!{|a, b| -(a <=> b)}
for i in 0..2 do #score rank sort
 for j in 0..2 do
  if et[j].value == arr[i] then
   score_rank[i] = et[j].id
  end
 end
end

lose = [0,1]
lose[0] = score_rank[0]
lose[1] = score_rank[0] == 0 ? 2 : score_rank[0] - 1

for i in 0..1 do
 et[lose[i]].print_name
 if 0==i then
  print ""
 end
end
puts " を交互に出せばよい"
sc = ( win_score[lose[0]] ) / 2
print "自分、相手の賞金額は","#{sc}","\n"
exit

[]追記:あえて最初に書くのも無粋かと思ったけど、これって一種の行動心理テストに近いものがあるなーと・・・ってのは勘違いか^^;[]