いまさら森博嗣「笑わない数学者」の24点ゲームを解く

# 0. はじめに

将棋の竜王戦の決勝トーナメントを以下に示す。一見とても不公平に見えるが，竜王戦の参加者は実力順に一組から六組までにカテゴライズされており，それらの組予選を勝ち抜いた者同士のトーナメントのため，実力上位の一組出場者から順に優遇されるという仕組みである。プロ野球のクライマックスシリーズやサッカーの天皇杯なども同様の仕組みであり，決して珍しくはないだろう。他に将棋にはパラマス方式を採用した銀河戦予選もある。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontStyle: normal;
  fontSize: 16;
}
</style>
sprite FIGURE <svg width="465" height="360" viewbox="0 0 465 460">
<g fill="black">
<path d="M220  13 h100 v2 h-100">
<path d="M220  45 h80  v2 h-80">
<path d="M220  77 h60  v2 h-60">
<path d="M220 109 h40  v2 h-40">
<path d="M220 141 h20  v2 h-20">
<path d="M220 173 h20  v2 h-20">
<path d="M220 205 h80  v2 h-80">
<path d="M220 237 h80  v2 h-80">
<path d="M220 269 h60  v2 h-60">
<path d="M220 301 h60  v2 h-60">
<path d="M220 333 h80  v2 h-80">

<path d="M240 141 v34 h2 v-34">
<path d="M240 157 h20 v2 h-20">
<path d="M260 109 v50 h2 v-50">
<path d="M260 133 h20 v2 h-20">
<path d="M280  77 v58 h2 v-58">
<path d="M280 105 h20 v2 h-20">
<path d="M300  45 v62 h2 v-62">
<path d="M300  75 h20 v2 h-20">
<path d="M320  13 v64 h2 v-64">
<path d="M320  44 h20 v2 h-20">
<path d="M340  44 v223 h2 v-223">
<path d="M340 155 h20 v2 h-20">

