Upload
fumihito-yokoyama
View
1.386
Download
1
Embed Size (px)
DESCRIPTION
7/7 七夕 プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 #pronamaclrhsapporocppで発表した内容
Citation preview
LINQ を使ったナンプレの解
法を作ったお話
momo_*(@tututen)
自己紹介
● 某北見市で働く職業プログラマ● 趣味でもプログラム書くことがあります● お仕事:C言語、(Python、C#)● 趣味:ほぼ何でも(※アセンブリを除く)● パネルでポン(以下、パネポン)ができます● タグ「友達がいないとこうなります」で検索!● あと、手元を映したUst動画もあったりします
地図
地図
自己紹介
● 某北見市で働く職業プログラマ● 趣味でもプログラム書くことがあります● お仕事:C言語、(Python、C#)● 趣味:ほぼ何でも(※アセンブリを除く)● パネルでポン(以下、パネポン)ができます● タグ「友達がいないとこうなります」で検索!● あと、手元を映したUst動画もあったりします
検索結果
最近のタグ(7/7 13:00現在)
Ust風景
http://www.ustream.tv/recorded/20923039
お品書
● LINQの簡易説明● ナンプレの解法手順1● 実装1● ナンプレの解法手順2● 実装2● デモ
LINQについて
Language Integrated Query の略称で、 C# や VB などの .NET Framework 対応言語に、 リレーショナルデータや XML に対するデータ操作構文を組み込む (+ データベースや XML 操作用のライブラリ)
引用:http://ufcpp.net/study/csharp/sp3_linq.html
LINQについて
クエリ式
拡張メソッド
ナンバープレース
引用:http://www.sudokugame.org/ 2012/7/4 最高級
9×9のマスの中に、1から9までの数字を入れていくパズルである。 次のような三つのルールは守らなければならない。
● 一列で同じ数字を使ってはいけない
● 一行で同じ数字を使ってはいけない
● 一つのブロックで同じ数字を使ってはいけ
ない
定義
● フィールドは1次元のint配列で定義● 配列にはそれぞれ[0-9]が入り、0は空白を示す
解法手順1
1. 空白場所を探す2. たて・横・ブロックを見て、
現状で空白に入る数字をリストアップする3. 2で得た数字を入れてみる4. 1に戻る5. 2で数字が見つからなければ、
一つ前の空白に戻り、違う数字を入れる
解法手順1
1. 空白場所を探す2. たて・横・ブロックを見て、
現状で空白に入る数字をリストアップする3. 2で得た数字を入れてみる4. 1に戻る5. 2で数字が見つからなければ、
一つ前の空白に戻り、違う数字を入れるここでLINQ使える!
0.使う構造体
各マスの構造体Valはマスの値、
Indexはマスの場所、
NumListは入れることの出来る数字のリストです
0.使う構造体の初期化
● 通常
0.使う構造体の初期化
● LINQ
1.空白の場所を探す(1)
● 通常
1.空白の場所を探す(2)
● LINQ
2.たて・横・ブロックの…(1)
今いるセルのたての列の値を取得したい場合
・・・今見てる空白マス
2.たて・横・ブロックの…(2)
・・・今見てる空白マス
2.たて・横・ブロックの…(3)
今いるセルの横の列の値を取得したい場合
・・・今見てる空白マス
2.たて・横・ブロックの…(4)
・・・今見てる空白マス
2.たて・横・ブロックの…(5)
今いるセルのボックスの列の値を取得したい場合
・・・今見てる空白マス
2.たて・横・ボックスの…
・・・今見てる空白マス
2.たて・横・ブロックの…(7)
たて・横・ボックスに存在しない数字を「候補リスト」として扱う
・・・今見てる空白マス
2.たて・横・ブロックの…(8)
2.たて・横・ブロックの…(9)
最後に1-9のリストと差分をとって「候補リスト」ができる↓差集合を取る
2.たて・横・ブロックの…(A)
LINQを使うと・・・
・・・今見てる空白マス
2.たて・横・ボックスの…
LINQを使うと・・・
2.たて・横・ボックスの…
LINQを使うと・・・
たて・横・ブロックマスの抽出
2.たて・横・ボックスの…
LINQを使うと・・・
空白除去・重複要素除去
2.たて・横・ボックスの…
LINQを使うと・・・
各スペースに候補リスト代入
解法手順1
1. 空白場所を探す2. たて・横・ブロックックスを見て、
現状で空白に入る数字をリストアップする3. 2で得た数字を入れてみる4. 1に戻る5. 2で数字が見つからなければ、
一つ前の空白に戻り、違う数字を入れる
省略!
解法手順1の問題点
● 空白マスが多く深く探索後に間違いに気づく問題の場合酷く時間がかかる
● 空白の多いマスで実行すると7~8時間帰って来ないことがある
● 再帰関数の呼び出し回数が1000万超えることも…
解法手順2
1. 候補が絞れている物は埋めてしまう2. 空白場所を探す3. たて・横・ブロックックスを見て、
現状で空白に入る数字をリストアップする4. 3で得た数字を入れてみる5. 2に戻る6. 3で数字が見つからなければ、
一つ前の空白に戻り、違う数字を入れる
解法手順2
1. 候補が絞れている物は埋めてしまう2. 空白場所を探す3. たて・横・ブロックックスを見て、
現状で空白に入る数字をリストアップする4. 3で得た数字を入れてみる5. 2に戻る6. 3で数字が見つからなければ、
一つ前の空白に戻り、違う数字を入れる
追加!ここもLINQ使える!!
手法
8
6
2
1
[4, 5, 7, 9]
[4, 5, 7]
[3, 5, 7]
[4, 5, 9]
[4, 9]
● ある列を抜き出した物● マスの横にあるものを候補リストとす
る
引用:http://www.geocities.jp/m_hiroi/func/abcscm41.html
手法
8
6
2
3
1
[4, 5, 7, 9]
[4, 5, 7]
[3, 5, 7]
[4, 5, 9]
[4, 9]
● この列の候補リストの中で[3, 5, 7]中の3だけ候補リストに存在する
● このマス以外に3を入れるとルール上崩れるのでこのマスに3を入れることが出来る
● これを検索するプログラムを書きました
2.たて・横・ボックスの…
LINQを使うと・・・
たて・横・ブロックに属するマスを取得
平坦化するIEnumerable<IEnumerable<TmpData>> { たて, 横, ブロック
}を、IEnumerable<TmpData> { たて, 横, ブロック}にする
たて・横・ブロックの候補リストを取得し候補の数字をキーにグループ化
グループ化した要素の個数が1個のものを取得し、リスト化する
1つだけの候補の位置を探しだし
その位置に数字を埋める
比較
● http://www.sudokugame.org/ の2012/07/05 中級の問題
● 解法1○ 解答時間 5.3851703秒○ 関数呼び出し回数: 3090回
● 解法2○ 解答時間 0.0805433秒○ 関数呼び出し回数: 4回
比較
● http://www.sudokugame.org/ の2012/07/05 最高級の問題
● 解法1○ 解答時間 測定不能(8h以上)○ 関数呼び出し回数: 1000万回以上
● 解法2○ 解答時間 0.3522107秒○ 関数呼び出し回数: 15回
DemoLINQ!! LINQ!!
まとめ
● このアプリ作成使ったループ文は1個!● LLじゃなくても1ライナー!(但し文字数多い)● わーいLINQ、@tututen LINQ大好き!
おまけ
● 画像処理もLINQ
今回の裏機能
今回の裏機能
主な流れ
● フォームのサイズでキャプチャ● キャプチャした画像をグレースケール→二値化● 予め用意した数字の画像とマッチング
主な流れ
● フォームのサイズでキャプチャ● キャプチャした画像をグレースケール→二値化● 予め用意した数字の画像とマッチング
ここでもLINQ使える!!
二値化
二値化
マッチング
マッチング
ご静聴
ありがとう
ございました
LINQ!! LINQ!!