Ruby Tips / Rubyで囚人のジレンマ?ゲーム作ってみた

Powered by dKingyo CSS | ゲーム理論 | ツクール | 統計学 | Rails

[wikipedia:囚人のジレンマ]の理論はよく分からないけど、ある程度遊べるかもしれないフレームワークを作ってみた。
名付けてジャン拳 V.S. ジャジャン拳 framework !!!!!!!


ちなみに
ジャン拳の元ネタはドラゴンボール
ジャジャン拳の元ネタはHUNTER×HUNTER
だったりする。


閑話休題・・・


このフレームワークで出来る事は

  • 各手の勝ちの点数を決める事が出来る
  • 各手の負け、引き分けの点数も決める事が出来る
  • 今までのスコアや相手が出した手や勝ち負けなどの成績を思考ルーチン側が取得する事ができる*1
  • 最後にキメ台詞をはく事が出来きる!?

等など 魅力的!?な機能がたくさんあります。


で、私の環境でちょっと遊んでみた所・・・
ランダム出力は以外と弱かった・・・
そして、今のところ d金魚 01 ルーチンに敵なし!!! *2
続きを読む
最新版はhttp://www.dkut.flnet.org/result.html#zyazyanよりダウンロードできます。


#usr/local/bin/ruby
=begin
Copyright(C) 2007 d金魚

ジャン拳 V.S. ジャジャン拳 framework version 2007.03.29
囚人のジレンマをプログラムで対戦させるフレームワーク...?
嗚呼!不毛だ!!!


自分のルーチンを組む場合はZyanやZyaZyanやDKingyo01参考にしてください。
とりあえず、ソースコードのライセンスはGPLでお願いします。
NYSLにしたいところだけれども・・・)
できれば相手方のルーチンとDKingyo01を戦わせてみたいと思いますし、
DKingyo02も控えていますし・・・何かのネタになればなにより。
=end



WIN =0
LOSE=1
DRAW=2

PAPER = 0
SCISSORS = 1
STONE = 2

class Score
# @param paper scissors stone スコアを入れる。
def initialize(paper,scissors,stone)
@score = [paper,scissors,stone]
end
attr_reader :score
end

class Record
def initialize(win,draw,score_)
@win_count = win
@draw_count= draw
@score = score_
end
attr_reader :win_count, :draw_count, :score

end

#0:paper 1:scissors 2:stone
class State
#a bの勝った数
@awin_count = 0
@bwin_count = 0
#引き分けの数
@draw_count = 0
#a b のスコア
@ascore = 0
@bscore = 0
#今のカウント
@now_count

# @param win_score_,lose_score_,draw_score_ スコアオブジェクトを入れる
# @param count_ 試行回数を入れる
# @param comflag コメントフラグ TRUEでコメント出力
def initialize(win_score_,lose_score_,draw_score_,count_,comflag=false)
@win_score = win_score_
@lose_score = lose_score_
@draw_score = draw_score_
@win_score_rank = [0,1,2]
@lose_score_rank= [0,1,2]
@draw_score_rank = [0,1,2]
@count = count_
@comment_flag = comflag
score_calc(win_score.score,win_score_rank)
score_calc(lose_score.score,lose_score_rank)
score_calc(draw_score.score,draw_score_rank)
print_score_rank
end

attr_reader :win_score, :lose_score, :draw_score,
:win_score_rank, :lose_score_rank, :draw_score_rank,
:count, :now_count,
:awin_count, :bwin_count, :draw_count, :ascore, :bscore

def score_calc(score,score_rank)
arr = score.clone
arr.sort!{|a, b| -(a <=> b)}

for i in 0..2 do #score rank sort
for j in 0..2 do
if score[j] == arr[i] then
if 0<i && score[j] == arr[i-1] then # 同条件問題
score_rank[i] = (2 == score_rank[i-1]) ? 0 : score_rank[i-1] + 1
else
score_rank[i] = j

end

break;

end
end
end
return arr
end

def action_name(v)
case(v)
when PAPER
return "パー "
when SCISSORS
return "チョキ"
when STONE
return "グー "
else
return "必殺!グーチョキパー同時出し!"#知っている人いるかな?
end
end

def print_score_rank
puts "勝ち得点表\" # 最後に\を挿入しないとインタプリタがバグる
for i in 0..STONE do
r = win_score_rank[i]
print action_name(r)
print " ",win_score.score[r],"\n"
end

puts "負け得点表\"
for i in 0..STONE do
r = lose_score_rank[i]
print action_name(r)
print " ",lose_score.score[r],"\n"
end

puts "あいこ得点表\"
for i in 0..STONE do
r = draw_score_rank[i]
print action_name(r)
print " ",draw_score.score[r],"\n"
end
print "\n"
end

def lose_point(action)
return lose_score.score[action]
end

def win_point(action)
return win_score.score[action]
end

def draw_point(action)
return draw_score.score[action]
end

# -1:aの勝ち 0:あいこ 1:bの勝ち
def check(a,b)
#追記:2007年3月31日バグがあったので更新
if a==b then
return 0
end
case(a)
when PAPER
if SCISSORS==b then
return 1
end

when SCISSORS
if STONE==b then
return 1
end

when STONE
if PAPER==b then
return 1
end