<path d="M300 205 v34 h2 v-34">
<path d="M300 221 h20 v2 h-20">
<path d="M280 269 v34 h2 v-34">
<path d="M280 285 h20 v2 h-20">
<path d="M300 285 v50 h2 v-50">
<path d="M300 309 h20 v2 h-20">
<path d="M320 221 v90 h2 v-90">
<path d="M320 265 h20 v2 h-20">
</g>
<text x="10"  y="20"  fill="black" font-size="16">一組優勝　山崎　隆之八段</text>
<text x="10"  y="52"  fill="black" font-size="16">一組四位　広瀬　章人九段</text>
<text x="10"  y="84"  fill="black" font-size="16">一組五位　斎藤慎太郎八段</text>
<text x="10"  y="116" fill="black" font-size="16">四組優勝　高野　智史六段</text>
<text x="10"  y="148" fill="black" font-size="16">五組優勝　渡辺　和史七段</text>
<text x="10"  y="180" fill="black" font-size="16">六組優勝　藤本　渚　五段</text>
<text x="10"  y="212" fill="black" font-size="16">一組三位　久保　利明九段</text>
<text x="10"  y="244" fill="black" font-size="16">二組優勝　佐々木勇気八段</text>
<text x="10"  y="276" fill="black" font-size="16">二組二位　郷田　真隆九段</text>
<text x="10"  y="308" fill="black" font-size="16">三組優勝　池永　天志六段</text>
<text x="10"  y="340" fill="black" font-size="16">一組二位　佐藤　康光九段</text>
<text x="380" y="162" fill="black" font-size="16">竜王挑戦者</text>
</svg>
title
<$FIGURE>
図０　竜王戦決勝トーナメント表（第37期）
end title
@enduml
```

このようにトーナメント表というのは，さまざまなバリエーションが存在し得る。$n$ 人が参加するトーナメントの場合，試合数は $n - 1$ になるが，いったいどのくらいのバリエーションが考えられるのだろうか・・・と考えを巡らせていると，昔解けなかった問題を解決するヒントを思いついた。

# 1. 問題

昔解けなかった問題とは森博嗣氏の小説「笑わない数学者」に登場する 24 点ゲームである。最初の二つの問題の出題者は劇中の登場人物である数学者・天王寺翔蔵博士，最後の問題は西之園萌絵嬢である。

<dl><dt>レベルⅠ</dt>
<dd>まず，ちょっとした算数の問題を出そう。考えたまえ。10 が二つ，4 が二つある。どんな順番でも良いから，これらを全部使って，足したり，引いたり，掛けたり，割ったりして，答を 24 にしたまえ。</dd></dl>
<dl><dt>レベルⅡ</dt>
<dd>では，今度は 7 が二つ， 3 が二つだ。この四つの数で同じように 24 を作りたまえ。</dd></dl>

<dl><dt>レベルⅢ</dt>
<dd>私ね，問題考えたの。難しいわよ。8，8，3，3 で，24 を作れます？</dd></dl>

:::note
中国で 24 点ゲームというトランプを用いたゲームが元ネタのようだ。1～10 までのカードから四枚抽出し，四則演算を駆使して 24 を作ることを競い合う。数字が 1～10 に限られているのは，中国も日本と同じく九九を学ぶので一桁の掛け算は容易にできるからだろう。10 の掛け算も容易なのは言うまでもない。
:::

# 2. まずは手計算で解く

十年ぶりの再挑戦である。ちなみに十年前は一問も解けなかった。

## 2.1 レベルⅠ

10, 10, 4, 4 で 24 を作る。試しに全部足してみると

```math
10 + 10 + 4 + 4 = 28 \tag{1-1}
```

となり，24 より大きな数字になるため引き算か割り算が必要となる。とはいえ単純な引き算では上手く行かない。

```math
\begin{aligned}
10 - 10 + 4 + 4 &= 8 \\ 
10 + 10 + 4 - 4 &= 20 \\ 
\end{aligned} \tag{1-2}
```

次に割り算を使ってみよう。$10/4$ も $4/10$ も整数にならないが

```math
\frac{10 \times 10}{4} = 25 \tag{1-3}
```

であればいい感じの（24 に近い）整数になる。ここから 1 を引けば 24 になるので

```math
\frac{10 \times 10}{4} - 1 = \bbox[4pt, border:2px dotted blue]{\frac{10 \times 10 - 4}{4} = 24} \tag{1-4}
```

となる。

## 2.2 レベルⅡ

7, 7, 3, 3 で 24 を作る。試しに全部足してみると

```math
7 + 7 + 3 + 3 = 20 \tag{2-1}
```

となり，24 より小さな数字になるため<b>「掛け算が必要」</b>と考えた。試しに掛け算を使ってみると

```math
7 \times 3 = 21 \tag{2-2}
```

となる。これに 3 を加えれば 24 が得られるので 

```math
7 \times 3 + 3 = \bbox[4pt, border:2px dotted blue]{7 \times \left( 3 + \frac{3}{7} \right) = 24} \tag{2-3}
```

となる。

## 2.3 レベルⅢ

8, 8, 3, 3 で 24 を作る。試しに全部足してみると

```math
8 + 8 + 3 + 3 = 22 \tag{3-1}
```

となり，24 より小さな数字になるため<b>「掛け算が必要」</b>と考えた。試しに掛け算を使ってみると

```math
8 \times 3 = 24 \tag{3-2}
```

となるが，これでちょうど良いのが困る。0 を足す，または 1 を掛けるにしても残る 8 と 3 では 0 も 1 も作れないからだ。この後 $8 \times 8$ や $3 \times 3$ をベースにして考えてみたがダメだった。実は<b>「掛け算が必要」</b>という前提が間違っているため，このまま考えても正解に辿り着くことは出来なかったのだ。

# 3. 計算機による力業で解く

ということで計算機による力業で解いてみよう。


まず組み合わせのパターンを求める。加減乗除の四則演算は全て二項演算，すなわち入力が二つ，出力が一つの関数であると考えると，二人のうち一人が敗退して一人が勝ち抜くトーナメントと同じように考えられる。トーナメントといってもフラットなものからシード付きのもの，将棋の竜王戦の決勝トーナメントのような変則トーナメントまで様々あるが，エントリーが四人だと以下の五種類しかないことが分かる。

演算子ⓧⓨⓩは加減乗除のいずれかであり，ABCD に当てはめる数字も後で決めるので，ここではトーナメントの種類（形）だけ考えれば良い。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontStyle: normal;
  fontSize: 17;
}
</style>
sprite FIGURE <svg width="500" height="300" viewbox="0 0 500 300">
<g fill="black">
<path d="M25  100 v-60 h1 v60" />
<path d="M57  100 v-40 h1 v40" />
<path d="M89  100 v-20 h1 v20" />
<path d="M121 100 v-20 h1 v20" />
<path d="M89  80 h32 v1 h-32" />
<path d="M105 80 v-20 h1 v20" />
<path d="M57  60 h48 v1 h-48" />
<path d="M81  60 v-20 h1 v20" />
<path d="M25  40 h56 v1 h-56" />
<path d="M52  40 v-20 h1 v20" />
<g fill="white">
<circle cx="105" cy="80" r="8" />
<circle cx="81"  cy="60" r="8" />
<circle cx="52"  cy="40" r="8" />
</g>
<g fill="none" stroke="black">
<circle cx="105" cy="80" r="8" />
<circle cx="81"  cy="60" r="8" />
<circle cx="52"  cy="40" r="8" />
</g>
<text x="101.5" y="84"  fill="black" font-size="14">z</text>
<text x="77.5"  y="64"  fill="black" font-size="14">y</text>
<text x="48.5"  y="44"  fill="black" font-size="14">x</text>
<text x="20"  y="120" fill="black" font-size="20">A</text>
<text x="52"  y="120" fill="black" font-size="20">B</text>
<text x="84"  y="120" fill="black" font-size="20">C</text>
<text x="116" y="120" fill="black" font-size="20">D</text>

<path d="M205 100 v-20 h1 v20" />
<path d="M237 100 v-20 h1 v20" />
<path d="M269 100 v-20 h1 v20" />
<path d="M301 100 v-20 h1 v20" />
<path d="M205  80 h32 v1 h-32" />
<path d="M269  80 h32 v1 h-32" />
<path d="M220  80 v-20 h1 v20" />
<path d="M285  80 v-20 h1 v20" />
<path d="M221  60 h64 v1 h-64" />
<path d="M253  60 v-20 h1 v20" />
<g fill="white">
<circle cx="221" cy="80" r="8" />
<circle cx="285" cy="80" r="8" />
<circle cx="253" cy="60" r="8" />
</g>
<g fill="none" stroke="black">
<circle cx="221" cy="80" r="8" />
<circle cx="285" cy="80" r="8" />
<circle cx="253" cy="60" r="8" />
</g>
<text x="216.5" y="84"  fill="black" font-size="14">x</text>
<text x="281.5" y="84"  fill="black" font-size="14">z</text>
<text x="249.5" y="64"  fill="black" font-size="14">y</text>
<text x="200" y="120" fill="black" font-size="20">A</text>
<text x="232" y="120" fill="black" font-size="20">B</text>
<text x="264" y="120" fill="black" font-size="20">C</text>
<text x="296" y="120" fill="black" font-size="20">D</text>

<path d="M385 100 v-20 h1 v20" />
<path d="M417 100 v-20 h1 v20" />
<path d="M449 100 v-40 h1 v40" />
<path d="M481 100 v-60 h1 v60" />
<path d="M385  80 h32 v1 h-32" />
<path d="M401  80 v-20 h1 v20" />
<path d="M401  60 h48 v1 h-48" />
<path d="M425  60 v-20 h1 v20" />
<path d="M425  40 h56 v1 h-56" />
<path d="M453  40 v-20 h1 v20" />
<g fill="white">
<circle cx="401" cy="80" r="8" />
<circle cx="425" cy="60" r="8" />
<circle cx="453" cy="40" r="8" />
</g>
<g fill="none" stroke="black">
<circle cx="401" cy="80" r="8" />
<circle cx="425" cy="60" r="8" />
<circle cx="453" cy="40" r="8" />
</g>
<text x="397.5" y="84"  fill="black" font-size="14">x</text>
<text x="421.5" y="64"  fill="black" font-size="14">y</text>
<text x="449.5" y="44"  fill="black" font-size="14">z</text>
<text x="380" y="120" fill="black" font-size="20">A</text>
<text x="412" y="120" fill="black" font-size="20">B</text>
<text x="444" y="120" fill="black" font-size="20">C</text>
<text x="476" y="120" fill="black" font-size="20">D</text>

<path d="M25  260 v-60 h1 v60" />
<path d="M57  260 v-20 h1 v20" />
<path d="M89  260 v-20 h1 v20" />
<path d="M121 260 v-40 h1 v40" />
<path d="M57  240 h32 v1 h-32" />
<path d="M73  240 v-20 h1 v20" />
<path d="M73  220 h48 v1 h-48" />
<path d="M96  220 v-20 h1 v20" />
<path d="M25  200 h72 v1 h-72" />
<path d="M60  200 v-20 h1 v20" />
<g fill="white">
<circle cx="73" cy="240" r="8" />
<circle cx="96" cy="220" r="8" />
<circle cx="60" cy="200" r="8" />
</g>
<g fill="none" stroke="black">
<circle cx="73" cy="240" r="8" />
<circle cx="96" cy="220" r="8" />
<circle cx="60" cy="200" r="8" />
</g>
<text x="69.5" y="244" fill="black" font-size="14">y</text>
<text x="92.5" y="224" fill="black" font-size="14">z</text>
<text x="56.5" y="204" fill="black" font-size="14">x</text>
<text x="20"  y="280" fill="black" font-size="20">A</text>
<text x="52"  y="280" fill="black" font-size="20">B</text>
<text x="84"  y="280" fill="black" font-size="20">C</text>
<text x="116" y="280" fill="black" font-size="20">D</text>

<path d="M385 260 v-40 h1 v40" />
<path d="M417 260 v-20 h1 v20" />
<path d="M449 260 v-20 h1 v20" />
<path d="M481 260 v-60 h1 v60" />
<path d="M417 240 h32 v1 h-32" />
<path d="M433 240 v-20 h1 v20" />
<path d="M385 220 h48 v1 h-48" />
<path d="M409 220 v-20 h1 v20" />
<path d="M409 200 h72 v1 h-72" />
<path d="M440 200 v-20 h1 v20" />
</g>
<g fill="white">
<circle cx="433" cy="240" r="8" />
<circle cx="409" cy="220" r="8" />
<circle cx="440" cy="200" r="8" />
</g>
<g fill="none" stroke="black">
<circle cx="433" cy="240" r="8" />
<circle cx="409" cy="220" r="8" />
<circle cx="440" cy="200" r="8" />
</g>
<text x="429.5" y="244" fill="black" font-size="14">y</text>
<text x="405.5" y="224" fill="black" font-size="14">x</text>
<text x="436.5" y="204" fill="black" font-size="14">z</text>
<text x="380" y="280" fill="black" font-size="20">A</text>
<text x="412" y="280" fill="black" font-size="20">B</text>
<text x="444" y="280" fill="black" font-size="20">C</text>
<text x="476" y="280" fill="black" font-size="20">D</text>
</svg>
title
<$FIGURE>
図１　トーナメントの種類（形）
end title
@enduml
```

