/********************************************************************* * C MAGAZINE 2001 4 電脳クラブ(121回) 隣差魔方陣 * * * * Vid Forn ( vid@geocities.co.jp ) * ********************************************************************/ /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* インクルードファイル *********************************************/ #include #include /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* マクロ ***********************************************************/ /* マスの位置 * A B C * D E F * G H I * と置く。 * 一次元配列に数値はセットするため、その添字 */ #define A 0 #define B 1 #define C 2 #define D 3 #define E 4 #define F 5 #define G 6 #define H 7 #define I 8 /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 隣差を計算する */ #define nsub(n,m) abs(mbox[n]-mbox[m]) /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 関数の戻り値 成功/失敗 */ #define SUCCEED 0 #define FAILE -1 /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 魔方陣の値,隣差の値を入れる時の変数 */ /* #define MAGIC unsigned char /* */ #define MAGIC int /* */ /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 数値の大小のチェックのため */ #define ifbig( a , b ) (((a)>(b))?1:(((b)>(a))?-1:0)) /* 参照が二回起るため、インクリメント/デクリメントの * 副作用に注意。よーするに使えない。 */ /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* フラグが上がっているかどうかを調べる */ #define USE(n) ( chkflg&(0x01<<(n)) ) /* 0: 上がっていない / not 0 フラグは上がっている */ #ifdef NDEBUG /* フラグ操作(マクロ) */ #define check(n) ( chkflg |= ( 0x01 << (n) ) ) #define uncheck(n) ( chkflg &= (~( 0x01<<(n))) ) #endif /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 答え表示用(デバグ時以外は出力しない) */ #ifdef NDEBUG #define printans() ; #endif /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 数値候補が 4 つある場合の計算 */ #define fourcheck(v,w,x,y,z) \ if( (v=mbox[(w)]+(x))==(mbox[(y)]+(z)) ){}else \ if( (v=mbox[(w)]+(x))==(mbox[(y)]+(z)) ){}else \ if( (v=mbox[(w)]+(x))==(mbox[(y)]+(z)) ){}else \ if( (v=mbox[(w)]+(x))==(mbox[(y)]+(z)) ){}else \ { continue; }; \ if( i < 1 ){ continue; } /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* for LOOP の中の条件 */ #define LOOP(n) for( n = 1 ; n <= 12 ; n++ ){ UseCheck(n); #define LOOPEND } #define LOOP2(n,m) for(n=1;n<=12;n++){ UseCheck(n);\ for(m=1;m<=12;m++){ UseCheck(m); #define LOOP2END }} /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* USE チェック→ for 繰り返し */ #define UseCheck(n) if( USE(n) ){ continue; } /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* sign による数値の上下 */ #define SIGNLOOP {int sign;\ for( sign = -1 ; sign <= 1 ; sign += 2 ){ #define SIGNLOOPEND }} /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* 関数宣言 *********************************************************/ int main( int argc , char *argv[] ); /* メイン関数 */ int clear(); /* セットされた魔方陣の数値のクリア */ #ifndef NDEBUG /* フラグ操作(関数) */ int check( int num ); /* 隣差として使用した値のチェック */ int uncheck( int num ); /* 同、チェックを外す */ #endif int calc1(); /* 計算1 A=1 の時 */ int calc1_sub1(); /* 計算1の時のインデント対策 */ int calc2(); /* 計算2 B=1 の時 */ int calc3(); /* 計算3 E=1 の時 */ #ifndef NDEBUG int printans(); /* 答えの表示 */ #endif /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* グローバル変数 ***************************************************/ MAGIC mbox[9]; /* 魔方陣 */ unsigned short int chkflg; /* 使用された隣差のチェックフラグ */ char *message[] = { "Pattern 1 ( A=1 / AB < AD )\n", "Pattern 2 ( B=1 / AB < BC )\n", "Pattern 3 ( E=1 / BE < EH / BE < DE < EF )\n", "Answer: %d\n", }; enum message_num { PAT1 = 0 , PAT2 , PAT3 , ANSWER }; /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* 関数 *************************************************************/ /* main +---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ int main( int argc , char *argv[] ) { int ans; /* 答えの数 */ /* 初期化 */ ans = 0; chkflg = 0; /* 計算1 A=1 */ ans = calc1(); printf( "%d\n" , chkflg ); /* 計算2 B=1 */ ans += calc2(); printf( "%d\n" , chkflg ); /* 計算3 E=1 */ ans += calc3(); printf( "%d\n" , chkflg ); /* 答えの数の表示 */ printf( message[ANSWER] , ans ); return SUCCEED; } #ifndef NDEBUG /* printans +---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* 答えを表示する */ int printans() { static int count = 0; static unsigned char hash[6]; count++; printf("\n>>%d\n" " %2d [%2d] %2d [%2d] %2d\n" "[%2d] [%2d] [%2d]\n" " %2d [%2d] %2d [%2d] %2d\n" "[%2d] [%2d] [%2d]\n" " %2d [%2d] %2d [%2d] %2d\n" , count , mbox[A] , nsub(A,B), mbox[B] , nsub(B,C) , mbox[C], nsub(A,D) , nsub(B,E) ,nsub(C,F), mbox[D] , nsub(D,E), mbox[E] , nsub(E,F) , mbox[F], nsub(D,G) , nsub(E,H) , nsub(F,I), mbox[G] , nsub(G,H), mbox[H] , nsub(H,I) , mbox[I] ); hash[0] = (( nsub(A,B) & 0x0F )<< 4) | ( nsub(B,C) & 0x0F ); hash[1] = (( nsub(D,E) & 0x0F )<< 4) | ( nsub(E,F) & 0x0F ); hash[2] = (( nsub(G,H) & 0x0F )<< 4) | ( nsub(H,I) & 0x0F ); hash[3] = (( nsub(A,D) & 0x0F )<< 4) | ( nsub(D,G) & 0x0F ); hash[4] = (( nsub(B,E) & 0x0F )<< 4) | ( nsub(E,H) & 0x0F ); hash[5] = (( nsub(C,F) & 0x0F )<< 4) | ( nsub(F,I) & 0x0F ); printf(":%02X%02X%02X%02X%02X%02X\n", hash[0] , hash[1] , hash[2] , hash[3] , hash[4] , hash[5] ); return SUCCEED; } #endif #ifndef NDEBUG /* check +---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* フラグチェック */ /* 戻り値 * SUCCEED 成功(値はチェックされる) * FAILE 失敗(値はチェックされている=使用されている) */ /* FAILE の場合、フラグ操作は行われない */ int check( int num ) { if( (chkflg&(0x01< ab /*条件2*/; ad-- ){ mbox[D] = 1 /*mbox[A]*/ + ad; check( ad ); /* E の決定 */ LOOP2(be,de){ /* E 決定時の時には4つのパターンが考えられる */ /* (+be,+de) , (+be,-de) , (-be,+de) , (-be,-de) */ /* これらのどれかで E が成立した場合、他の組み合わせは 成り立たない */ fourcheck( i , B , be , D , de ); /* */ /* ここに来た時点で E が成立している */ /* E の候補値は i に代入されている */ /* 成立した場合は次の計算に移るのだが、 * インデントが深く&関数が長くなったので次の関数へ移す */ mbox[E] = i; check(be); check(de); ans += calc1_sub1( i , be , de ); uncheck(be); uncheck(de); }LOOP2END/* END LOOP: be,de */ uncheck( ad ); } /* END for : ad = 12 ; ad > ab ; ad-- */ uncheck( ab ); /* 使用した値の解放 */ } /* End for : ab = 1 ; ab < ad ; ab++ */ return ans; } /* calc1_sub +---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* インデントが深くなったために関数分割 */ int calc1_sub1() { MAGIC cf , bc , dg , ef , eh , fi , gh , hi; int ans = 0 , i; /* ABDE が決定されている/回転・鏡像解は既に考慮済み */ /* F の決定 */ LOOP(ef){ check( ef ); SIGNLOOP; mbox[F] = mbox[E] + (ef*sign); /* C の決定 */ LOOP2(bc,cf){ fourcheck( i , B , bc , F , cf ); mbox[C] = i; check(bc); check(cf); /* H の決定 */ LOOP(eh){ check(eh); SIGNLOOP; mbox[H] = mbox[E] + (eh*sign); /* G の決定 */ LOOP2(dg,gh){ fourcheck( i , D , dg , H , gh ); mbox[G] = i; check(dg); check(gh); /* I の決定 */ LOOP2(fi,hi){ fourcheck( i , F , fi , H , hi ); mbox[I] = i; printans(); ans++; /* 答えが求まった */ /* ……結局インデントが深いのは気にしたら負けかも */ }LOOP2END; /* END LOOP : fi , hi */ uncheck(dg); uncheck(gh); }LOOP2END; /* END LOOP: dg,gh */ SIGNLOOPEND; uncheck(eh); }LOOPEND;/* END LOOP: eh */ uncheck(cf); uncheck(bc); }LOOP2END; /* END LOOP : bc,cf */ SIGNLOOPEND; uncheck( ef ); }LOOPEND; /* END LOOP : ef */ return ans; } /* calc2 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* パターン2/条件 B = 1 : AB < BC */ int calc2() { int ans = 0 ; /* 答えの数 */ /* 条件表示など */ printf( "%s" , message[PAT2] ); return ans; } /* calc3 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /* パターン3/条件 E = 1 : BE < EH : BE < DE < EF */ int calc3() { int ans = 0; /* 答えの数 */ /* 条件表示など */ printf( "%s" , message[PAT3] ); return ans; } /*+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+*/ /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /********************************************************************/ /********************************************************************/ /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* メモ ************************************************************** * マスの位置 * A B C * D E F * G H I * 1:数値の1を絶対に使用すること。 * 2:回転・鏡像解の排除 * この2点より、計算は * 1) A = 1 : AB < AD * 2) B = 1 : AB < BC * 3) E = 1 : BE < EH : BE < DE < EF * 三種類を計算し、この合計が答えになると考えられる。 * 計算の順番 * 求める箱の順番 () の中は隣差として決定する値 * 一意に決められない場合はそこで計算を一つ前に戻す * 計算の順番は何通りも考えられるが、私はこの順番とした * 1) A * (AB)B * (AD)D * (BE:DE)E * (EF)F * (BC:CF)C * (EH)H * (DG:GH)G * (FI:HI)I * 2) B * (BE)E * (AB)A * (AD:DE)D * (BC)C * (CF:EF)F * (EH)H * (DG:GH)G * (FI:HI)I * 3) E * (BE)B * (AB)A * (AD:DE)D * (EF)F * (BC:CF)C * (EH)H * (DG:GH)G * (FI:HI)I ********************************************************************/ /********************************************************************/ /* Copyright (c) Vid Forn / FUKUMORI Akihiro , 2001 */ /********************************************************************/ /* EOF **************************************************************/