(2007.1.5)最初に作ったプログラムは「1,4」と「3,6」のパターンを見逃していた(出力中のの赤い「Find」の部分)。原因はソース中の赤い部分。恥ずかしい。
プログラムの実行結果は以下の通り。行頭にFindが付いているのが正解の黒白パターン。
0 0 ...... 1 1 1..... 1 2 .2.... Find 2 3 12.... 1 4 ..3... Find 2 5 1.3... Find 2 6 .23... 3 7 123... 1 8 ...4.. Find 2 9 1..4.. Find 2 a .2.4.. 3 b 12.4.. 2 c ..34.. 3 d 1.34.. 3 e .234.. Find 4 f 1234.. 1 10 ....5. Find 2 11 1...5. 2 12 .2..5. 3 13 12..5. Find 2 14 ..3.5. 3 15 1.3.5. 3 16 .23.5. Find 4 17 123.5. Find 2 18 ...45. 3 19 1..45. 3 1a .2.45. Find 4 1b 12.45. 3 1c ..345. Find 4 1d 1.345. 4 1e .2345. 5 1f 12345. 1 20 .....6 2 21 1....6 Find 2 22 .2...6 3 23 12...6 Find 2 24 ..3..6 3 25 1.3..6 3 26 .23..6 Find 4 27 123..6 Find 2 28 ...4.6 3 29 1..4.6 3 2a .2.4.6 Find 4 2b 12.4.6 3 2c ..34.6 4 2d 1.34.6 Find 4 2e .234.6 5 2f 1234.6 Find 2 30 ....56 3 31 1...56 3 32 .2..56 4 33 12..56 3 34 ..3.56 Find 4 35 1.3.56 Find 4 36 .23.56 5 37 123.56 3 38 ...456 Find 4 39 1..456 Find 4 3a .2.456 5 3b 12.456 Find 4 3c ..3456 5 3d 1.3456 5 3e .23456 6 3f 123456
上から順に見ていくと以下のように「隣り合う2面が黒の場合と,それを白黒反転した場合」であることがわかる。
「向かい合う2面」の場合は駄目なので,答えには「隣り合う2面」と書かなければならない。
サイコロを振ったとき出る目のパターンとしては以下の3通り。
プログラムのソースは以下の通り。
#include "puzutl.h" const ulong bit0 = 0x00000001; const ulong bit1 = 0x00000002; const ulong bit2 = 0x00000004; const ulong bit3 = 0x00000008; const ulong bit4 = 0x00000010; const ulong bit5 = 0x00000020; const ulong bit6 = 0x00000040; const ulong bit7 = 0x00000080; const ulong bit8 = 0x00000100; int num[0x3F+1]; // int getbit( int val, int bitpos) // 1オリジンでビットを取り出す { int b = 1 << (bitpos-1); // 1オリジンなので-1してからシフトする if( val & b) return 1; // ビットがONか調べる return 0; } int rotate3x3( int val) // 3x3の矩形を左に90度回転する { // 012 258 // 345 ⇒ 147 // 678 036 int newval = 0; if( val&bit0) newval |= bit6; if( val&bit1) newval |= bit3; if( val&bit2) newval |= bit0; if( val&bit3) newval |= bit7; if( val&bit4) newval |= bit4; if( val&bit5) newval |= bit1; if( val&bit6) newval |= bit8; if( val&bit7) newval |= bit5; if( val&bit8) newval |= bit2; return newval; } int min4( int v1, int v2, int v3, int v4) // 4つの数字の最小値を取得する { return min(min(v1,v2),min(v3,v4)); } cstring bitstr( int val) // 黒く塗った部分の数値,白い部分は.を出力する { static char bits[10]; if( val & bit0) bits[0] = '1'; else bits[0] = '.'; if( val & bit1) bits[1] = '2'; else bits[1] = '.'; if( val & bit2) bits[2] = '3'; else bits[2] = '.'; if( val & bit3) bits[3] = '4'; else bits[3] = '.'; if( val & bit4) bits[4] = '5'; else bits[4] = '.'; if( val & bit5) bits[5] = '6'; else bits[5] = '.'; bits[6] = NIL; return bits; } void expand( int val, int face1, int face2, int face3, int face4, int face5) // 上から見た展開図で考える { // face1が上面,それ以外は側面 // それぞれの面の黒/白を取得する int b1 = getbit( val, face1); // 上面の黒白 int b2 = getbit( val, face2); // 側面の黒白(展開図の上) int b3 = getbit( val, face3); // 側面の黒白(展開図の左) int b4 = getbit( val, face4); // 側面の黒白(展開図の下) int b5 = getbit( val, face5); // 側面の黒白(展開図の右) int pattern1 = (b1<<4) | (b2<<1) | (b3<<3) | (b4<<7) | (b5<<5); // これを3x3の矩形内に配置し9ビットの数と見なす int pattern2 = rotate3x3(pattern1); // 「正規化」のために回転して考える(90度) int pattern3 = rotate3x3(pattern2); // 「正規化」のために回転して考える(180度) int pattern4 = rotate3x3(pattern3); // 「正規化」のために回転して考える(270度) int pattern = min4( pattern1, pattern2, pattern3, pattern4); // 回転して一番小さな数をこの展開図の値とする num[pattern]++; // 展開図の値を記憶する } int main( int argc, cstring argv[]) { for( int i=0; i<= 0x3F; i++) { // 6面全てに色を付けてみる for( int k=0; k<= 0x3F; k++) num[k] = 0; // 色付けし直す毎に前の記録を削除する // この色付けでサイコロを振る。1から6の出る確率は1/6で同じ。 expand( i, 1,2,3,5,4); // 1が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する expand( i, 2,3,1,4,6); // 2が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する expand( i, 3,1,2,6,5); // 3が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する expand( i, 4,1,5,6,2); // 4が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する expand( i, 5,1,3,6,4); // 5が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する expand( i, 6,2,4,5,3); // 6が上面に来た場合,それを上からの平面図に展開し正規化した値を記憶する // 正規化した値が3通り出現し同じ回数の場合,iが答えになる int num_value = 0; // 出現した数 int num_cnt = 0; // 出現した回数 YesNo ynFind = YES; // 解が見つかった? for( k=0; k<= 0x3F; k++) { // 正規化した数字を調べる if( num[k] != 0) { // 正規化した数がある num_value++; // 出現回数を勘定する if( num_cnt == 0) num_cnt = num[k]; // 出現した数 else if( num_cnt != num[k]) { // 違う数が出現した,出現する確率が違うってこと ynFind = NO; } } } if( num_value != 3) { // 出現した数字は3種類? ynFind = NO; // 3種類でない場合ジャンケンには使えない } if( ynFind) { ps( "Find %d %2x %s\n", bitcount(i), i, bitstr(i)); } else { ps( " %d %2x %s\n", bitcount(i), i, bitstr(i)); } } return 0; }