これを数式で表すと以下のようになる。またプログラムへ実装し易いよう逆ポーランド記法で表すと以下のようになる。

<table>
<caption>表１　演算の組み合わせ</caption>
<thead>
<tr><th style="text-align:center">No</th>
    <th style="text-align:center">数式</th>
    <th style="text-align:center">逆ポーランド記法</th></tr>
</thead>
<tbody>
<tr><td style="text-align:center">1</td>
    <td>${\bf A}\ ⓧ\ ({\bf B}\ ⓨ\ ({\bf C}\ ⓩ\ {\bf D}))$</td>
    <td>${\bf A}\ {\bf B}\ {\bf C}\ {\bf D}\ ⓩ\ ⓨ\ ⓧ$</td></tr>
<tr><td style="text-align:center">2</td>
    <td>${\bf A}\ ⓧ\ (({\bf B}\ ⓨ\ {\bf C})\ ⓩ\ {\bf D})$</td>
    <td>${\bf A}\ {\bf B}\ {\bf C}\ ⓨ\ {\bf D}\ ⓩ\ ⓧ$</td></tr>
<tr><td style="text-align:center">3</td>
    <td>$({\bf A}\ ⓧ\ {\bf B})\ ⓨ\ ({\bf C}\ ⓩ\ {\bf D})$</td>
    <td>${\bf A}\ {\bf B}\ ⓧ\ {\bf C}\ {\bf D}\ ⓩ\ ⓨ$</td></tr>
<tr><td style="text-align:center">4</td>
    <td>$(({\bf A}\ ⓧ\ {\bf B})\ ⓨ\ {\bf C})\ ⓩ\ {\bf D}$</td>
    <td>${\bf A}\ {\bf B}\ ⓧ\ {\bf C}\ ⓨ\ {\bf D}\ ⓩ$</td></tr>
<tr><td style="text-align:center">5</td>
    <td>$({\bf A}\ ⓧ\ ({\bf B}\ ⓨ\ {\bf C}))\ ⓩ\ {\bf D}$</td>
    <td>${\bf A}\ {\bf B}\ {\bf C}\ ⓨ\ ⓧ\ {\bf D}\ ⓩ$</td></tr>
<tr><td colspan=3></td></tr>
</tbody>
</table>

四つの数字のうち同じ数字を二つずつ用いる場合の組み合わせは六種類しかない。

<table>
<caption>表２　数値の組み合わせ</caption>
<thead>
<tr><th style="text-align:center">No</th>
    <th style="text-align:center">${\bf A}$</th>
    <th style="text-align:center">${\bf B}$</th>
    <th style="text-align:center">${\bf C}$</th>
    <th style="text-align:center">${\bf D}$</th></tr>
</thead>
<tbody>
<tr><td style="text-align:center">1</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$q$</td></tr>
<tr><td style="text-align:center">2</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td></tr>
<tr><td style="text-align:center">3</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td></tr>
<tr><td style="text-align:center">4</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td></tr>
<tr><td style="text-align:center">5</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td></tr>
<tr><td style="text-align:center">6</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$q$</td>
    <td style="text-align:center">$\color{red}{p}$</td>
    <td style="text-align:center">$\color{red}{p}$</td></tr>
</tbody>
</table>

トーナメント（演算の組み合わせ）が五種類，数値の組み合わせが六種類，演算子ⓧⓨⓩは加減乗除のいずれかであるから $4^3 = 64$ 通り，以上より $5 \times 6 \times 64 = 1920$ 通りのパターンを網羅すれば良いことが分かる。

:::note
加算と乗算については交換法則が成り立つので，うまくやればパターン数をもっと絞れると思うが，今回の記事ではそこまで踏み込まないことにする。
:::

# 4. プログラム実装

## 4.1 数式の網羅

まず数式の組み合わせ（トーナメント）は五種類しかない。数値 `A,B,C,D` および演算子 `x,y,z` は後ほど文字列置換を行う。

```javascript:数式の組み合わせ（逆ポーランド記法）
var	eq = [
	"A B C D z y x",
	"A B C y D z x",
	"A B x C D z y",
	"A B x C y D z",
	"A B C y x D z"
];
```

演算子は四則演算の四種類である。

```javascript:演算子の組み合わせ
var	op = ["+", "-", "*", "/"];
```

二つの整数 `p, q` より数式の組み合わせパターンを網羅すると以下のようになる。

```javascript:数式の組み合わせパターンを網羅する
var	list = [];
for(var h = 0; h < eq.length; h++) {
	for(var i = 0; i < op.length; i++) {
		for(var j = 0; j < op.length; j++) {
			for(var k = 0; k < op.length; k++) {
				var	s = eq[h];
				s = s.replace("x", op[i]);
				s = s.replace("y", op[j]);
				s = s.replace("z", op[k]);
				if(p == q) {
					list.push(calc(s, p, p, p, p));
				} else {
					list.push(calc(s, p, p, q, q));
					list.push(calc(s, p, q, p, q));
					list.push(calc(s, p, q, q, p));
					list.push(calc(s, q, p, p, q));
					list.push(calc(s, q, p, q, p));
					list.push(calc(s, q, q, p, p));
				}
			}
		}
	}
}
```

実際に数値 `A,B,C,D` を置換して計算する関数 `calc()` を示す。関数 `eval_rpn()` は逆ポーランド記法の計算を行う。※RPN: Reverse Polish Notation

```javascript:数式を計算する
var	calc = function(s, a, b, c, d) {
	s = s.replace("A", a);
	s = s.replace("B", b);
	s = s.replace("C", c);
	s = s.replace("D", d);
	var	v = eval_rpn(s);
	return {val:v, eq:s};
};
```
## 4.2 逆ポーランド記法の演算

逆ポーランド記法の計算はとても簡単に実装できる。入力文字列のパースを行って数値が来るとスタックに積み，演算子が来るとスタックから二つの数値を取り出して演算し，結果を再びスタックに積めば良いだけだ。※単項演算子のマイナス `-` は考えないものとする。

```javascript:逆ポーランド記法の演算
function eval_rpn(s) {
	var	a = s.split(" ");
	var	n, x, y, z;
	var	ret = [];
	for(var i = 0; i < a.length; i++) {
		var	s = a[i];
		/*--*/ if(s == "+") {
			y = ret.pop(); x = ret.pop(); z = x.add(y); ret.push(z);
		} else if(s == "-") {
			y = ret.pop(); x = ret.pop(); z = x.sub(y); ret.push(z);
		} else if(s == "*") {
			y = ret.pop(); x = ret.pop(); z = x.mul(y); ret.push(z);
		} else if(s == "/") {
			y = ret.pop(); x = ret.pop(); z = x.div(y); ret.push(z);
		} else {
			n = parseInt(s); z = new Fraction(n, 1);    ret.push(z);
		}
	}
	return ret.pop().toString();
}
```

