/******************************************************************************  i-mode の「キティ&サンリオオマケアリ」(http://kk.sanrio-i.com) に 2010 年 十一月ごろ出た、きせかえツール「キティ盛りガール」のおまけゲームと同等のゲーム です。 乱数の種は 1288673722 です. ○ ○ ○ ○ 1 2 3 4 ● ○ ● ● 5 6 7 8 ○ ● ○ ● 9 10 11 12 ○ ● ○ ○ 13 14 15 16 1 から 16 までの数を入力してください. のように表示されます。1 から 16 までの数を入力すると、その数に対応するマスを 通る斜め±45°の線上のコマがすべて反転されます。全てを「◯」にするか、全てを 「●」にするかすればクリアです。 解ける問題だけが出題されます。必勝法、解けるための初期配置の条件は、各自で 考えてみてください。それほどむずかしくはありません。 できる限り、授業で教えた範囲のC言語の知識でわかるように書きましたが、関数 move() では、見やすさ、わかりやすさを考慮し、まだ教えていない書き方をして います。それは、for の小カッコの中の、第一の初期設定、第三の再初期化で複数の 代入などを行わせたい場合、カンマ「,」で区切って書けばよい、ということです。 for (i = ii, j = jj; i > 0 && j > 0; i--, j--) { ^^^^^^^^^^^^^^ ^^^^^^^^ 初期設定 再初期化 簡単にできる改造について: 1. 研究のため、全てが「○」の状態から始めるには、初期化後の「ランダムに選んで 手を打つ」を実行しないようにし、main() の中の三つめの for ループの継続条件を 空白にします。(止めたいときは Ctrl+C を押してください。) 2. 初めのほうで #define されている N の値を変えれば盤の大きさが N × N に 変わります。 3. このゲームは、 ○ ・ ○ ・ ・ ○ ・ ○ ・ ○ ・ ○ と ○ ・ ○ ・ の上の二つのゲームを同時にやっているに ○ ・ ○ ・ ・ ○ ・ ○ ・ ○ ・ ○ ○ ・ ○ ・ すぎません。片方だけを、あるいは両者を別々に表示させることもできます。考えて みてください。 ******************************************************************************/ #include #include #include #define N 4 /* これを変えれば盤の大きさが変わる */ #define YES 1 #define NO 0 int a[1+N*N]; /* 盤面。使うのは a[1] ... a[N*N] */ void show(void); void move(int n); void reverse(int n); int check(void); main() { int n, end; /* end はクリアしたかどうかを示す変数 */ { /* この中カッコの中(乱数の種の設定)はわからなくてもよい */ unsigned seed = (unsigned)time(NULL); /* 現在時刻を取得して */ printf("乱数の種は %u です.\n", seed); srand(seed); /* それを乱数の種に */ } for (n = 1; n <= N*N; n++) { /* 配列は 0 で初期化 */ a[n] = 0; } for (n = 0; n < 8*N*N; n++) { /* ランダムに選んで */ move(rand() % (N*N) + 1); /* 手を打つ */ } show(); /* 画面表示 */ for (end = NO; end == NO; end = check()) { printf("1 から %d までの数を入力してください. ", N*N); scanf("%d", &n); if (n >= 1 && n <= N*N) { /* 入力が範囲内なら */ move(n); /* 反転し */ printf("\n"); show(); /* 再表示 */ } } printf("おめでとう! クリアです.\n"); } /* 盤面の画面への表示 */ void show(void) { int i, j; for (i = 1; i <= N*N; i++) { if (a[i] == 0) { printf("◯ "); /* この「◯」と「●」を */ } else { /* 別の全角文字に変えれば */ printf("● "); /* その記号で表示される */ } if (i % N == 0) { /* 以下、数の表示 */ printf(" "); for (j = i-N+1; j <= i; j++) { printf(" %2d", j); } printf("\n"); } } } /* 手を打つ。具体的には、1 以上 N*N 以下の数 n に対し、マス n を通る斜め線 */ /* 上のコマをすべて反転する。 */ void move(int n) { int i, j, ii, jj; /* i は行、j は列。いずれも 1 以上 N 未満 */ ii = (n-1)/N + 1; /* n を行 ii と列 jj に換算。 */ jj = (n-1)%N + 1; /* これらの値はこの関数内では変わらない */ for (i = ii, j = jj; i > 0 && j > 0; i--, j--) { /* そこから左上へ */ reverse(N*(i-1)+j); } for (i = ii, j = jj; i > 0 && j <= N ; i--, j++) { /* そこから右上へ */ reverse(N*(i-1)+j); } for (i = ii, j = jj; i <= N && j > 0 ; i++, j--) { /* そこから左下へ */ reverse(N*(i-1)+j); } for (i = ii, j = jj; i <= N && j <= N ; i++, j++) { /* そこから右下へ */ reverse(N*(i-1)+j); } reverse(n); /* 指定されたマス自身は上で四回ひっくり返るので */ } /* 番号 n のマスのコマを裏返す */ void reverse(int n) { a[n] = 1 - a[n]; } /* ゲームをクリアしたかどうかのチェック */ int check(void) { int n; for (n = 1; n < N*N; n++) { if (a[n] != a[n+1]) { return NO; } } return YES; }