end
return -1
=begin
バグの元
if a==b then
return 0
end
a = a==0 ? 3 : a
b = b==0 ? 3 : b

if a < b then
return 1
end
return -1
=end

end
#ここの中をいじって途中でルールが変わるようにしても面白い
def fight(a,b)
@awin_count = 0
@ascore = 0
@bscore = 0
@draw_count = 0
@bwin_count = 0
@now_count = 0

for i in 0 .. count - 1 do
arecord = Record.new(awin_count,draw_count,ascore)
brecord = Record.new(bwin_count,draw_count,bscore)

ar = a.calc(self,arecord,brecord)
br = b.calc(self,brecord,arecord)

re = check(ar,br)

ares = DRAW
bres = DRAW

case(re)
when -1
ares = WIN
bres = LOSE
@awin_count = @awin_count + 1
@ascore = @ascore + win_point(ar)
@bscore = @bscore + lose_point(br)
when 0
ares = bres = DRAW
@draw_count = @draw_count + 1
@ascore = @ascore + draw_point(ar)
@bscore = @bscore + draw_point(br)
when 1
ares = LOSE
bres = WIN
@bwin_count = @bwin_count + 1
@ascore = @ascore + lose_point(ar)
@bscore = @bscore + win_point(br)

end

a.result(ares,ar,br)
b.result(bres,br,ar)

@now_count = @now_count + 1
end

print a.name," 勝利数 : ",awin_count," 賞金総額 : ",ascore,"円\n"
print b.name," 勝利数 : ",bwin_count," 賞金総額 : ",bscore,"円\n"
print "あいこ : ",draw_count,"\n\n"

if true==@comment_flag
arecord = Record.new(awin_count,draw_count,ascore)
brecord = Record.new(bwin_count,draw_count,bscore)

print a.name,"のコメント\n"
a.comment(self,arecord,brecord)
print "\n"

print b.name,"のコメント\n"
b.comment(self,brecord,arecord)
print "\n"
end
end


end


class Zyan
def initialize
@name = "悟空"
end

attr_reader :name

def calc(state,your_record,enemy_record)
res = state.now_count % 3

return res
end

def result(res,your_action,enemy_action)

end
def comment(state,your_record,enemy_record)
if your_record.score < enemy_record.score
puts "オラ負けちまったぞ!"
else
puts "オラ勝っちまったぞ!"
end
end
end

class ZyaZyan
def initialize
@name = "ゴン"
end
attr_reader :name
def calc(state,your_record,enemy_record)
res = rand(3)
return res
end

def result(res,your_action,enemy_action)

end
def comment(state,your,enemy)
if your.score < enemy.score then
#puts ゴンっぽいセリフを入れてくれ
end
end
end

class DKingyo01
def initialize
@name = "d金魚 01"
@pattern = [0,1]
@next_action = -1
@ctr = 0
@foul_ctr = 0
end

attr_reader :name

def get_lose(score_rank)
return score_rank[0] == 0 ? STONE : score_rank[0] - 1
end
# @state ステート Stateクラスが入る
# @your_record Recordクラスが入る あなたの成績が参照できる
# @enemy_action 敵の成績が... 上記同
def calc(state,your_record,enemy_record)
@pattern[0] = state.win_score_rank[0]
@pattern[1] = get_lose(state.win_score_rank[0])

if -1 != @next_action then
return @next_action
else
@next_action = @pattern[0]
end

return @next_action
end
# @res 結果 WIN LOSE DRAWのどれか
# @your_action あなたの手 PAPER SCISSORS STONEのどれか
# @enemy_action 敵の手 上記同
def result(res,your_action,enemy_action)
if WIN==res then
@ctr = @ctr + 1
end
@next_action = @pattern[@ctr % 1]

if enemy_action != @pattern[0] && enemy_action != @pattern[1] then
@next_action = enemy_action
@foul_ctr = @foul_ctr + 1
end
end
#最後に出力させるコメント 引数からどのオブジェクトが格納されるのかは上記参照
def comment(state,your,enemy)
if @foul_ctr > state.count / 4 then
print state.count,"中 ",@foul_ctr,
"回も期待に添わない手を出してくるあなたって卑怯ね\n"
print "そして・・・"
end
if your.score > enemy.score then
puts "私の勝ち"
else
puts "まいったー おrz"
end
end
end


#今回のルールは元ネタによる
# http://satoshi.blogs.com/life/2007/03/post_16.html
#Score.new(paper,scissors,stone)
win = Score.new(500,200,0)
lose= Score.new(0,0,0)
draw= Score.new(0,0,0)

Prisoners_Dilemma = State.new(win,lose,draw,1000)

Prisoners_Dilemma.fight(Zyan.new,ZyaZyan.new)

Prisoners_Dilemma.fight(Zyan.new,DKingyo01.new)

Prisoners_Dilemma.fight(ZyaZyan.new,DKingyo01.new)

#todo 総当たり戦とかランキング出力とか出来るね。
# それから自分の手の引数から勝ち負けの手を返すメソッドとか?

*1:なので思考ルーチン側が配列を用意して今までの敵の手を保存してパターンを解析したり事も可能。

*2:これを井の中の蛙と言う。追記:何故かアホなルーチンだったのに敵なしだった訳は勝敗チェックルーチンがバグっていたからです。(爆)