なんか、とあるプログラミングスクールの入学試験でこういう問題は出題されたらしい。
合格できると、スクールの費用が全額無料ということなのですが、やはり、その門のハードルは高いようです。
で、オイラも腕試しで数独(ナンバープレイス)を解くプログラミングをやってみようと思いました。
まずは、問題を読み取るところから。(そこからかよ!)
とにかく、今回はUIは気にしないで、
こんな感じのファイルを取り込んで、デバッグ機能としてそのまま出力するところまでやります。
コードはこんな感じになりました。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace sudoku
{
class Program
{
static void Main(string[] args)
{
int[,] matrix = new int[9, 9];
// パラメータチェック
if (args.Length != 1)
{
Console.WriteLine("usage : sudoku.exe [input file]");
return;
}
// ファイルの存在を確認
string filePath = Environment.CurrentDirectory + "\\" + args[0];
if (File.Exists(filePath) == false)
{
Console.WriteLine("File not found.");
return;
}
// ファイルを開く
bool error = false;
using (var stream = new StreamReader(filePath))
{
int row = 0;
while(stream.EndOfStream == false)
{
string lineText = stream.ReadLine();
var val = lineText.Split(',');
int col = 0;
foreach(var v in val)
{
int i;
if(int.TryParse(v, out i))
{
matrix[row, col] = i;
}
else
{
error = true;
}
col++;
}
row++;
if(row > 9)
{
error = true;
}
}
}
if (error)
{
Console.WriteLine("Illegal format.");
return;
}
// debug
using (var stream = new StreamWriter(System.Environment.CurrentDirectory + "\\output"))
{
for(int row = 0; row < 9; row++)
{
for(int col = 0; col < 9; col++)
{
stream.Write(matrix[row, col]);
}
stream.Write("\r\n");
}
}
}
}
}
実行結果
引数でファイル名を取得する
Main()の引数args[]の中にコマンドパラメータが入っています。
今回使用する引数は、ファイル名1個だけですので、args.lengthが1以外の場合は、usageを表示して終了します。
ファイルの存在を確認する
今回はカレントフォルダに存在するファイルを対象にすることにします。
おそらく相対パスなら大丈夫かもしれませんが、絶対パスならエラーになるでしょう。
対策は後で考えます。力を入れるべきところはここじゃないので。
Environment.CurrentDirectoryにカレントフォルダが入っているので、これにファイル名をくっつけて、完全なファイルパスを作成します。
そして、File.Exists()でファイルの存在を確認します。存在しなければfalseが返るので、エラーメッセージを表示して終了します。
ファイルのデータを取り込む
テキストのデータ読み取りならStreamReaderを使うのが簡単でしょう。
StreamReaderでファイルを開いて、ファイルストリームを取得します。
usingを使うと、usingの中でExceptionが発生しても、適切なtry/catch処理をやってくれます。
まぁ、エラーが起こってもプログラムがファイルを掴んだままにならない、ということです。
usingの中でwhileループをおこない、ReadLine()でファイルから1行ずつ取り出します。
取り出した1行データをsplit()を使って、”,”(カンマ)で分割します。結果はstring[]になります。
これをさらにtryParse()でint型に変換します。
これで読み込んだ文字列が数字に変換されて取り込むことができます。
これを全てのデータに対して行います。
念のためフォーマットエラーも確認します。
まぁ、クラス構成はもうちょっと考えるとして、とりあえずはこんな感じで。