B:(2,3,1),A:(2,1,1), B:(0,1,1),A:(0,0,1), B:(0,0,0)でBの勝ちです.
([数学ソフトタッチ」から)0 0 1 0 + 0 1 1 0 ------------ 1 0 0 0
0 0 1 0 ^ 0 1 1 0 ------------ ? ? ? ?
| A | B | A^B |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
5: 1 0 1 4: 1 0 0 1: 0 0 1 --------------- 0 0 0
x = a[0] ^ a[1] ^ a[2]x == 0 のとき必勝形です。
a[i] ^ x a[0] = (1,0,1) (1,1,0) a[1] = (0,1,1) > (1,0,1) a[2] = (1,0,0) (1,1,0) x = (0,1,0)
/***********************************************************
nim.c -- 三山くずし
***********************************************************/
#include <stdio.h>
#include <stdlib.h>
//奥村著:アルゴリズム辞典より
void main()
{
int a[4], i, j, imax, max, n, r, x, my_turn;
for (i = 1; i <= 3; i++) {
printf("%d 番の山の石の数? ", i); scanf("%d", &a[i]);
if (a[i] <= 0) return EXIT_FAILURE;
}
for (my_turn = 1; 1; my_turn ^= 1) {
max = 0;
for (i = 1; i <= 3; i++) {
printf(" %d ", i);
for (j = 1; j <= a[i]; j++) printf("*");
printf("\n");
if (a[i] > max) {//maxは最大値
max = a[i]; imax = i;
}
}
if (max == 0) break;//繰り返し終了
if (my_turn) {
printf("私の番です.\n");
x = a[1] ^ a[2] ^ a[3]; /* 排他的論理和 */
j = 0;
for (i = 1; i <= 3; i++)
if (a[i] > (a[i] ^ x)) j = i;//jから石を取る
if (j != 0) a[j] ^= x;
else a[imax]--;//必勝形になっている場合
}
else {//相手の番
do {
printf("何番の山からとりますか? ");
r = scanf("%d", &i); // rは読んだ文字数
} while (r != 1 || i < 1 || i > 3 || a[i] == 0);
do {
printf("何個とりますか? ");
r = scanf("%d", &n);
} while (r != 1 || n <= 0 || n > a[i]);
a[i] -= n;
}
}
if (my_turn) printf("あなたの勝ちです!\n");
else printf("私の勝ちです!\n");
}
1 番の山の石の数? 5 2 番の山の石の数? 3 3 番の山の石の数? 2 1 ***** 2 *** 3 ** 私の番です. 1 * 2 *** 3 ** 何番の山からとりますか? 2 何個とりますか? 2 1 * 2 * 3 ** 私の番です. 1 * 2 * 3 何番の山からとりますか? 1 何個とりますか? 1 1 2 * 3 私の番です. 1 2 3 私の勝ちです!