challenge マルバツゲーム

マルバツゲームは3×3の格子に交互に○と×を書き込み、先に縦・横・斜めに記号をそろえたほうが勝ちというおなじみのゲームです。

「毎ターン乱数を使って手を決めるランダムプレイヤー同士を対戦させる」というのが今回のお題です。 1万回対戦させ、勝ち・負け・引き分けの数を表示してください。 そして先手が有利であることを確かめてください。

良い手を思考するプレイヤーについては別のお題にしようと思っています。 プレイヤーを簡単に差し換えることができる設計を目指してください。

Posted feedbacks - Ruby

Rubyらしくなくビット演算を使ってみました。○,×それぞれ9ビットのビット配列(実際にはただの整数)を用意し、ゲーム盤を表現しています。
0x1c0, 0x124, 0x111, 0x92, 0x54, 0x49, 0x38, 0x7
は3つ並んだかどうか判定するためのマスクです。例えば、0x111は2進数で100010001となりますが、これを3ビットずつ並べると
100
010
001
となり、斜めの判定パターンになってることが分かります。これと○・×のビット配列の論理和を取ることで、並んだかの判定を行うことが出来ます。

実行例です。
ruby marubatu.rb
{"PLAYER 0"=>5870, "PLAYER 1"=>2828, "DRAW"=>1302}
 
PLAYER 0が先手、 PLAYER 1が後手です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Judge
  def initialize(player1, player2)
    @players = []
    @players[0] = player1
    @players[1] = player2
  end

  def is_end?(ban)
    [0x1c0, 0x124, 0x111, 0x92, 0x54, 0x49, 0x38, 0x7].each do |mask|
      if ban & mask == mask then
        return true
      end
    end
    return false
  end

  KOMA = {0 => " ", 1 => "○", 2 => "×"}
  def display(play1, play2)
    print "---\n"
    (0..2).each do |i|
      (0..2).each do |j|
        print KOMA[(play1 & 1) + ((play2 & 1) << 1)]
        play1 >>= 1
        play2 >>= 1
      end
      print "\n"
    end
    print "---\n"
    print "\n"
  end

  def play(vervose = false)
    bans = [0, 0]
    curplayer = 0
    (1..9).each do |no|
      other = 1 - curplayer
      bans[curplayer] = @players[curplayer].think(bans[curplayer], bans[other])
      if vervose then
        display(bans[0], bans[1])
      end

      if is_end?(bans[curplayer]) then
        return "PLAYER #{curplayer}"
      end
      curplayer = other
    end

    "DRAW"
  end

end

class Player
  def think(myban, yourban)
    r = 0
    begin
      r = rand(9)
    end while ((myban | yourban) & (1 << r) != 0)

    myban | (1 << r)
  end
end

result = Hash.new(0)
jd = Judge.new(Player.new, Player.new)
(1..10000).each do |n|
  result[jd.play] += 1
end

p result

Index

Feed

Other

Link

Pathtraq

loading...