## 4.3 分数計算

浮動小数点演算で実装すると，結果として整数を得られるはずでも丸め誤差によって整数を得られない場合がある。このため分数計算を行うクラスを実装した。とはいっても四則演算のルールとはとてもシンプルである。

```math
\left\{ \begin{aligned}
\frac{a}{b} + \frac{c}{d} &= \frac{ad + bc}{bd} \\
\frac{a}{b} - \frac{c}{d} &= \frac{ad - bc}{bd} \\
\frac{a}{b} \times \frac{c}{d} &= \frac{ac}{bd} \\
\frac{a}{b} \div \frac{c}{d} &= \frac{ad}{bc} \\
\end{aligned} \right. \tag{4-1}
```

有理数を分子 `num` と分母 `den` の二つの整数で保持し，コンストラクタで約分を行うようにした。なお分母 `den` は基本的に正の値となるように扱うが，計算過程でゼロになってしまう場合もある。その場合も例外を発生させずに計算を継続すること自体は可能である。

<table>
<caption>表３　約分ルール</caption>
<thead>
<tr><th rowspan=2 colspan=2><th colspan=3 style="text-align:center">分母 $\text{den}$</th></tr>
<tr><th style="text-align:center">$\text{den} > 0$</th>
    <th style="text-align:center">$\text{den} = 0$</th></tr>
</thead>
<tbody>
<tr></tr>
<tr><th rowspan=5 style="text-align:center">分子 $\text{num}$</th>
    <th style="text-align:center">$\text{num} > 0$</th>
    <td style="text-align:center">約分する<br>（正の有理数）</td>
    <td style="text-align:center">$\text{num} = 1,\quad\text{den} = 0$<br>（正の無限大）</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\text{num} = 0$</th>
    <td style="text-align:center">$\text{num} = 0,\ \text{den} = 1$<br>（ゼロ）</td>
    <td style="text-align:center">$\text{num} = 0,\quad\text{den} = 0$<br>（不能）</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\text{num} < 0$</th>
    <td style="text-align:center">約分する<br>（負の有理数）</td>
    <td style="text-align:center">$\text{num} = -1,\ \text{den} = 0$<br>（負の無限大）</td></tr>
<tr><th colspan=5></th></tr>
</tbody>
</table>

:::note
正の∞は $1/0$，負の∞は $-1/0$，ゼロは $0/1$ として内部データを保持するという意味である。
:::

```javascript:分数クラス
function Fraction(num, den) {
	//----------------------------------------------------------
	// コンストラクタ　※同時に約分を行う
	//----------------------------------------------------------
	if(den == 0) {
		/**/ if(num > 0) num =  1;
		else if(num < 0) num = -1;
	} else if(num == 0) {
		den = 1;
	} else {
		var	neg = false;
		if(num < 0) {
			num = -num;
			neg = true;
		}
		for(var q = 2; q <= den; q++) {
			while(num % q == 0 && den % q == 0) {
				num /= q;
				den /= q;
			}
		}
		if(neg) num = -num;
	}
	this.num = num;
	this.den = den;
	//----------------------------------------------------------
	// 加算
	//----------------------------------------------------------
	this.add = function(x) {
		var	n = this.num * x.den + x.num * this.den;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 減算
	//----------------------------------------------------------
	this.sub = function(x) {
		var	n = this.num * x.den - x.num * this.den;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 乗算
	//----------------------------------------------------------
	this.mul = function(x) {
		var	n = this.num * x.num;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 除算
	//----------------------------------------------------------
	this.div = function(x) {
		var	n = this.num * x.den;
		var	d = this.den * x.num;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 文字列変換
	//----------------------------------------------------------
	this.toString = function() {
		if(this.den == 1)
			return this.num.toString();
		else
			return this.num + "/" + this.den;
	};
}
```

無限大∞の計算について，現在の実装では無限大同士の加算を行うと $0/0$ になってしまう。

```math
\frac{1}{0} + \frac{1}{0} = \frac{1 \cdot 0 + 0 \cdot 1}{0 \cdot 0} = \frac{0}{0} \tag{4-2}
```

本来，分母が共通であるから

```math
\frac{1}{0} + \frac{1}{0} = \frac{1 + 1}{0} = \frac{2}{0} = \frac{1}{0}  \tag{4-3}
```

としたいところだが，今回の問題（四つの自然数による演算）では無限大同士の演算は生じないため手を抜いている。

## 4.4 実装コード

今回，ささっと手軽に作れる JavaScript で組んだ。

<details><summary><font color=blue><b>JavaScript プログラム game24.js の実装コードはコチラ</b></font></summary>

