• 締切済み

数独を解くプログラム

私は、ナンプレ(数独)が好きでよく問題を解いています。 ふと、(以前少しだけC言語の勉強をしていたので)C言語でナンプレを解くプログラムを作るとしたらどんなソースになるのか気になりました。 私自身のプログラム理解のレベルがソースをかなりゆっくり読んで理解できる程度なので、プログラムにおこすことなど、とてもできません。 また、過去の質問を検索してみましたがJavaやC#のものは見つけられましたが、Cは見つけられませんでした。 面倒だとは思いますが、よろしければご教授ください。

みんなの回答

  • tadokiro
  • ベストアンサー率100% (1/1)
回答No.4

9行9列のスタンダード限定ですが虱潰しをするソースが載ってます。

参考URL:
http://www.mediatips.co.jp/puzzle-9x9.html
  • chie65535
  • ベストアンサー率43% (8520/19368)
回答No.3

9×9の配列を用意して、それを処理します。 配列の各要素には 0=空欄 1~9=埋まっている数字 -1~-9=置けない場所 を入れます。 そして 1.配列の中で1が置けない場所を-1で埋める 2.縦、横、3×3の枠で、0(空欄)が1つだけになったら、そこに1を入れる 3.配列の中の-1を0に戻す 4.配列の中で2が置けない場所を-2で埋める 5.縦、横、3×3の枠で、0(空欄)が1つだけになったら、そこに2を入れる 6.配列の中の-2を0に戻す 7.上記1~3、4~6の手順で、3~9までの数字を処理する 8.数字を1~9まで処理し、すべての枠が埋まったら完成。まだ空欄があるなら最初からやり直す 9.まだ空欄があって最初からやり直しても変化しないなら、置ける数字を置けそうな場所に置いて、試してみる 上記の処理をプログラムしてみたのが、以下のプログラムです。 #define true 1 #define false 0 //例題がセットしてあります //ReadMap()の中身が無くても //例題を解く事が出来ます char map[9][9] = { 0,0,0,0,3,2,0,0,0, 0,3,0,6,0,4,0,5,0, 0,0,7,0,0,0,1,0,0, 6,8,0,0,0,0,0,7,0, 2,0,0,0,8,0,0,0,3, 0,9,0,0,0,0,0,1,4, 0,0,3,0,0,0,5,0,0, 0,6,0,3,0,5,0,2,0, 0,0,0,8,1,0,0,0,0 }; void ReadMap(void) { //ファイルから読んでmap配列にセットする関数 //自分で作りましょう } int CheckMap(int x,int y,int n) { int i,j,ii,jj; for (i = 0;i < 9;i++) { if ((i != y) && (map[x][i] == n)) return false; if ((i != x) && (map[i][y] == n)) return false; } ii = x - (x % 3); jj = y - (y % 3); for (i = 0;i < 3;i++) { for (j = 0;j < 3;j++) { if ((x != ii+i) && (y != jj+j) && (map[ii+i][jj+j] == n)) return false; } } return true; } void SetMask(int n) { int i,j,ii,jj,iii,jjj; for(i = 0;i < 9;i++) { for(j = 0;j < 9;j++) { if (map[i][j] == n) { for(ii=0;ii < 9;ii++) { if (map[ii][j] == 0) map[ii][j] = (char)-n; if (map[i][ii] == 0) map[i][ii] = (char)-n; } iii = i - (i % 3); jjj = j - (j % 3); for(ii = 0;ii < 3;ii++) { for(jj = 0;jj < 3;jj++) { if (map[iii+ii][jjj+jj] == 0) map[iii+ii][jjj+jj] = (char)-n; } } } } } } int AnswerMake(void) { int e; int p; int n; int i,j,ii,jj; e = true; for (;;) { int f = 0; for(n = 1;n <= 9;n++) { SetMask(n); for(i = 0;i < 9;i++) { p = 0; for(j = 0;j < 9;j++) { if (map[i][j] == n) { p = -1; break; } if (map[i][j] == 0) { p++; ii = i; jj = j; } } if (p == 1) { map[ii][jj] = (char)n; SetMask(n); f++; } if (!p) { e = false; } } for(i = 0;i < 9;i++) { p = 0; for(j = 0;j < 9;j++) { if (map[j][i] == n) { p = -1; break; } if (map[j][i] == 0) { p++; ii = i; jj = j; } } if (p == 1) { map[jj][ii] = (char)n; SetMask(n); f++; } if (!p) { e = false; } } for(int i = 0;i < 9;i += 3) { for(int j = 0;j < 9;j += 3) { p = 0; bool b = false; for(iii = 0;iii < 3;iii++) { for(jjj = 0;jjj < 3;jjj++) { if (map[i+iii][j+jjj] == n) { p = -1; b = true; break; } if (map[i+iii][j+jjj] == 0) { p++; ii = i+iii; jj = j+jjj; } } if (b) break; } if (p == 1) { map[ii][jj] = (char)n; SetMask(n); f++; } if (!p) { e = false; } } } p = 0; for(i = 0;i < 9;i++) { for(j = 0;j < 9;j++) { if (map[i][j] < 0) { map[i][j] = 0; } if (!map[i][j]) { p++; } } } } if (f == 0) break; } if (!p) return 0; if (e) return 1; return -1; } int AnswerSearch(void) { int i,j,n,s; char map2[9][9]; for(i = 0;i < 9;i++) { for(j = 0;j < 9;j++) { if (map[i][j] == 0) { for(n = 1;n <= 9;n++) { if (CheckMap(i,j,n)) { memcpy(map2,map,sizeof(map)); map[i][j] = (char)n; s = AnswerMake(); if (s == 0) { return 0; } if (s > 0) { s = AnswerSearch(); if (s == 0) return 0; } memcpy(map,map2,sizeof(map)); } } return -1; } } } return 0; } void DisplayMap(void) { int i,j; for (i = 0;i < 9;i++) { for (j = 0;j < 9;j++) { printf("%3d",map[i][j]); } printf("\n"); } } int main(void) { int s; ReadMap(); //自分で作りましょう s = AnswerMake(); if (s > 0) s = AnswerSearch(); if (s < 0) printf("解答が存在しません\n"); if (s > 0) printf("数字を特定できないマスがあります\n"); DisplayMap(); }

  • toku8
  • ベストアンサー率26% (64/246)
