• ベストアンサー

数独かを判断するプログラム

私が作ろうとしているプログラムは数独を解くものではなく、予めテキストファイルに書かれている横9つ縦9つ、計81個の数字の表が、数独として成り立っているかを判断するものです。 数独についてはこちらで http://ja.wikipedia.org/wiki/数独 or http://sudoku.ara3.net/rule.htm 配列をa[9][9]と用意し、テキストファイルから数字を左上から順に配列に確保していき、その表が数独かどうか判断する段階で躓いています。3×3のマスの中に1~9までの数字が1個ずつあり、かつそのマスが計9つあれば数独なので、まず最初の3×3のマスの中の数字を1~9まで確認し、それを残り8つのマスにも同様に繰り返すだけで良いと思うのですが、その方法がわからず困っています。どなたかお解かりになる方、よろしくお願いします。 例として、テキストファイルの数字の表は以下の様になっています。 1 2 3 4 5 6 7 8 9 4 5 6 7 8 9 1 2 3 7 8 9 1 2 3 4 5 6 2 3 4 5 6 7 8 9 1 5 6 7 8 9 1 2 3 4 8 9 1 2 3 4 5 6 7 3 4 5 6 7 8 9 1 2 6 7 8 9 1 2 3 4 5 9 1 2 3 4 5 6 7 8 ちなみにこの表は数独として成り立っています。

質問者が選んだベストアンサー

  • ベストアンサー
  • fonera
  • ベストアンサー率52% (38/72)
回答No.2

No.1で回答したモノです。 申し訳ありません、ブロック判定がおかしかったです。 for(bx = 0; bx < 9; bx+=3) {  for(by= 0; by < 9; by+=3) {   for(x = 0+bx; x < 3+bx; x++) {    for(y= 0+by; y < 3+by; y++) {     check[array[x][y]]++;    }   }  /*ここで判定する*/  } } ですな。 # 卓上で考えたのでバグに気がつきませんでした・・・手元ではとりあえずこれで動いてます。

lockwell
質問者

補足

とても理解しやすかったです。おかげさまでプログラムができました! 一つだけ確認したいのですが、x軸y軸のチェックは、それぞれどれか1行だけ選んでチェックすればいいんですよね?数独はすべての行をチェックする必要はありませんよね?

その他の回答 (5)

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.6

すみません。 アイディアが、先走って変なプログラム投稿しちゃいました。 基本的な考え方は、checkの右側から27個のビットを、1~9までの数字が現れたかどうかのチェックに使っています。 for(i = 0; i < 9; i++) {  check = 0;  for(j = 0;j < 9;j++) {   r = a[i * 9 + j] - 1;   c = a[j * 9 + i] - 1;   b = a[i / 3 * 27 + i % 3 * 3 + j % 3 + j / 3 * 9] - 1;   check != ((1 << (r + 18)) + (1 << (c + 9)) + (1 << b));   }   if(check != 0x7ffffff) {    return 0;   }  } } return 1;

lockwell
質問者

お礼

あぁなるほどビット演算ですか。たしかにこれだとやりやすいかもしれません。 私なんかでは全然アイデアが浮かばず、しかしいくつもアイデアがあり驚きました。いやはや、なんとも未熟です。。 本当にありがとうございました!

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.5

ループを1つにまとめるアイディアです。 for(i = 0; i < 9; i++) {  for(j = 0;j < 9;j++) {   r = i * 9 + j;   c = j * 9 + i;   b = i / 3 * 27 + i % 3 * 3 + j % 3 + j / 3 * 9;   if((((1 << r) << 18) |= ((1 << c) << 9) |= 1 << b) != 0x7FFFFFF) {    return 0;   }  } } return 1; 変数の宣言などは、省いてます。全て整数です。 考え方には、自信がありますが、動かしてないんで、タイプミスがあるかもしれません。

  • masa6272
  • ベストアンサー率66% (93/140)
回答No.4