```javascript:game24.js
var	args = WScript.Arguments.Unnamed;
var	ret = main(args);
try {
	WScript.Quit(ret);
} catch(e) {
	/* 何もしない */
}
//--------------------------------------------------------------
// メイン関数
//--------------------------------------------------------------
function main(args) {
	//----------------------------------------------------------
	// ヘルプメッセージ
	//----------------------------------------------------------
	if(args.Count < 2) {
		WScript.Echo("二つの数値を二回ずつ用い，四則演算によって得られる数値を求めます。");
		WScript.Echo("");
		WScript.Echo("GAME24(.JS) [数値(1)] [数値(2)]");
		return false;
	}
	//----------------------------------------------------------
	// 数値の読み込み
	//----------------------------------------------------------
	var	p = parseInt(args(0));
	var	q = parseInt(args(1));
	//----------------------------------------------------------
	// 数式の組み合わせ（逆ポーランド記法）
	//----------------------------------------------------------
	var	eq = [
		"A B C D z y x",
		"A B C y D z x",
		"A B x C D z y",
		"A B x C y D z",
		"A B C y x D z"
	];
	//----------------------------------------------------------
	// 数式を計算する
	//----------------------------------------------------------
	var	calc = function(s, a, b, c, d) {
		s = s.replace("A", a);
		s = s.replace("B", b);
		s = s.replace("C", c);
		s = s.replace("D", d);
		var	v = eval_rpn(s);
		return { val:v, eq:s };
	};
	//----------------------------------------------------------
	// 数式の組み合わせパターンを網羅する
	//----------------------------------------------------------
	var	op = ["+", "-", "*", "/"];
	var	list = [];
	for(var h = 0; h < eq.length; h++) {
		for(var i = 0; i < op.length; i++) {
			for(var j = 0; j < op.length; j++) {
				for(var k = 0; k < op.length; k++) {
					var	s = eq[h];
					s = s.replace("x", op[i]);
					s = s.replace("y", op[j]);
					s = s.replace("z", op[k]);
					if(p == q) {
						list.push(calc(s, p, p, p, p));
					} else {
						list.push(calc(s, p, p, q, q));
						list.push(calc(s, p, q, p, q));
						list.push(calc(s, p, q, q, p));
						list.push(calc(s, q, p, p, q));
						list.push(calc(s, q, p, q, p));
						list.push(calc(s, q, q, p, p));
					}
				}
			}
		}
	}
	//----------------------------------------------------------
	// 計算結果を出力する
	//----------------------------------------------------------
	for(var i = 0; i < list.length; i++)
		WScript.Echo([list[i].val, list[i].eq].join("\t"));
	return true;
}
//--------------------------------------------------------------
// 逆ポーランド記法の計算　※返値は文字列である
//--------------------------------------------------------------
function eval_rpn(s) {
	var	a = s.split(" ");
	var	n, x, y, z;
	var	ret = [];
	for(var i = 0; i < a.length; i++) {
		var	s = a[i];
		/*--*/ if(s == "+") {
			y = ret.pop(); x = ret.pop(); z = x.add(y); ret.push(z);
		} else if(s == "-") {
			y = ret.pop(); x = ret.pop(); z = x.sub(y); ret.push(z);
		} else if(s == "*") {
			y = ret.pop(); x = ret.pop(); z = x.mul(y); ret.push(z);
		} else if(s == "/") {
			y = ret.pop(); x = ret.pop(); z = x.div(y); ret.push(z);
		} else {
			n = parseInt(s); z = new Fraction(n, 1);    ret.push(z);
		}
	}
	return ret.pop().toString();
}
//--------------------------------------------------------------
// 分数クラス
//--------------------------------------------------------------
function Fraction(num, den) {
	//----------------------------------------------------------
	// コンストラクタ（約分）
	//----------------------------------------------------------
	if(den == 0) {
		/**/ if(num > 0) num =  1;
		else if(num < 0) num = -1;
	} else if(num == 0) {
		den = 1;
	} else {
		var	neg = false;
		if(num < 0) {
			num = -num;
			neg = true;
		}
		for(var q = 2; q <= den; q++) {
			while(num % q == 0 && den % q == 0) {
				num /= q;
				den /= q;
			}
		}
		if(neg) num = -num;
	}
	this.num = num;
	this.den = den;
	//----------------------------------------------------------
	// 加算
	//----------------------------------------------------------
	this.add = function(x) {
		var	n = this.num * x.den + x.num * this.den;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 減算
	//----------------------------------------------------------
	this.sub = function(x) {
		var	n = this.num * x.den - x.num * this.den;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 乗算
	//----------------------------------------------------------
	this.mul = function(x) {
		var	n = this.num * x.num;
		var	d = this.den * x.den;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 除算
	//----------------------------------------------------------
	this.div = function(x) {
		var	n = this.num * x.den;
		var	d = this.den * x.num;
		return new Fraction(n, d);
	};
	//----------------------------------------------------------
	// 文字列変換
	//----------------------------------------------------------
	this.toString = function() {
		if(this.den == 1)
			return this.num.toString();
		else
			return this.num + "/" + this.den;
	};
}
```

</details>

chakra.cmd は Edge の JavaScript エンジンを用いてを高速実行するバッチファイルである。もちろん使わなくても動くが，使ったほうが精神衛生上良いだろう。

<details><summary><font color=blue><b>chakra.cmd の実装コードはコチラ</b></font></summary>

```:chakra.cmd
@echo off
setlocal
if "%1"=="" goto USAGE
rem ----------------------------------------------------------------------------
rem スクリプトファイルの拡張子が省略された場合 .JS とする
rem ----------------------------------------------------------------------------
if "%~x1"=="" (
  set SCRIPTFILE=%~1.JS
) else (
  set SCRIPTFILE=%~1
)
rem ----------------------------------------------------------------------------
rem スクリプトファイルが存在する場合
rem ----------------------------------------------------------------------------
if exist %SCRIPTFILE% (
  set SCRIPTPATH=%SCRIPTFILE%
  goto SKIP
)
rem ----------------------------------------------------------------------------
rem スクリプトファイルをパスから検索する
rem ----------------------------------------------------------------------------
for %%I in ( %SCRIPTFILE% ) do set SCRIPTPATH=%%~$PATH:I
if "%SCRIPTPATH%"=="" (
  echo %SCRIPTFILE% が見つかりません!!
  exit /b
)
:SKIP
rem ----------------------------------------------------------------------------
rem スクリプトファイルのオプション解析
rem ----------------------------------------------------------------------------
set SCRIPTARGS=%SCRIPTPATH%
:LOOP
  if "%~2"=="" goto BREAK
  set SCRIPTARGS=%SCRIPTARGS% %2
  shift /2
goto LOOP
:BREAK
rem ----------------------------------------------------------------------------
rem スクリプトの実行
rem ----------------------------------------------------------------------------
cscript //E:{1B7CD997-E5FF-4932-A7A6-2A9E636DA385} %SCRIPTARGS%
exit  /b
:USAGE
rem ----------------------------------------------------------------------------
rem ヘルプメッセージ
rem ----------------------------------------------------------------------------
echo Microsoft Edge の chakra エンジンを用いて Javascript を高速実行します。
echo.
echo CHAKRA(.CMD) [スクリプトファイル名(.JS)]  [スクリプトオプション] ...
echo.
echo スクリプトファイルの拡張子を省略すると .JS とします。
exit /b
```

</details>

# 5. 実行例

引数を何も指定しないで実行するとヘルプメッセージが表示される。

```:引数なしで実行した場合
chakra game24.js
二つの数値を二回ずつ用い，四則演算によって得られる数値を求めます。

GAME24(.JS) [数値(1)] [数値(2)]
```

## 5.1 レベルⅠの答え

レベルⅠの問題を解かせると下記のようになる。なお `findstr` コマンドの引数の文字列の最後の文字はスペースではなくタブ文字である。コマンドプロンプトからタブ文字をうまく入力できない場合はバッチファイルを作成するなどして対応して頂きたい。

```:レベル1の答え
chakra game24.js 10 4 | findstr /R /C:"^24	"
24	10 10 * 4 - 4 /
```

で，実行すると答えが 24 になる数式が得られる。逆ポーランド記法を解釈すると以下のような数式になる。イヤコレ，1920 通りもあるのに答えは一種類しかないのか・・・

```math
24 = \frac{10 \times 10 - 4 }{4} \tag{5-1}
```

## 5.2 レベルⅡの答え

答えは四種類出てくるが，実質同じである。

```:レベル2の答え
chakra game24.js 7 3 | findstr /R /C:"^24	"
24      7 3 3 7 / + *
24      7 3 7 / 3 + *
24      3 7 / 3 + 7 *
24      3 3 7 / + 7 *
```
逆ポーランド記法を通常の数式に変換すると分かり易い。

```math
\left\{ \begin{aligned}
24 &= 7 \times \left( 3 + \frac{3}{7} \right) \\
24 &= 7 \times \left( \frac{3}{7} + 3 \right) \\
24 &= \left( \frac{3}{7} + 3 \right) \times 7 \\
24 &= \left( 3 + \frac{3}{7} \right) \times 7
\end{aligned} \right. \tag{5-2}
```

## 5.3 レベルⅢの答え

イヤコレ，暗算で解ける人は天才だろうな。

```:レベル3の答え
chakra game24.js 8 3 | findstr /R /C:"^24	"
24	8 3 8 3 / - /
```

答えを見ると啞然とする。掛け算を使わないで，二回の割り算と引き算だけで四個の数字の総和 22 よりも大きな数を作ることが出来てるのだ。この問題のトリックは鮮やかで感動してしまう。