回答No.2

わたしは ACCESS2000 で 数独の答えが算出できるプログラムを作成して ナンプレクイズなどで 使用しています (頭の体操にはなりませんが 答えは瞬時に出ます) ACCESSvbaで組んでいます ロジックとしては 縦横の既存数字を見て 各コマに 候補(だいたい2-5個ぐらい)数値を表示して その次に その状況から見て 確定数字を出せるコマを プログラムが選び出してそこの数値を確定させる また 次に その状況を基にして他のコマを順次確定していく という方式です だいたい 5回程度ボタンを押せば全コマ確定します ごくたまに上級向けの問題では 数値確定できない問題もあります その場合は 人力で(2つの候補が表示されているコマ)1つの数値 を仮選択して 次の段階へ進むようにしています (もし選んだほうがミスなら後刻エラーになるので もういちど  戻り 別の数値を選んで進める)

回答No.1

JavaやC#もCから発展したものなので いくつかの関数は自分で作る必要が出るかもしれませんが アルゴリズム自体はCに変換可能でしょう。 (数字が入ったオブジェクトを変数に変えるなどが必要でしょう) ただ、どのような環境でCを使用するかわかりませんが 単純なCではGUIが準備されていないので どのように数字を入力し、どのように結果を表示するか? ということを考えなくてはいけません。

jookanau
質問者

お礼

お早い回答、ご指摘ありがとうございます。 数字の入力と結果の表示ですがtxtで問題をあらかじめ用意しておいて、そのファイルを読み込み、そのファイルに追加に書き込み表示する。というファイル操作の方法くらいしか私のレベルでは思い付かないのですが…。 とにかくご回答ありがとうございました。

