challenge マルバツゲーム

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

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

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

Posted feedbacks - Other

ちょっと力業でしょうか。

 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
(use srfi-1)
(use srfi-27)
(use util.list)

(random-source-randomize! default-random-source)

;; board: (0 1 0 0 0 0 0 0 0)
;; board -> board
(define (player-random board self)
  (define (okeru)
    (length (filter zero? board)))

  (let loop ((board board)
         (next  (random-integer (okeru))))
    (if (null? board)
    ()
    (cons (if (= next 0)
          self
          (car board))
          (loop (cdr board)
            (if (= (car board) 0)
            (- next 1)
            next
            ))))))

(define (play p1 p2)
  (define (finish? board)
    (or (> (judge board) 0)
    (not (find zero? board))))

  (let loop ((board (make-list 9 0))
         (phase 1))
    (if (finish? board)
    board
    (if (= phase 1)
        (loop (p1 board 1) 2)
        (loop (p2 board 2) 1)))))

(define (judge board)
  (define line-points-list
    '((0 1 2)
      (3 4 5)
      (6 7 8)
      (0 3 6)
      (1 4 7)
      (2 5 8)
      (0 4 8)
      (2 4 6)))

  (define (judge-4-player n)
    (find (lambda (line-points)
        (every (lambda (j)
             (= (ref board j) n))
           line-points))
      line-points-list))

  (cond ((judge-4-player 1) 1)
    ((judge-4-player 2) 2)
    (else 0)))

(define (marubatsu p1 p2)
  (define (one-play)
    (judge (play p1 p2)))

  (define hash (make-hash-table))
  (dotimes (counter 10000)
    (hash-table-update! hash (one-play) (cut + 1 <>) 0))

  (write (hash-table->alist hash)))

drawを先に判定しちゃダメじゃん...

というわけで、100万回試行の結果がちゃんと

player 1 won : 585255(0.585255)
player 2 won : 287878(0.287878)
draw : 126867(0.126867)

になりました。

 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
int
board_checker::operator()(board& b)
  const
{
  if ( int id = b(1,1) )
    if ((b(0,0) == id && b(2,2) == id ) ||
        (b(0,2) == id && b(2,0) == id) ||
        (b(0,1) == id && b(2,1) == id) ||
        (b(1,0) == id && b(1,2) == id) )
      return id;
  if ( int id = b(0,0) )
    if ((b(0,1) == id && b(0,2) == id) ||
        (b(1,0) == id && b(2,0) == id) )
      return id;
  if ( int id = b(2,2) )
    if ((b(1,2) == id && b(0,2) == id) ||
        (b(2,1) == id && b(2,0) == id) )
      return id;

  bool draw=true;
  for (int x = 0; draw && x < 3; ++x )
    for (int y = 0; draw && y < 3; ++y )
      draw = b(x,y) != 0;
  if ( draw )
    return -1;
  // not finish
  return 0;
}

Index

Feed

Other

Link

Pathtraq

loading...