```math
24 =\frac{8}{3 - \displaystyle \frac{8}{3}} \tag{5-3}
```

# 6. まとめ

10 以下の自然数 $p,q$ を二つずつ用いて 24 を作ることの出来るパターン数 $N_{24}(p,q)$ を求めた。ちなみにパターン数をカウントするときは以下のように `find` コマンドを使うとよい。

```:答えが 24 になるパターン数をカウントする方法
chakra game24 8 4 | findstr /R /C:"^24	" | find /C /V ""
54
```

パターン数 $N_{24}(p,q) = N_{24}(q,p)$ であるから $p \le q$ となる範囲のみ示す。なお，小説内で出題された個所を赤色 `#FF0000` で示す。これ以外に 24 を得られるパターンが一つしかない組み合わせを青色 `#0000FF` で示す。

<table>
<caption>表４　24 を作ることの出来るパターン数 $N_{24}(p,q)$</caption>
<tdead>
<tr><th rowspan=2 colspan=2></td>
    <th colspan=10 style="text-align:center">$p$</th></tr>
<tr><th style="text-align:right">&nbsp;&nbsp;1</th>
    <th style="text-align:right">&nbsp;&nbsp;2</th>
    <th style="text-align:right">&nbsp;&nbsp;3</th>
    <th style="text-align:right">&nbsp;&nbsp;4</th>
    <th style="text-align:right">&nbsp;&nbsp;5</th>
    <th style="text-align:right">&nbsp;&nbsp;6</th>
    <th style="text-align:right">&nbsp;&nbsp;7</th>
    <th style="text-align:right">&nbsp;&nbsp;8</th>
    <th style="text-align:right">&nbsp;&nbsp;9</th>
    <th style="text-align:right">10</th></tr>
</tdead>
<tbody>
<tr></tr>
<tr><th rowspan=19>$q$</th>
    <th style="text-align:right">1</th>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">2</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">3</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">16</td>
    <td style="text-align:right">2</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">4</th>
    <td style="text-align:right">12</td>
    <td style="text-align:right">12</td>
    <td style="text-align:right">8</td>
    <td style="text-align:right">6</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">5</th>
    <td style="text-align:right">19</td>
    <td style="text-align:right">13</td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td style="text-align:right">13</td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">6</th>
    <td style="text-align:right">6</td>
    <td style="text-align:right">20</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">11</td>
    <td style="text-align:right">7</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">7</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">8</td>
    <td style="text-align:right"><font color=red><b>4</b></font></td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">36</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">8</th>
    <td style="text-align:right">4</td>
    <td style="text-align:right">20</td>
    <td style="text-align:right"><font color=red><b>1</b></font></td>
    <td style="text-align:right">54</td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td style="text-align:right">8</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">9</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">38</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">10</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">36</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right"><font color=red><b>1</b></font></td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td></tr>
</tbody>
</table>

このうち 24 を作ることの出来るパターンの一例を示す。青色 `#0000FF` は組み合わせが一つしかないが，比較的単純なパターンである。当然のことながら著者の森博嗣氏は敢えて難しいところを選んでいることが分かる。

<table>
<caption>表５　24 を作ることの出来るパターンの一例</caption>
<tdead>
<tr><th rowspan=2 style="text-align:center">$\!q$</th>
    <th colspan=6 style="text-align:center">$\!p$</th></tr>
<tr><th style="text-align:center">$\!1$</th>
    <th style="text-align:center">$\!2$</th>
    <th style="text-align:center">$\!3$</th>
    <th style="text-align:center">$\!4$</th>
    <th style="text-align:center">$\!5$</th>
    <th style="text-align:center">$\!6$</th></tr>
</tdead>
<tbody>
<tr></tr>
<tr><th style="text-align:center">$\!1$</th>
    <td style="text-align:center">$\!-$</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!2$</th>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!-$</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!3$</th>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!2\!\cdot\!2(3\!+\!3)$</td>
    <td style="text-align:center">$\!3\!\cdot\!3\!\cdot\!3\!-\!3$</td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!4$</th>
    <td style="text-align:center">$\!4(4\!+\!1\!+\!1)$</td>
    <td style="text-align:center">$\!2(4\!+\!2\!\cdot\!4)$</td>
    <td style="text-align:center">$\!3\!\cdot\!4\!+\!3\!\cdot\!4$</td>
    <td style="text-align:center">$\!4\!+\!4\!+\!4\!\cdot\!4$</td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!5$</th>
    <td style="text-align:center">$\!(5\!-\!1)(5\!+\!1)$</td>
    <td style="text-align:center">$\!2(2\!+\!5\!+\!5)$</td>
    <td style="text-align:center">$\!\color{blue}{5\!\cdot\!5\!-\!\displaystyle\frac{3}{3}}$</td>
    <td style="text-align:center">$\!4(5\!+\!5\!-\!4)$</td>
    <td style="text-align:center">$\!\color{blue}{5\!\cdot\!5\!-\!\displaystyle \frac{5}{5}}$</td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!6$</th>
    <td style="text-align:center">$\!6(6\!-\!1\!-\!1)$</td>
    <td style="text-align:center">$\!2\!\cdot\!6\!+\!2\!\cdot\!6$</td>
    <td style="text-align:center">$\!3\!\left(\!6\!+\!\displaystyle\frac{6}{3}\!\right)$</td>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!6(5\!+\!5\!-\!6)$</td>
    <td style="text-align:center">$\!\,\,\,6\!+\!6$<br>$\!+\!6\!+\!6$</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!7$</th>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!2(7\!+\!7\!-\!2)$</td>
    <td style="text-align:center">$\!\color{red}{7\!\left(\!3+\!\displaystyle\frac{3}{7}\!\right)}$</td>
    <td style="text-align:center">$\!7\!\left(\!4\!-\!\displaystyle\frac{4}{7}\!\right)$</td>
    <td style="text-align:center">$\!\,\,\,5\!+\!5$<br>$\!+\!7\!+\!7$</td>
    <td style="text-align:center">$\!-$</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!8$</th>
    <td style="text-align:center">$\!8\!+\!8(1\!+\!1)$</td>
    <td style="text-align:center">$\!2\!\cdot\!2\!\cdot\!8\!-\!8$</td>
    <td style="text-align:center">$\!\color{red}{\displaystyle\frac{8}{3\!-\!\displaystyle\frac{8}{3}}}$</td>
    <td style="text-align:center">$\!\,\,\,4\!+\!4$<br>$\!+\!8\!+\!8$</td>
    <td style="text-align:center">$\!\color{blue}{5\!\cdot\!5\!-\!\displaystyle\frac{8}{8}}$</td>
    <td style="text-align:center">$\!\displaystyle\frac{8\!\cdot\!6}{8\!-\!6}$</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!9$</th>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!\,\,\,3\!+\!3$<br>$\!+\!9\!+\!9$</td>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!\color{blue}{5\!\cdot\!5\!-\!\displaystyle\frac{9}{9}}$</td>
    <td style="text-align:center">$\!-$</td></tr>
<tr></tr>
<tr><th style="text-align:center">$\!10$</th>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!\,\,\,2\!+\!2$<br>$\!+\!10\!+\!10$</td>
    <td style="text-align:center">$\!-$</td>
    <td style="text-align:center">$\!\color{red}{\displaystyle\frac{10\!\cdot\!10\!-\!4}{4}}$</td>
    <td style="text-align:center">$\!\color{blue}{5\!\cdot\!5\!-\!\displaystyle\frac{10}{10}}$</td>
    <td style="text-align:center">$\!-$</td></tr>