関連するQ&A

  • この数独の解き方を教えてください

    最近数独にハマりました。 優しい問題~普通レベルは解けるようになったんですが 下記の問題が解けません。 私自身いろいろなサイトを見て勉強しているのですが いまいち理解できません。 数独に詳しい方にご教授いただきたいです。 仮定で進めるのではなく、理詰めで解きたいです。 お手数ですが、どのような理由で数字が入るのか 教えていただけませんでしょうか。 よろしくお願いいたします。

  • 数独の自動生成サンプル

    数独の問題を自動生成するプログラムを作りたいのですが、方法が分かりません 考え方やサンプルが記載されているHPをご存知の方、教えてください。 (言語はjavaで組む予定ですが、他の言語でのサンプルでも構いません) よろしくお願いします。

  • 「世界で一番むつかしい数独の問題」・・・

    東大の渡辺氏のサイトに「世界で一番むつかしい数独の問題」というのが載っているのを見つけました。フィンランドの数学者、Inkara氏が2010年、2012年に発表したものだそうです。 http://apollon.issp.u-tokyo.ac.jp/~watanabe/sample/sudoku/index_j.html (A)2010年          (B)2012年 005 300 000       800 000 000   800 000 020       003 600 000 070 010 500       070 090 200 400 005 300       050 007 000 010 070 006       000 045 700 003 200 080       000 100 030  000 500 009       001 000 068 004 000 030       008 500 010 000 009 700       090 000 400 ※空白には「0」を入れています。 渡辺氏はこれよりもむつかしい問題を作ろうと考えたようです。ス^パーコンピュータを動かして作ったのが次の問題です。 (C)2013年3月 061 007 003 092 003 000 000 000 000 008 530 000 000 000 504 500 008 000 040 000 001 000 160 800 600 000 000 しかしこれは市販の問題集に載っている上級レベルの問題です。これを「世界で一番むつかしい問題」だと判断して発表したのですから計算機を動かすアルゴリズムに初歩的なミスがあった、または渡辺氏の数独の理解の程度に致命的な欠陥があったということになりそうです。(渡辺氏は自分では数独の問題を解こうとはしていないようです。コンピュータの出した数値だけをそのまま判断材料にしているのです。普通に解けば簡単にわかる不具合が見つからないままになっています。) (C)が簡単に解くことができる問題だったということが分かったので作り直したというものが追記の形で発表されています。 (D)3/22付け 追記 080 000 150 406 509 080 000 008 000 000 000 000 002 070 003 300 801 000 900 170 000 600 000 004 150 000 090 Inkara氏の(A)(B)に比べると格段にやさしいです。 「世界で一番むつかしい問題」を作ろうとしている意味とはどういうものでしょう。 数独というゲームとどういう関係があるのかもよくわかりません。 「むつかしい」ということがどういうことかも十分に吟味されているとは思えません。 解くのに必要な時間にはかなりの違いがあります。(B)>(A)>(D)です。でも解くのに必要な時間の違いがむつかしさの違いでしょうか。(B)を解くのには時間がかかります。でもむつかしくはありません。面倒なだけです。同じ論理をただ繰り返し使っているだけです。仮定の段数が多いので場合の数が多くなり、可能性のチェックに時間がかかるのです。ゲームとしての面白さ、むつかしさは時間だけではないはずです。(面倒くさいと思いながらも意地になって解きました。) ゲームとしての面白さは別にして、人の手で解くことのできるギリギリのところはどこらあたりにあるのかを探ることを目的にしているのかもしれません。でも渡辺氏の初めの問題(問題C)は「どうだ人の手では解けないだろう!」という形で発表されているのですから「人の手では解けない問題を作る」ことを目指しているようにも見えます。そうであればもはや数独ではありません。数独から派生した数学の問題だということになります。 そうであれば「むつかしい」の概念規定が重要になります。「むつかしい」というのは解く立場があってのことです。 たとえば初期設定の数字の数Noについて、「唯一解の存在する最低のNoは?」という問題は数学的に設定することは可能でしょう。でも数独の問題として解くときにNoが小さいことはそのままむつかしいにはつながりません。市販の難問問題集の中にNoが17,18というような問題ばかり集めているものがあります。でも別の問題集に載っているNoが22,23のものよりも易しいのです。 数独、ナンプレの本を出版している人たちはどういう風に考えているのでしょうか。 2010年に発表された問題であれば知れ渡っているはずです。 ゲームとしての数独、ナンプレとは関係がないとして無視しているのでしょうか。 でも数独、ナンプレの内部の話としても「むつかしい」というのは全然吟味されていないように思います。「超難問」とか「究極の難問」、「激辛の難問」とかのタイトルの本がたくさん売られています。むつかしさのレベルはまちまちです。中には鉛筆を縦横に置くだけで解けてしまうような問題まで含まれています。 参考 (B)を解いてみた結果 812 753 649 943 682 157 675 491 283 154 237 896 369 845 721 287 169 534 521 974 368 438 526 917 796 218 452 たぶん間違っていないと思います。 使ったのは紙と鉛筆とマーカーペンだけです。 A4の用紙に書いていけるところまで行きます。 場合分けに入るところからあとはコピーした用紙をたくさん使いました。 どの問題を解くのでも場合分けと仮定が必要です。(A)、(B)では仮定の積み重ねが必要ですが(D)では並立的な仮定しか使いません。 一般解法とと言われているものも仮定を使っています。ただ並立的にしか使いません。 「この本の問題を解くのに仮定法は使わない。すべて理詰めで解くことができる」と書いてある本がありますが誤りです。数独、ナンプレの問題の解法は「仮定法」なしでは成り立ちません。

  • C++プログラムをCで呼び出したい

    こんにちは。質問させていただきます。 現在、Linux/GCC3.2.3系でC言語の開発をしています。 私自身のレベルとしては、C言語での実務は1年未満。C++はゼロ。本業はJavaプログラマを数年やっております。 さっそく本題です。 既にC++で作成されたある一連のプログラム群(20本程度)があり、これらC++の関数をC言語で作成されたプログラムから呼び出して使用したいと思っています。 C++プログラムは既にテスト済みなので、これらのソースは基本的には手を加えず、そのままライブラリ化などして使用したいと考えています。 そこで質問なのですが、C言語から呼び出せるような形式でC++ソースをライブラリ化する方法と、C言語からの呼び出し方を教えていただけないでしょうか?

  • C言語プログラムを用いた画像表示プログラム

    おはようございます。 お時間ありましたら、ご教授よろしくお願いいたします。 C言語を使って、画像の表示、画像の処理ができるプログラムを作成したいのですが、私自身、JAVAを少しかじった程度の知識しかなくなかなかうまくいきません。 やっかいなことに、ただ画像を表示させるだけでなく、JPEGライブラリを用いた(JPEG画像を読み込んで処理できる)C言語プログラムのプログラムを作成したいのですがうまくいかずご質問させていただきました。 参照できるサイト、ご自信の作られたプログラム、プログラムを経験されている方の記述など教えていただければ幸いです。 明確な質問ではないのでご回答が非常に難しいと思いますが、よろしくお願いいたします。 早朝からお忙しいと思いますが、お時間がありましたら是非ご教授よろしくおねがいします。

  • プログラムを始めるなら

    C言語をある程度知っている人なら、プログラミングは大丈夫だと言われる理由って何でしょう? 別にC言語を元に全てのプログラムができたわけでもないし、 オブジェクト指向のプログラムとは毛色が違うし。 私自身C言語,javaなどのソースが読める程度しかできませんが、 プログラミングが出来るとはお世辞にも言えません。 何故このような事が言われているのでしょう? また、最初に学ぶべき言語としてはやはりC等の言語がいいのでしょうか? それともアセンブリ言語のような物の方がいいのでしょうか?

  • C言語のプログラムをJavaに

    C言語のプログラムをJavaのプログラムに直したいと思います。 で、どこから手を付ければよいでしょう? ヘッダファイルはどのように扱えばよいでしょうか? どうぞご教授お願いいたします

    • ベストアンサー
    • Java
  • GNOME数独のインストールについて

    勉強の為、Ubuntuを古いノートPCにインストールしました。 メモリの関係上今さらですが、6.10を入れました。 7.10を試した時に数独が標準で入っていましたが、6.10には入っておりません。検索の結果ソース(?)だと思いますがダウンロードはできましたが、ソースのインストール方法、並びに、メニューへの登録等教えてください。 PCは、モバイルセレロンの800、メモリー256MB、OSはUbuntu6.10、 インストールしたい数独はGNOME-SUDOKU-0.7.1が/TEPに入っております ネットを検索した時、Gnome端末にて、./configureを実行しましたが、見た目では何も変わりせんでした。 レスが遅れるかもしれませんが、よろしくお願いします。

  • JAVAで作るプログラムとは

    HPに使うJAVAスクリプトの勉強をしたく、JAVAとスクリプトは違う事を知らずにJAVAの通信教育を申し込んでしまいました。 JAVAはサーバー側のプログラミング言語で、 スクリプトはクライアント側のスクリプト言語でブラウザ上で動作する。 申し込んだものは仕方ないので頑張ってJAVAを理解したいと思うのですが、 ネット上のJAVA講座を見ると最初にJAVAをインストールするとあります。 これはJAVAを作成するソフトのようなものですか? JAVAで作るプログラムとはOSのようなものですか? JAVAでプログラムを作ってHPの更新やスクリプトが作成できるのですか? そもそもJAVAで作るプログラムとはどのように利用するのか、 プログラムの意味がよく分かりません。 JAVAとスクリプトの違いはもう良いのでプログラムについて 分かりやすく教えてください。

    • ベストアンサー
    • Java
  • 組み込み系+制御系プログラムの勉強するなら?

    組み込み系か制御系のプログラムの勉強したいのですが、 前からC言語とjavaはやってるのですが、 言語以外に勉強すべき事や、 c/javaよりも、やるべき言語が、あれば教えてください。 学習に、いい本が有ったら本の名前等も教えてください。 よろしくお願いします。

専門家に質問してみよう