マルバツゲーム
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;
}
|
groovyのカバレッジをあげるべく、書いてみました。 動かしてみたら、すごく遅かったです。
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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | class Report{
def circleWin = 0
def xrosWin = 0
def tie = 0
}
class Game {
def curPlayer
def circlePlayer
def xrosPlayer
def report
def board
def play(){
board = new Board()
circlePlayer.type = 'CIRCLE'
xrosPlayer.type = 'XROS'
curPlayer = xrosPlayer
while( !board.getWinner() ){
curPlayer.set(board)
swapPlayer()
}
def winner = board.getWinner()
if (winner == 'CIRCLE') report.circleWin ++
if (winner == 'XROS') report.xrosWin ++
if (winner == 'TIE') report.tie++
}
def swapPlayer(){
curPlayer = (curPlayer == circlePlayer) ? xrosPlayer : circlePlayer
}
}
class Player {
def type
def set(board){
board.set(select(board.available()),type[0])
}
def select(available){
def idx = (Math.floor(Math.random() * available.size())) as int
available[idx]
}
}
class Board {
def field = []
def winPattern = [ [0,1,2], [3,4,5], [6,7,8],
[0,3,6], [1,4,7], [2,5,8],
[0,4,8], [2,4,6]]
Board(){
9.times{field[it] = ''}
}
def available(){
def result = []
field.eachWithIndex{var, idx ->
if (!var) result << idx
}
result
}
def getWinner(){
def winner = ''
winPattern.each{ pattern ->
def var = ''
pattern.each{ idx ->
var += field[idx]
}
switch (var){
case 'CCC': winner = 'CIRCLE'; break;
case 'XXX': winner = 'XROS'; break;
}
}
if (winner == '' && available() == []) winner = 'TIE'
winner
}
def set(idx, var){ field[idx] = var }
}
def report = new Report()
def player1 = new Player()
def player2 = new Player()
10000.times{
new Game(circlePlayer:player1, xrosPlayer:player2, report:report).play()
}
println report.dump()
|



syat
#6190()
Rating5/5=1.00
マルバツゲームは3×3の格子に交互に○と×を書き込み、先に縦・横・斜めに記号をそろえたほうが勝ちというおなじみのゲームです。
「毎ターン乱数を使って手を決めるランダムプレイヤー同士を対戦させる」というのが今回のお題です。 1万回対戦させ、勝ち・負け・引き分けの数を表示してください。 そして先手が有利であることを確かめてください。
良い手を思考するプレイヤーについては別のお題にしようと思っています。 プレイヤーを簡単に差し換えることができる設計を目指してください。
[ reply ]