<tr><th colspan=7></th></tr>
</tbody>
</table>

さて，なぜ「24点」ゲームなのかを考えてみる。10 以下の自然数 $p,q$ を二つずつ用いて作ることが出来る整数と，それらを実現できる $(p,q)$ の組み合わせ数を以下に示す。

ある程度組み合わせ数が多くないとゲームとしては成立しないであろうから「24点」はいい感じの設定である。表４を見て分かるように 24 を作ることのできる $(p,q)$ の組み合わせは 31 通りあり，図２を見ると 24 の前後では極大値になっている。だが，他にも 20 や 30 の組み合わせも多いことに気づく。※約数が多いと組み合わせ数も多くなるようだ。

```plantuml
@startuml
<style>
root {
  margin: 0;
  padding: 0;
}
title {
  fontStyle: normal
  fontSize: 17;
}
</style>
sprite FIGURE <svg width="600" height="380" viewbox="0 0 600 380">
<g fill="gray">
<path d="M65 20  h505 v1 h-505" />
<path d="M65 70  h505 v1 h-505" />
<path d="M65 120  h505 v1 h-505" />
<path d="M65 170 h505 v1 h-505" />
<path d="M65 220 h505 v1 h-505" />
<path d="M65 270 h505 v1 h-505" />
<path d="M65 320 h505 v1 h-505" />
<path d="M70  325 v-305 h1 v305" />
<path d="M120 325 v-305 h1 v305" />
<path d="M170 325 v-305 h1 v305" />
<path d="M220 325 v-305 h1 v305" />
<path d="M270 325 v-305 h1 v305" />
<path d="M320 325 v-305 h1 v305" />
<path d="M370 325 v-305 h1 v305" />
<path d="M420 325 v-305 h1 v305" />
<path d="M470 325 v-305 h1 v305" />
<path d="M520 325 v-305 h1 v305" />
<path d="M570 325 v-305 h1 v305" />
</g>
<text x="65"  y="340" fill="black" font-size="16">0</text>
<text x="115" y="340" fill="black" font-size="16">5</text>
<text x="160" y="340" fill="black" font-size="16">10</text>
<text x="210" y="340" fill="black" font-size="16">15</text>
<text x="260" y="340" fill="black" font-size="16">20</text>
<text x="310" y="340" fill="black" font-size="16">25</text>
<text x="360" y="340" fill="black" font-size="16">30</text>
<text x="410" y="340" fill="black" font-size="16">35</text>
<text x="460" y="340" fill="black" font-size="16">40</text>
<text x="510" y="340" fill="black" font-size="16">45</text>
<text x="560" y="340" fill="black" font-size="16">50</text>
<text x="55"  y="326" fill="black" font-size="16">0</text>
<text x="42"  y="276" fill="black" font-size="16">10</text>
<text x="42"  y="226" fill="black" font-size="16">20</text>
<text x="42"  y="176" fill="black" font-size="16">30</text>
<text x="42"  y="126" fill="black" font-size="16">40</text>
<text x="42"  y="76"  fill="black" font-size="16">50</text>
<text x="42"  y="26"  fill="black" font-size="16">60</text>
<text x="245" y="360" fill="black" font-size="16">四則演算で求める数</text>
<text x="15"  y="90"  fill="black" font-size="16">実</text>
<text x="15"  y="107" fill="black" font-size="16">現</text>
<text x="15"  y="124" fill="black" font-size="16">可</text>
<text x="15"  y="141" fill="black" font-size="16">能</text>
<text x="15"  y="158" fill="black" font-size="16">な</text>
<text x="15"  y="175" fill="black" font-size="16">組</text>
<text x="15"  y="192" fill="black" font-size="16">み</text>
<text x="15"  y="209" fill="black" font-size="16">合</text>
<text x="15"  y="226" fill="black" font-size="16">わ</text>
<text x="15"  y="243" fill="black" font-size="16">せ</text>
<text x="15"  y="260" fill="black" font-size="16">数</text>
<g fill="pink">
<path d="M68  320 v-275 h5 v275" />
<path d="M78  320 v-275 h5 v275" />
<path d="M88  320 v-275 h5 v275" />
<path d="M98  320 v-200 h5 v200" />
<path d="M108 320 v-195 h5 v195" />
<path d="M118 320 v-210 h5 v210" />
<path d="M128 320 v-210 h4 v210" />
<path d="M138 320 v-220 h5 v220" />
<path d="M148 320 v-225 h5 v225" />
<path d="M158 320 v-235 h5 v235" />
<path d="M168 320 v-215 h5 v215" />
<path d="M178 320 v-185 h5 v185" />
<path d="M188 320 v-190 h5 v190" />
<path d="M198 320 v-160 h5 v160" />
<path d="M208 320 v-135 h5 v135" />
<path d="M218 320 v-200 h5 v200" />
<path d="M228 320 v-175 h5 v175" />
<path d="M238 320 v-185 h5 v185" />
<path d="M248 320 v-140 h5 v140" />
<path d="M258 320 v-165 h5 v165" />
<path d="M278 320 v-130 h5 v130" />
<path d="M288 320 v-75  h5 v75" />
<path d="M298 320 v-60  h5 v60" />
<path d="M318 320 v-110 h5 v110" />
<path d="M328 320 v-110 h5 v110" />
<path d="M338 320 v-65  h5 v65" />
<path d="M348 320 v-90  h5 v90" />
<path d="M358 320 v-75  h5 v75" />
<path d="M378 320 v-75  h5 v75" />
<path d="M388 320 v-100 h5 v100" />
<path d="M398 320 v-75  h5 v75" />
<path d="M408 320 v-70  h5 v70" />
<path d="M418 320 v-115 h5 v115" />
<path d="M428 320 v-140 h5 v140" />
<path d="M438 320 v-100 h5 v100" />
<path d="M448 320 v-20  h5 v20" />
<path d="M458 320 v-50  h5 v50" />
<path d="M468 320 v-115 h5 v115" />
<path d="M478 320 v-55  h5 v55" />
<path d="M488 320 v-100 h5 v100" />
<path d="M498 320 v-50  h5 v50" />
<path d="M508 320 v-35  h5 v35" />
<path d="M518 320 v-80  h5 v80" />
<path d="M528 320 v-45  h5 v45" />
<path d="M538 320 v-15  h5 v15" />
<path d="M548 320 v-140 h5 v140" />
<path d="M558 320 v-105 h5 v105" />
<path d="M568 320 v-115 h5 v115" />
</g>
<g fill="red">
<path d="M268 320 v-175 h5 v175" />
<path d="M308 320 v-155 h5 v155" />
<path d="M368 320 v-160 h5 v160" />
</g>
<text x="260" y="140" fill="red" font-size="16">35</text>
<text x="300" y="160" fill="red" font-size="16">31</text>
<text x="360" y="155" fill="red" font-size="16">32</text>
</svg>
title
<$FIGURE>
図２　四則演算で求める数と実現可能な組み合わせの数
end title
@enduml
```

