Line 1: Error: Invalid Blog('by Esehara' )

または私は如何にして心配するのを止めてバグを愛するようになったか

>> Zanmemo

あと何かあれは 「esehara あっと じーめーる」 か @esehara まで

ジャンケンみたいに三すくみになるサイコロについて

今日の風景

f:id:nisemono_san:20160810152435j:plain

mograg garage【ART SPACE /GALLERY】の展示で買った郡司侑祐という方の作品です。

はじめに

普通、サイコロと言うと、1から6までの数字が書いてあるものだ。イカサマのサイコロでは無い限り、お互いの出た目を比較すると、だいたい半々の確率になる筈だろう。しかし、これではゲーム性があまりにもない。そこで、サイコロの目を改造し、あるサイコロAと、あるサイコロB、あるサイコロCの出目がそれぞれジャンケンのように、三すくみになるようなサイコロが作れるという話が実はある。

オンライン上では、英語になるけれども、この記事で概要を知ることができる。また、実物は海外だとグランド・イリュージョン社が販売している。

f:id:nisemono_san:20160810225508j:plain

側面が二つ2のサイコロと、見えている側面全部が4であるサイコロが見える。

さて、このサイコロを実際に自分達の手で作ってみることは非常に楽しいことであるのは間違いないけれども、プログラマーなんだから、簡単にこの手のダイズについてシミュレーションしてみるのが楽しいだろう。

ジャンケンみたいなサイコロの組みあわせ

まず、最初にこの「ジャンケンみたいなサイコロ」の定義から始める。まず、任意の目を持つサイコロが三種類あり、それぞれのサイコロに対して、A、B、Cと名づける。このとき、AはBより勝率が高く、AはCより勝率が低い。同様に、BはCより勝率が高い。当然、CはAより勝率が高い……というようにくりかえされる。

さて、まず気になる出目に関してだが、3つ見つかっている。

  • {3, 3, 5, 5, 7, 7}, {2, 2, 4, 4, 9, 9}, {1, 1, 6, 6, 8, 8}
  • {1, 1, 1, 13, 13, 13}, {0, 3, 3, 12, 12, 12}, {2, 2, 2, 11, 11, 14}
  • {1, 4, 4, 4, 4, 4}, {3, 3, 3, 3, 3, 6}, {2, 2, 2, 5, 5, 5}

元記事によれは、最初の3組は、下の魔方陣から取られている。

|8|1|6|
|3|5|7|
|4|9|2|

それぞれの横の列が、そのままこのジャンケンみたいなサイコロの出目となっている。

実際に勝負させてみる

というわけで、実際に勝負させてみよう。これは簡単なプログラムなので、Lisp系であるところのRacketを使って書き下してみよう:

(define dice-a '(3 3 7 7 5 5))
(define dice-b '(2 2 9 9 4 4))
(define dice-c '(1 1 8 8 6 6))

(define (winner? a b)
  (> (car (shuffle a)) (car (shuffle b))))

(define (win a b)
  (printf "勝利数: ~a\n"
   (count (lambda(x) x)
          (build-list 100000 (lambda (x) (winner? a b))))))

特徴としては、build-listが、第2引数の回数だけ、第三引数の関数の結果をリスト化している。さて、まずdice-adice-bを5回セットさせてみると、以下のようになる。

> (for ([i 5]) (win dice-a dice-b))
勝利数: 55763
勝利数: 55565
勝利数: 55306
勝利数: 55609
勝利数: 55500

だいたい、5.5割の確率で勝利する。同様にAとCの場合:

> (for ([i 5]) (win dice-a dice-c))
勝利数: 44678
勝利数: 44407
勝利数: 44390
勝利数: 44805
勝利数: 44593

となる。つまり、0.5割ほど有利だということになる。次に、dice-bdice-cを組みあわせた場合

> (for ([i 5]) (win dice-b dice-c))
勝利数: 55475
勝利数: 55514
勝利数: 55418
勝利数: 55576
勝利数: 55436

となり、若干有利である。

2回振ると逆転するようなサイコロ

さて、次は{1, 4, 4, 4, 4, 4}, {6, 3, 3, 3, 3, 3}, {2, 2, 2, 5, 5, 5}なのだが、これには不思議な特徴があるらしい。その特徴というのが、なんでも二回振った合計の数だと、勝率が逆転してしまうというものらしい。なので、下のようにリファクタする

#lang racket
(define dice-a '(1 4 4 4 4 4))
(define dice-b '(6 3 3 3 3 3))
(define dice-c '(2 2 2 5 5 5))

(define (throw a) (car (shuffle a)))

(define (winner? a b)
  (> (throw a) (throw b)))

(define (winner-two? a b)
  (> (+ (throw a) (throw a))
     (+ (throw b) (throw b)))) 

(define (win a b)
  (printf "1回だけの勝利数: ~a\n"
   (count (lambda(x) x)
          (build-list 100000 (lambda (x) (winner? a b))))))

(define (win-two a b)
  (printf "2回の勝利数: ~a\n"
   (count (lambda(x) x)
          (build-list 100000 (lambda (x) (winner-two? a b))))))```

一度だけ振ってみる

まず、dice-adice-bの勝率から:

> (for ([i 5]) (win dice-a dice-b))
1回だけの勝利数: 69428
1回だけの勝利数: 69579
1回だけの勝利数: 69485
1回だけの勝利数: 69529
1回だけの勝利数: 69625

次に、dice-adice-cの勝率:

1回だけの勝利数: 41912
1回だけの勝利数: 41687
1回だけの勝利数: 41898
1回だけの勝利数: 41521
1回だけの勝利数: 41748

最後に、dice-bdice-cの勝率:

1回だけの勝利数: 58290
1回だけの勝利数: 58308
1回だけの勝利数: 58267
1回だけの勝利数: 58166
1回だけの勝利数: 58587

若干ばらつきはあるものの、AとBが対決した場合は、Aは7割勝利し、AとCが対決した場合はAは4割勝利し、BとCの場合は5.8割となる。ゲームとしてはともかく、定義的にはあっている。

次に二回振ってみる

そこで、次に二回振ってみることにする。dice-aおよびdice-bの場合だとすると:

> (for ([i 5]) (win-two dice-a dice-b))
2回の勝利数: 48276
2回の勝利数: 47996
2回の勝利数: 48410
2回の勝利数: 48008
2回の勝利数: 48136

ということになり、dice-adice-cだと

> (for ([i 5]) (win-two dice-a dice-c))
2回の勝利数: 59055
2回の勝利数: 59072
2回の勝利数: 59139
2回の勝利数: 59035
2回の勝利数: 59024

ということになる。そこで、さらにdice-bdice-cを比較すると:

(for ([i 5]) (win-two dice-b dice-c))
2回の勝利数: 40914
2回の勝利数: 40884
2回の勝利数: 40908
2回の勝利数: 41044
2回の勝利数: 41082

となるので、見事有利なサイコロが逆転した

まとめ

これが数学に属するのかどうかはよくわからないけれども、このように三すくみのサイコロができるという観点は面白かった。このサイコロはちょっと欲しい気もするけれども、作るとなると、オーダーメイドになるよなーという感じではある。それはともかくとして、「サイコロにはこういう観点から見ることもできるのだな」と思ったので、とてもわかりがあってとても面白かった。

反直観の数学パズル―あなたの数学的思考力を試す14の難問

反直観の数学パズル―あなたの数学的思考力を試す14の難問

数学のおもちゃ箱 下

数学のおもちゃ箱 下