ループの回し方と、判定についてのアイディアです。 for(i = 0;i < 3;i++) {  for(j = 0;j < 3;j++) {   check = 0;   for(k = 0;k < 9;k++) {    check |= (1 << (a[(k % 3 + i * 3) + (k / 3 + j * 3)] - 1));   }   if(check != 0x1ff) {    数独ではないときの処理、多分これが関数なら、0 でも返す   }  } } aは81個の、1次元配列です。ここに挙げたのは、3×3の部分のチェックです。 後、横は for(i = 0;i < 9;i++) {  for(j = 0;j < 9;j++) {   a[i * 9 + j]に関する処理  } } 縦は for(i = 0;i < 9;i++) {  for(j = 0;j < 9;j++) {   a[i + j * 9]に関する処理  } } ここで、縦と横は同じ形のループですので、1つにまとめることもできます。 ここまでが、回し方のアイディア。 判定ですが、ダブってないかをチェックするのに、ビット演算を使っています。これで、1~9までが、ダブりなく存在するか、簡単にチェックできるはずです(動かしてないんで・・)

  • yuu_yuu
  • ベストアンサー率41% (34/81)
回答No.3

同じようなことを考える人はいるものですね^^ 私は、数独を解く方のプログラムを組みました^^; >>まず最初の3×3のマスの中の数字を1~9まで確認し、 >>それを残り8つのマスにも同様に繰り返すだけで良いと思うのですが これは、違います。縦と横も1~9があることを確認しないと数独として成立しません。 回答ですが。。。 頭の良い人なら、計算で求める事が出来るのかもしれませんが、私は頭が悪いので ベタに書きました^^; (私はa[9][9]の配列は使わず、a[81]の配列を使用。) int SANxSAN[9][9]; //左上の3×3 SANxSAN[0][0] = 0; SANxSAN[0][1] = 1; SANxSAN[0][2] = 2; SANxSAN[0][3] = 9; SANxSAN[0][4] = 10; SANxSAN[0][5] = 11; SANxSAN[0][6] = 18; SANxSAN[0][7] = 19; SANxSAN[0][8] = 20; //中上の3×3 SANxSAN[1][0] = 3; SANxSAN[1][1] = 4; SANxSAN[1][2] = 5; SANxSAN[1][3] = 12; SANxSAN[1][4] = 13; SANxSAN[1][5] = 14; SANxSAN[1][6] = 21; SANxSAN[1][7] = 22; SANxSAN[1][8] = 23;   以下全部ベタに書く・・・ で、チェックするところでは for(i=0;i<9;i++){   for(j=0;j<9;j++){     a[SANxSAN[i][j]] が1~9全部あるかチェック   } } ちなみに横は for(i=0;i<9;i++){   for(j=0;j<9;j++){     a[i*9+j] が1~9全部あるかチェック   } } ついでに縦 for(i=0;i<9;i++){   for(j=0;j<9;j++){     a[i+j*9] が1~9全部あるかチェック   } }

lockwell
質問者

お礼