しかし 20 を作ることのできる組み合わせ 35 のうち，パターン数が一つしかないものは存在しない。また，パターン数が二つしかないもの $(p,q)=\lbrace(5,6),\ (5,7),\ (5,8),\ (5,9)\rbrace$ も決して難しくはないだろう。

```math
\left\{ \begin{aligned}
5 \times \left(5 - \frac{6}{6}\right) &= 20 \\
5 \times \left(5 - \frac{7}{7}\right) &= 20 \\
5 \times \left(5 - \frac{8}{8}\right) &= 20 \\
5 \times \left(5 - \frac{9}{9}\right) &= 20
\end{aligned} \right. \tag{6-1}
```

<table>
<caption>表５　20 を作ることの出来るパターン数 $N_{20}(p,q)$</caption>
<tdead>
<tr><th rowspan=2 colspan=2></td>
    <th colspan=10 style="text-align:center">$p$</th></tr>
<tr><th style="text-align:right">&nbsp;&nbsp;1</th>
    <th style="text-align:right">&nbsp;&nbsp;2</th>
    <th style="text-align:right">&nbsp;&nbsp;3</th>
    <th style="text-align:right">&nbsp;&nbsp;4</th>
    <th style="text-align:right">&nbsp;&nbsp;5</th>
    <th style="text-align:right">&nbsp;&nbsp;6</th>
    <th style="text-align:right">&nbsp;&nbsp;7</th>
    <th style="text-align:right">&nbsp;&nbsp;8</th>
    <th style="text-align:right">&nbsp;&nbsp;9</th>
    <th style="text-align:right">10</th></tr>
</tdead>
<tbody>
<tr></tr>
<tr><th rowspan=19>$q$</th>
    <th style="text-align:right">1</th>
    <td style="text-align:right">0</th>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">2</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">3</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">12</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">4</th>
    <td style="text-align:right">60</td>
    <td style="text-align:right">40</td>
    <td style="text-align:right">8</td>
    <td style="text-align:right">4</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">5</th>
    <td style="text-align:right">32</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">8</td>
    <td style="text-align:right">26</td>
    <td style="text-align:right">7</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">6</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">40</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">41</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">7</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">30</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">8</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">46</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">20</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">8</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">9</th>
    <td style="text-align:right">30</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">10</th>
    <td style="text-align:right">120</td>
    <td style="text-align:right">73</td>
    <td style="text-align:right">71</td>
    <td style="text-align:right">77</td>
    <td style="text-align:right">71</td>
    <td style="text-align:right">77</td>
    <td style="text-align:right">69</td>
    <td style="text-align:right">69</td>
    <td style="text-align:right">69</td>
    <td style="text-align:right">31</td></tr>
</tbody>
</table>

同様に 30 を作ることのできる組み合わせ 32 のうち，パターン数が一つしかないものは僅か一つのみ $(p,q) = (3,10)$ である。10, 10, 3, 3 で 30 を作るのは難しいが，本記事を読破した方なら分かるであろう。

```math
\frac{10}{\displaystyle \frac{10}{3} - 3} = 30 \tag{6-2}
```

ちなみに足し算と掛け算は交換法則が成り立つので順番を入れ替えただけのパターンが存在するため，足し算と掛け算のみから成るものはパターン数が多くなる。逆に引き算と割り算は交換法則が成り立たないのでパターン数が少ないものは引き算と割り算を使っている。

<table>
<caption>表６　30 を作ることの出来るパターン数 $N_{30}(p,q)$</caption>
<tdead>
<tr><th rowspan=2 colspan=2></td>
    <th colspan=10 style="text-align:center">$p$</th></tr>
<tr><th style="text-align:right">&nbsp;&nbsp;1</th>
    <th style="text-align:right">&nbsp;&nbsp;2</th>
    <th style="text-align:right">&nbsp;&nbsp;3</th>
    <th style="text-align:right">&nbsp;&nbsp;4</th>
    <th style="text-align:right">&nbsp;&nbsp;5</th>
    <th style="text-align:right">&nbsp;&nbsp;6</th>
    <th style="text-align:right">&nbsp;&nbsp;7</th>
    <th style="text-align:right">&nbsp;&nbsp;8</th>
    <th style="text-align:right">&nbsp;&nbsp;9</th>
    <th style="text-align:right">10</th></tr>
</tdead>
<tbody>
<tr></tr>
<tr><th rowspan=19>$q$</th>
    <th style="text-align:right">1</th>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">2</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">3</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">24</td>
    <td style="text-align:right">4</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">4</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">5</th>
    <td style="text-align:right">60</td>
    <td style="text-align:right">24</td>
    <td style="text-align:right">24</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">4</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">6</th>
    <td style="text-align:right">30</td>
    <td style="text-align:right">22</td>
    <td style="text-align:right">10</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">26</td>
    <td style="text-align:right">2</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">7</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">8</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">6</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">30</td>
    <td style="text-align:right">0</td>
    <td></td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">9</th>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">16</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">4</td>
    <td style="text-align:right">32</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td></td></tr>
<tr></tr>
<tr><th style="text-align:right">10</th>
    <td style="text-align:right">4</td>
    <td style="text-align:right">14</td>
    <td style="text-align:right"><font color=blue><b>1</b></font></td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">52</td>
    <td style="text-align:right">2</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td>
    <td style="text-align:right">0</td></tr>
</tbody>
</table>

ということで 24 点ゲームは 24 を作ることができる組み合わせ自体は多いが，その中に高難度のものが含まれるという点で絶妙な設定だと思われる。「笑わない数学者」でのルールは，二つの数字を二回ずつ用いるという亜流バージョンではあるが，おそらくオリジナルの 24 点ゲームも同様の傾向ではないかと思われる。

# 7. 参考文献
- [森博嗣，笑わない数学者 MATHEMATICAL GOODBYE，1996年](https://bookclub.kodansha.co.jp/product?item=0000158149)
  ※自分が持っているのは2011年発行の第36刷（文庫版）である
- [中国で人気のある算数ゲーム「24点」の紹介，神戸大学経済研究所，2021年 <img width=16 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490655/66e66c9d-a6f3-f215-951a-9d79cc94a9d6.png">](https://www.rieb.kobe-u.ac.jp/research/publication/newsletter/column_back-issues/file/column221.pdf)
- [javascriptで分数クラス - Qiita](https://qiita.com/tkturbo/items/a14310750813a181b6ea)
- [【C++】分数クラスのすすめ＋無限大への拡張【競プロ】- Qiita](https://qiita.com/gandalfr-KY/items/b0eed6727e873a313455)
- [C++で分数class - Qiita](https://qiita.com/HitsujiRere/items/43a4b53c64b8eec3b7bd)
- [逆ポーランド記法を利用した数式の計算(1) 逆ポーランド記法の計算 - Qiita](https://qiita.com/gushwell/items/a40f4119a35a1e6d7622)
- [逆ポーランド記法とスタック - Qiita](https://qiita.com/zak74702675/items/b2b22765c558f34eef5a)
- [スタック&逆ポーランド記法 - Qiita](https://qiita.com/miaomiao/items/4de2b896007095070ad0)
- [Javascriptで逆ポーランド記法の式生成と計算 - Qiita](https://qiita.com/spica/items/6babc851c8d02a5cec7d)
- [JavaScriptでなんちゃって演算子オーバーロード---四則演算子 - Qiita](https://qiita.com/I-Yasusi/items/ad0f174e8d5f14d598b9)