>縦と横も1~9があることを確認しないと数独として成立しません。 確かにその通りですね・・・失念していました^^ a[81]でも出来るという発想はありませんでした。いやはや、自分の初心ぶりがよく自覚できます(涙 おかげさまでプログラムができました!ありがとうございました!

  • fonera
  • ベストアンサー率52% (38/72)
回答No.1

恐れ入ります。 array[9][9]の配列でチェックする方法で回答します。 (判定の方法は他にいくつかあると思いますが、理解しやすいベタな書き方で回答します) ・まず、X軸のチェックをします。 例えばcheck[9]の配列を全て0で初期化しておき、 check[array[x][y]]++ などで、2以上もしくは0の配列が一つでもあれば数独ではないですよね。 for(x = 0; x < 9; x++) {  check[array[x][0]]++; } であれば、一番上の列のX軸のチェックが出来ます。 ・次に、Y軸のチェックをします。 X軸と同様に行います。 ・3x3マスのチェックを行います。 X軸と同様ですが、 array[x][y]で、xだけ・yだけ変えつつループさせるわけにはいかないので工夫が必要です こういうときは、まず手でべた書きして、その後省略できないか考えた方が楽です。 array[0][0], array[0][1], array[0][2] array[1][0], arrya[1][1], array[1][2] array[2][0], arrya[2][1], array[2][2] こうやって書けば、何となく判りますか? 先ほどまでと同様に、 for(x = 0; x < 3; x++) {  for(y= 0; y < 3; y++) {   check[array[x][y]]++;  } } とすればチェックできますね?あとは、これを9ブロック分やりたいので・・・ for(bx = 0; bx < 3; bx++) {  for(by= 0; by < 3; by++) {   for(x = 0+bx; x < 3+bx; x++) {    for(y= 0+by; y < 3+by; y++) {     check[array[x][y]]++;    }   }  } } とすればチェックできます。 べた書きは見づらいし、インデントが深くなって混乱しがちです。 一回動くモノが出来たら、関数に出来るところはないか、省略できるところはないか考えるようにしてみて下さい。

関連するQ&A

  • 数独(ナンプレ)の解き方(アルゴリズム)

    プログラミングの宿題で、Javaを使って数独を解くプログラムを作っています。雑誌などにある数独の問題を解くことはできたのですが、今回はその問題もプログラムで作ってそれを解かせようというお題になってしまいました。今のところ下のような感じになっています。 1. 乱数を使って0-80までのマス番号に1-9の数字を数個適当に入れていきます。(0が左上の角で、80が右下の角です。) 乱数でマスに数字を入れますから、同じマスに数字が入ることがありますが、それはそれでそのマスを上書きしています。さらにこの段階で、数字が同じ列または3×3マスで重なることがないようにしています。 2. それを元に各マスに入る可能性のある数字をリストアップ 3. リストアップした中で、最後に必ず1つだけ数字が残るのでそれをそのマスに入れます。 とここまではできました。しかし、乱数で適当に問題をつくったにしか過ぎないから、当然ダブってしまうところや、数字が入らないマスがあります。ですから、そういったダブるところや数字の入らないマスのために補正をしたいと思うのですが、まったくアイディアが浮かびません。どのようにしたら補正をして問題を回答できますか? アルゴリズムが少々長くてもかまいません。また、Javaのコードでの回答でなくてもかまいません。とにかく、如何の様に補正するのかを知りたいです。 下にあるのが、上の1.で作った問題です。 # 0は数字が入っていないマスを示します。 060 | 000 | 080 030 | 080 | 017 000 | 100 | 000 --------------- 800 | 000 | 903 000 | 803 | 060 000 | 096 | 500 --------------- 908 | 407 | 000 205 | 000 | 400 700 | 001 | 000

  • 4×4の数独の種類

    先日の大学入試問題で 出た問題です。 4×4のマスの中に 1~4の数字を 9×9の数独と同じルールで 埋めていきます。 そのとき何通り できるかを聞いています。 各塾で出した入試速報の中で いくつかの解答が間違った そうです。 一応答えは288通り なのですが、 どう解説したらよいかが よくわかりません。 どなたか教えて いただけませんか??

  • この数独を解けますか?8

    過去に出した問題について、「数字の配列に規則性がみられる」等、ご指摘がありましたので、それらを改善し、新たに「16×16」の問題を作ってみました。 ルールは従来と同様、 (1)1×16 (2)16×1 (3)4×4 のマスに、1から16の数字を重複することなく埋める。 です。 解答・感想等、お待ちしております。 関連質問の以下を合わせてご覧ください。 「この独数を解けますか?7」 http://okwave.jp/qa/q6637620.html ---------- csv形式 ---------- 1,2,3,4,11,5,15,10,13,7,6,9,16,8,12,14 5,6,7,8,4,13,9,1,10,16,12,14,2,11,15,3 9,10,11,12,8,16,3,14,1,15,5,2,6,13,4,7 13,14,15,16,2,7,12,6,4,3,8,11,5,9,1,10 10,5,16,3,,,,,,,,6,,4,, 2,15,8,11,,12,,,,,,,9,,, 12,9,4,13,,,6,,2,,16,,,,, 7,1,14,6,,,,,,,,,,2,, 6,13,10,2,15,,,,,,,,,,,11 11,3,12,14,,,,,,13,,1,,,, 15,4,5,9,,,,,,,,,,,, 8,16,1,7,,,,13,,,,,3,,,9 16,7,2,10,,15,,,,,3,,,,, 4,12,13,5,,,,9,,,,,,,14, 14,8,9,15,,,2,,,,,,,7,, 3,11,6,1,,,,,,,,,,,9, ---------- end ------------- csv形式の使い方(エクセルをお持ちの方): (1)新しいテキストファイルを開き、上記内容をコピー&ペースト。 (2)ファイルの拡張子を「.csv」に変更する。 (3)ファイルを開く。

  • 数独の場合の数

    Wikiprdiaで調べると、 http://ja.wikipedia.org/wiki/%E6%95%B0%E7%8B%AC で、 「数独の組み合わせパターン数は、回転や反射や順列や名前を変更することなどの左右対称が考慮に入れられると、54億7273万0538になるとエド・ラッセルとフレーザージャービスによって示されている[8]。」 とあります。 「・・・」の中の意味を分かりやすく教えてもらえないでしょうか。全部マス目を埋めたパターンが54億通りある、ということでしょうか。それにしたら多すぎるような気がします・・・。

  • 「数独」は名詞として五七五に使えるのか

    ナンバープレーズの中に「数独」というパズルがあります。9x9の列があり、9x9のマスがあって、そのどれにも重複しないように、1~9の数字を埋めていくというパズルです。ニコリという会社の商標登録がされていますが、私の読んでいる新聞にも週1回掲載されます。ボケ防止の一環として解いてます。私は他に五七五を詠むことも趣味としています。そこでお尋ねします。「数独」を名詞として五七五に使っても通用するでしょうか。それともいまだ人口に膾炙していない言葉でしょうか。「ナンバープレーズ」では字余りなのです。なお、五七五に使えば商標登録違反かという質問ではありません。

  • この数独の、ある基準での解き方をお願いします。

    画像の数独は、途中まで自力で解いたものです。 大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を記述してください。 [NG - 禁止テク] Sudopedia ( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ※初級/中級程度の手筋は省略して結構です。全部の解答は必要ありません。 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、仮定法を使わず、基準を遵守してください。 大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を教えてください。 [NG - 禁止テク] ・Sudopedia( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ※初級/中級程度の手筋は省略して結構です。全部の解答は必要ありません。 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、仮定法を使わず、基準を遵守してください。

  • 下図の数独を、提示した基準で解いてください。

    画像の数独(途中まで自力で解いたもの)について、以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を記述してください。 [NG - 禁止テク] ・Sudopedia( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ヒントは以下のサイトにあるようです。 http://www.sudoku.org.uk/SudokuThread.asp?fid=4&sid=10069&p1=6&p2=15 ※図については、大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 ※全部の解答は必要ありません。初級/中級程度の手筋は省略して結構です。 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、仮定法を使わず、基準を遵守してください。

  • 数独の最難問を提示された基準でといてください。

    画像の数独(途中まで自力で解いたもの)について、以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を教えてください。 大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 (初級/中級程度の手筋は省略して結構です。全部の解答は必要ありません) [NG - 禁止テク] ・Sudopedia( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、仮定法を使わず、基準を遵守してください。

  • 画像の数独を、提示された基準で、解いてください。

    画像の数独(途中まで自力で解いたもの)について、以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を教えてください。 大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 (初級/中級程度の手筋は省略して結構です。全部の解答は必要ありません) [NG - 禁止テク] ・Sudopedia( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ヒントは以下のサイトにあるようです。 http://www.sudoku.org.uk/SudokuThread.asp?fid=4&sid=10069&p1=6&p2=15 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、基準を遵守してください。

  • 下図の数独を、提示された基準に従って解いてください

    画像の数独(途中まで自力で解いたもの)について: 大きい数字が表出数字、丸で囲んだ数字があとから埋めた数字、小さい数字が今のところ除外できていない候補数字です。 以下の基準で、どれかひとつでも、マスの埋まる解き方、あるいは候補が除外できる解き方(できるならテク名とその参照元も)を教えてください。 [NG - 禁止テク] ・Sudopedia( http://www.sudopedia.org/wiki/Solving_Technique )で 「Techniques of Last Resort」「Brute Force」に分類されているテク。 [OK] ・上記以外のSudopediaにあるテクおよびそのバリエーションならOKです。 ・Unique Rectangle などの唯一解系もOKです。 ・その他独自のテクは、この問題だけでなく他の問題にも適用できるような一般化した解説を付けてください。 ※初級/中級程度の手筋は省略して結構です。全部の解答は必要ありません。 ※試行錯誤的な方法なら解けるのは当たり前すぎるので、仮定法を使わず、基準を遵守してください。

専門家に質問してみよう