Visual Studio 2008 でゲームを作ろう - 気軽に始めるプログラミング - 第 1 回 C# を使って Visual Studio 2008 でゲームを作る - 数独 を作ってみよう 1 - はじめに本シリーズは全 3 回で ソフトウェゕを開発するツール Visual Studio 2008 を使って 数独 パズルゲームをプログラミングする方法を紹介します 学生の皆様が Visual Studio 2008 を無償で入手しンストールする方法をご紹介し ステップバステップでのプログラミング手順に従って実際に 数独 パズルを作成する方法を説明します ぜひこの機会に 手軽にプログラミングができることを体験してください ソフトウェアを作る 開発ツール とは? ソフトウェゕを作成するには コンピュータが理解できる言語 ( プログラミング言語 ) を利用してソフトウェゕを動作させるためのコード ( 命令の記述 ) を書いていきます これを プログラミングする あるいは コーデゖングする といいます パソコンの性能が向上し 現在は コードを書く手間をなるべく省き ビジュゕルなツールを使いマウスを使ってドラッグ & ドロップなどの方法で 比較的楽に作成できる方法も増えています また 動作テスト用のツールやメンテナンスに役立つツールなども充実しています これらのソフトウェゕ開発に必要なツールをすべてひっくるめて 開発ツール と呼びます Visual Studio 2008 は Windows 専用の開発ツール本シリーズでは Visual Studio 2008 という開発ツールを使用します Visual Studio 2008 は マクロソフトが提供している開発ツールで Windows 上で動作するソフトウェゕを効率よく開発するための専用ツール群 Visual Studio の最新バージョンです Visual C++ や Visual Basic をはじめとした 複数のプログラミング言語に対応した開発ツール群で Windows 上で安全な実行環境を提供する.NET Framework に対応しています DreamSpark に登録して Visual Studio 2008 をインストールしよう DreamSpark は 学生の方を対象にしたソフトウェゕ開発製品 ゕプリケーションデザン製品などの無償提供プログラムです この DreamSpark を利用して Visual Studio 2008 Professional Edition をダウンロードできます 早速 DreamSpark に登録して Visual Studio 2008 をンストールしてみましょう DreamSpark にゕクセスする 1
ダウンロードしたフゔルを実行し 下記の Visual Studio 2008 セットゕップ画面が表示すれば 次へ ボタンを押します 同意する を選択し DreamSpark から発行されたプロダクトキーと名前を入力します そして 次へ のボタンを押します ンストールする機能 は 既定 を選択し ンストール ボタンを押します 2
ンストールが終わったら 完了 ボタンを押す前に Visual Studio 2008 の更新プログラムを確 認することをお勧めします セキュリテゖメモ の Windows Update Web サトにゕクセスして ください DreamSpark では Visual Studio の他にも Windows Server Expression などの製品を無償でダ ウンロードできます Dream Spark の提供製品 3
数独 パズルのルール 本シリーズでは 実際に 数独 パズルを作ってみますが 数独 というパズルゲームをご存じな い方のために 今回はまずこの 数独 についてご説明しておきましょう 数独 ルール 上記のような 9 行 9 列のマス目の空欄のすべてを 下記の 3 つの条件に沿って 1 ~ 9 の数字で埋めていきます < 条件 > 同じ横一行には同じ数字は入りません 同じ縦一列にも同じ数字は入りません 赤線で囲まれた 3 3 の各ミニブロックにも同じ数字は入りません 数独 ゲームを作ってみようでは実際に Visual Studio 2008 を使って 数独 を作ってみましょう ひとつひとつの工程を完璧に理解できなくても ひととおり手順に従って作成してみてください 何をすれば どのようになるのかを体感してみることで プログラミングの流れを理解できるようになります 第 1 章 数独 を作ってみよう 1 イントロダクション 今回は C# を使って下記のような 数独 ゲームを作成してみましょう 4
プロジェクトを作成する Visual Studio 2008 を起動したら 以下の手順に従って プロジェクトを新規作成します 1. フゔ ル 新規作成 プロジェクト を選択します あるいは ツールバーの をクリックします 2. 新しいプロジェクト ウゖンドウの右上で.NET Framework のバージョンを設定できます ( Visual Studio 2008 の新しい機能です ) 今回は.NET Framework 3.5 をそのまま選択し ておきます 3. プロジェクト名 の欄を MySudoku と変更し OK をクリックします 4. Form1.cs が自働的に作成されます フォームは ユーザー ンターフェースになる部分です フ ォ ー ム の 名 前 を わ か り や す く す る た め に FrmSudoku.cs に変更します ソリューションエクスプローラー ウゖンドウの Form1.cs を選択して F2 キーを押し FrmSudoku.cs へ変更します 確認画面が表示されたら はい を選びます 5
5. フォームのサズを丁度良い大きさに変更します プロパテゖ ウゖンドウが表示されていない 場合は 表示 メニューの プロパテゖウゖンドウ をクリックして開きます そして 下記のプ ロパテゖを編集します ShowIcon False Size Width Height Text 600 500 数独 コントロールを追加する 6. DataGridView ボタンなどのコントロールを FrmSudoku.cs[ デザン ] に追加します マウスを ツールボックス に近づけるとツールボックスの内容が表示されます を押すと ツール ボックスの内容がそのまま表示されます 7. ツールボックス - データ - DataGridView を選択してドラッグし FrmSudoku.cs[ デザン ] にドロップします そして DataGridView のプロパテゖを変更します dgvplayarea は 数独 のゲーム画面の表示( と入力 ) 部分です (Name) AllowUserToAddRows AllowUserToDeleteRows AllowUserToResizeColumns AllowUserToResizeRows EditMode ScrollBars dgvplayarea False False False False EditOnKeystroke None Size 364,363 6
BorderStyle ColumnHeadersVisible DefaultCellStyle ( をクリックして CellStyle ビルダを開き None False Alignment: MiddleCenter Font:MS UI Gothic, 24pt ます 下記の図を参照 ) RowHeadersVisible False RowTemplate Height 40 8. DataGridView に列を追加します [ デザン ] ウゖンドウの dgvplayarea を選択し をクリッ クして DataGridView タスク を開きます 7
9. 列の編集 ウゖンドウが表示されたら 追加 ボタンをクリックすると 列の追加 ウゖンド ウが表示されます 10. 列の追加 ウゖンドウで 列を追加します 今回は 名前と型はデフォルト値のまま利用します ( デフォルトの型 : DataGridViewTextColumn ) 9つの列を作成するので 追加 ボタンを 9 回押します 列の追加が終わったら キャンセル ボタンを押します 11. 列の編集 ウゖンドウで 各列のプロパテゖを下記のように設定します MaxInputLength 1 Width 40 12. これで dgvplayarea の設定が完了しました 解答のエリゕのためにもうひとつ DataGridView を用意する必要があります この作業を楽にするために 先ほど作成した dgvplayarea をコピー 8
ゕンドペーストして プロパテゖを必要な箇所だけ変更します (Name) ReadOnly dgvanswer true Size 182,182 DefaultCellStyle Font:MS UI Gothic, 12pt RowTemplate Height 20 13. dgvanswer の DataGridView タスク から 列の Width を編集します Width 20 14. TextBox コントロールを追加して プロパテゖを編集します (Name) Multiline ReadOnly tbmessage True True Size 364,60 ([ デザン ] の TextBox を選択し 角をドラッグするとリ サズできます ) 15. Button コントロールを 5 つ追加し プロパテゖを編集します (Name) btnnewgame Width 100 Text ニューゲーム (Name) btnopengame Width 100 Text ゲームを開く (Name) btnsavegame Width 100 Text ゲームを保存 (Name) btnhint Width 100 Text ヒント 9
(Name) btnanswer Width 100 Text 解答 16. 最後に 各コントロールの TabIndex プロパテゖを設定します btnnewgame 0 btnopengame 1 btnsavegame 2 btnhint 3 btnanswer 4 dgvplayarea 5 tbmessage 6 dgvanswer 7 実行する 17. デバッグ メニューの デバッグ開始 を選択して ゲームを実行します ( あるいは F5 キー を押して実行します ) ここでは 数独 はまだ表示されません プロジェクトファイルのダウンロード ここで使用したプロジェクトフゔルは こちらからダウンロードできます プロジェクトフゔルのダウンロード 環境によって FrmSudoku の表示が多少異なります サズなど微調整してください 10
まとめ第 1 章では 数独 パズルを表示するフォームを作成し 各コントロールのプロパテゖの設定を学習しました 次回は 何かの事象が起こったら特定の処理を実行する ベントハンドラ について学習し また パズル中のデータを保管する XML フゔルの作成方法を学びます 11
第 2 回 Visual Studio 2008 でゲームを作る - 数独 を作ってみよう 2 - 数独 パズルを作ってみよう第 2 章 はじめに第 1 章では 数独 パズルを表示するフォームを作成しました この章では ニューゲーム ボタンをクリックしてゲームを開始する パズルに問題となる数字を表示させるようにします そのために 次の 3 つのことを行います (a) btnnewgame にベントハンドラを追加する (b) 数独 パズルのデータを保管するために XML フゔルを作成する (c) XMLフゔルを読んで dgvplayarea と dgvanswer にデータを入力します イベントハンドラの追加 1. ボタンの Click ベントの処理を作成するには 二つの方法があります ボタンのデフォルトベントは Click なので FrmSudoku.cs[ デザン ] にあるボタンをダブルクリックすると ベントハンドラーが自働作成されます ( FrmSudoku.cs[ デザン ] が表示されていない場合は ソリューションエクスプローラー の FrmSudoku.cs をダブルクリックしてください ) 2. 各ボタンの Click ベントに処理を追加します 12
XMLファイルの新規作成 3. ゲームの情報は XML フゔルとして保存します 4. ソリューションエクスプローラー - MySudoku プロジェクトを選択し 右クリックし 追加 - 新しい項目 を選択します 5. 新しい項目の追加 ウゖンドウで XML フゔル のテンプレートを選択し フゔル名 に PuzzleData と入力し 追加 ボタンを押します 6. PuzzleData.xml のプロパテゖを設定します 出力デゖレクトリにコピー 新しい場合はコピーする 7. PuzzleData.xml に記述する内容は下記のようになります <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE sudoku [ <!ELEMENT sudoku (puzzle*)> <!ELEMENT puzzle (question, answer)> <!ELEMENT question (row*)> <!ELEMENT answer (row*)> <!ATTLIST puzzle id ID #REQUIRED> ]> <sudoku> <puzzle id="0"> <question> <row>,4,,,5,,,,</row> <row>5,,,9,2,,4,,8</row> <row>7,,2,6,,,1,,5</row> <row>,,,,,,,2,1</row> <row>,7,9,,,,,8,</row> <row>,6,5,,,,9,7,</row> <row>,8,1,,3,,,,9</row> 13
<row>,2,,,,8,3,,7</row> <row>3,5,,4,9,2,8,,6</row> </question> <answer> <row>8,4,6,3,5,1,7,9,2</row> <row>5,1,3,9,2,7,4,6,8</row> <row>7,9,2,6,8,4,1,3,5</row> <row>4,3,8,5,7,9,6,2,1</row> <row>1,7,9,2,4,6,5,8,3</row> <row>2,6,5,8,1,3,9,7,4</row> <row>6,8,1,7,3,5,2,4,9</row> <row>9,2,4,1,6,8,3,5,7</row> <row>3,5,7,4,9,2,8,1,6</row> </answer> </puzzle> <puzzle id="1"> <question> <row>,1,8,,,2,,,</row> <row>,5,3,,6,8,9,,</row> <row>,,,7,,,6,8,1</row> <row>,,,,7,,,,8</row> <row>,,,,4,,1,,9</row> <row>,,,8,1,,2,,5</row> <row>,9,,,5,1,,,6</row> <row>8,6,,9,2,,5,,</row> <row>5,,1,,,4,7,9,2</row> </question> <answer> <row>6,1,8,4,9,2,3,5,7</row> <row>7,5,3,1,6,8,9,2,4</row> <row>9,4,2,7,3,5,6,8,1</row> <row>1,2,6,5,7,9,4,3,8</row> <row>3,8,5,2,4,6,1,7,9</row> <row>4,7,9,8,1,3,2,6,5</row> <row>2,9,7,3,5,1,8,4,6</row> <row>8,6,4,9,2,7,5,1,3</row> <row>5,3,1,6,8,4,7,9,2</row> </answer> </puzzle> <puzzle id="2"> <question> <row>,,,,,6,,,</row> <row>,,,,1,,9,,7</row> <row>,,,7,9,,6,,4</row> <row>,,,,3,,,,9</row> <row>,7,4,2,6,,8,,3</row> 14
<row>5,,3,1,,,,4,6</row> <row>,1,6,,5,7,,,2</row> <row>,,7,9,2,,,6,8</row> <row>2,,9,,,1,,3,5</row> </question> <answer> <row>7,9,2,8,4,6,3,5,1</row> <row>4,6,8,5,1,3,9,2,7</row> <row>1,3,5,7,9,2,6,8,4</row> <row>6,2,1,4,3,8,5,7,9</row> <row>9,7,4,2,6,5,8,1,3</row> <row>5,8,3,1,7,9,2,4,6</row> <row>8,1,6,3,5,7,4,9,2</row> <row>3,5,7,9,2,4,1,6,8</row> <row>2,4,9,6,8,1,7,3,5</row> </answer> </puzzle> </sudoku> メソッドスタブの生成 8. XML フゔルのパズルの数を数えるために countpuzzles という名前のメソッドを作成します (countpuzzles の出力は整数のンスタンス変数 TotalPuzzles に割り当てます ) 参照される未定義の countpuzzles メッソドを定義するときには countpuzzles を右クリックし メソッドスタブの生成 を選択すると メソッドスタブが自動的に作成されます ( あるいは 下記のように 青いスマートタグをクリックします ) FrmSudoku.cs のコードが表示されない場合は FrmSudoku.cs[ デザン ] を選んで 表示 メニューの コード を選択してください 15
インテリセンス 9. XML フゔルを読むために XmlDocument クラスを用意します これを入力すると ンテリセンスが候補のクラスを表示してきます XmlDocument はンテリセンスの候補にはないので 赤いスマートタグをクリックし using System.Xml を追加します 10. そして ンテリセンスを使ってコードを書き終えます 11. 完成した countpuzzle メソッド ( 文字列定数 DATAPATH の値は PuzzleData.xml です ) private int countpuzzles() XmlDocument xd = new XmlDocument(); 1. Write code xd.load(datapath); to read and load data from PuzzleData.xml into dgvplayarea and 2. return xd.getelementsbytagname("puzzle").count; 3. 16
12. PuzzleData.xml から dgvplayarea と dgvanswer へデータを読み込むためのコードを書きます (btnnewgame_click の文字列のンスタンス変数 CurPuzzleID はランダムな ID を保存します ) private void btnnewgame_click(object sender, EventArgs e) CurPuzzleID = new Random().Next(TotalPuzzles).ToString(); loadpuzzle(); private void loadpuzzle() // リセット tbmessage.text = ""; if (dgvplayarea.rows.count > 0) for (int row = 0; row < 9; row++) dgvplayarea.rows.removeat(0); dgvanswer.rows.removeat(0); //PuzzleData.xmlからデータを抽出 XmlDocument xd = new XmlDocument(); xd.load(datapath); XmlElement xepuzzle = xd.getelementbyid(curpuzzleid); //DataGridView にゲームの情報を入力 foreach (XmlNode node in xepuzzle.firstchild.childnodes) dgvplayarea.rows.add(node.innertext.split(new char[] ',' )); //DataGridView に解答の情報を入力 foreach (XmlNode node in xepuzzle.childnodes[1].childnodes) dgvanswer.rows.add(node.innertext.split(new char[] ',' )); //dgvplayarea には初期値のセルをReadOnlyを設定 for (int row=0; row<9; row++) for (int col = 0; col < 9; col++) 17
DataGridViewCell cell = dgvplayarea[col, row]; if (!cell.value.equals("")) cell.readonly = true; cell.style.forecolor = Color.Blue; cell.style.font = new Font(cell.InheritedStyle.Font, FontStyle.Bold); //dgvplayarea を表示 dgvplayarea.visible = true; // 初期値のハラトされているセルを無効に dgvplayarea.currentcell = null; // タトルを更新 this.text = " 数独 [" + CurPuzzleID + "]"; 13. dgvplayarea と dgvanswer にカラーフレームを描くために それぞれに Paint ベントハンド ラを追加します そして 各 Paint ベントハンドラに drawframe メソッドを実行します ( 定 数 CELL_WIDTH と CELL_WIDTH_ANSWER の値はそれぞれ 40 と 20 です ) 18
private void dgvplayarea_paint(object sender, PaintEventArgs e) drawframe(e, CELL_WIDTH, Color.Red); private void dgvanswer_paint(object sender, PaintEventArgs e) drawframe(e, CELL_WIDTH_ANSWER, Color.Gray); private void drawframe(painteventargs e, int cellwidth, Color framecolor) Point curpoint = new Point(0, 0); Size size = new Size(cellWidth * 3, cellwidth * 3); Pen mypen = new Pen(frameColor, 3); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) curpoint.x = i * cellwidth * 3; curpoint.y = j * cellwidth * 3; Rectangle rect = new Rectangle(curPoint, size); e.graphics.drawrectangle(mypen, rect); 14. ユーザーが Delete キーか Back Space キーを押したときに 消す 処理のために dgvplayarea に KeyDown ベントハンドラを追加します private void dgvplayarea_keydown(object sender, KeyEventArgs e) if (dgvplayarea.currentcell.readonly == false && (e.keycode == Keys.Delete e.keycode == Keys.Back)) dgvplayarea.currentcell.value = ""; dgvplayarea.currentcell.style.backcolor = SystemColors.Window; isdirty = true; 19
15. FrmSudoku を開始したときに dgvplayarea と dgvanswer を非表示にさせておくように コンストラクターに下記のコードを追加します public FrmSudoku() InitializeComponent(); TotalPuzzles = countpuzzles(); //DataGridViewを隠す dgvplayarea.visible = false; dgvanswer.visible = false; 16. ゲームを実行すると 下記のように表示されます プロジェクトファイルのダウンロード 1 章と 2 章までのデザンとコーデゖングはこちらからダウンロードできます デザンとコードのダウンロード 環境によって FrmSudoku の表示が多少異なります サズ調整などを行ってください まとめ第 2 章では ベントハンドラを利用してゲーム開始の処理を作成し XML フゔルを使って問題データを画面に準備しました 次回 第 3 回目では 数独 のルールを実装してゲームを完成させます 20
第 3 回 Visual Studio 2008 でゲームを作る - 数独 を作ってみよう 3 - 数独 パズルを作ってみよう第 3 章 はじめに本章では 数独 のルールを設定して入力された値をチェックする機能を加えます ゲームの本質的な動作にあたる部分です 入力された値をチェックする 1. dgvplayarea に CellValueChanged のベントハンドラを追加する public FrmSudoku() InitializeComponent(); TotalPuzzles = countpuzzles(); //DataGridViewを隠す dgvplayarea.visible = false; dgvanswer.visible = false; dgvplayarea.cellvaluechanged +=new DataGridViewCellEventHandler(dgvPlayArea_CellValueChanged); 2. 主な 3 つのチェックの処理を作成します 1 数字であるかどうか :checkinputisnumber 2 行 列 ミニブロック内に数字の重複がないかどうか :checkhaveduplicates 3 すべてのセルが入力されたかどうか :checkhavecompleted 21
private void dgvplayarea_cellvaluechanged(object sender, DataGridViewCellEventArgs e) // メッセージをリセット tbmessage.text = ""; if (!dgvplayarea.currentcell.value.equals("")) if (checkinputisnumber() == true) checkhaveduplicates(); checkhavecompleted(); isdirty = true; checkinputisnumber private bool checkinputisnumber() string input = dgvplayarea.currentcell.value.tostring(); Regex r = new Regex("^[1-91-9]$"); if (!r.ismatch(input)) tbmessage.text = NOTNUMBER; dgvplayarea.currentcell.style.backcolor = Color.Red; return false; r = new Regex("^[1-9]$"); if (r.ismatch(input)) dgvplayarea.currentcell.value = input.replace('1', '1').Replace('2', '2').Replace('3', '3').Replace('4', '4').Replace('5', '5').Replace('6', '6').Replace('7', '7').Replace('8', '8').Replace('9', '9'); return true; 22
checkhaveduplicates private void checkhaveduplicates() bool hasduplicateinrow = false; bool hasduplicateincol = false; bool hasduplicateinbox = false; object input = dgvplayarea.currentcell.value; int currowindex = dgvplayarea.currentcell.rowindex; int curcolindex = dgvplayarea.currentcell.columnindex; // 当行を確認 for (int i = 0; i < 9; i++) if (dgvplayarea[i, currowindex].value.equals(input) && i!= curcolindex) tbmessage.text += " 行 " + (currowindex + 1) + SAMENUMBER; hasduplicateinrow = true; break; // 当列を確認 for (int i = 0; i < 9; i++) if (dgvplayarea[curcolindex, i].value.equals(input) && i!= currowindex) tbmessage.text += " 列 " + (curcolindex + 1) + SAMENUMBER; hasduplicateincol = true; break; //3x3 ミニブロックを確認 int blockx = curcolindex / 3; int blocky = currowindex / 3; for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) int curx = blockx * 3 + i; int cury = blocky * 3 + j; if (dgvplayarea[curx, cury].value.equals(input) &&!(curx == curcolindex && cury == currowindex)) 23
tbmessage.text += " ミニブロック [" + (blockx + 1) + "," + (blocky + 1) + "]" + SAMENUMBER; hasduplicateinbox = true; break; // 当セルを色付ける if (hasduplicateinrow == false && hasduplicateincol == false && hasduplicateinbox == false) dgvplayarea.currentcell.style.backcolor = SystemColors.Window; else dgvplayarea.currentcell.style.backcolor = Color.Red; checkhavecompleted private void checkhavecompleted() bool pass = true; // 各セルに値が入力されているかどうか エラーがないか を確認 for (int row = 0; row < 9; row++) for (int col = 0; col < 9; col++) if (dgvplayarea[col, row].value.equals("") dgvplayarea[col, row].style.backcolor.equals(color.red)) return; // 各セルには値があり かつエラーなし // 念のため 入力と解答が一致することを確認 for (int row = 0; row < 9; row++) for (int col = 0; col < 9; col++) if (!dgvplayarea[col, row].value.equals(dgvanswer[col, row].value)) dgvplayarea[col, row].style.backcolor = Color.Red; tbmessage.text += "[" + col + "," + row + "] の答えは違います \r\n"; pass = false; if (pass) tbmessage.text = " 正解! おめでとうございます!"; 24
3. 残りのボタンの Click ベントハンドラに 次の処理のコードを書く ( ゕ ) btnopengame_click: 保存データを開く ( ) btnsavegame_click: 現在のゲームデータを保存する ( ウ ) btnhint_click: 選んだセルの答えを表示する ( エ ) btnanswer_click: 答えの表示 / 非表示を切り替えるボタン ( ア )btnopengame_click private void btnopengame_click(object sender, EventArgs e) if (isdirty && getconfirmation(loadconfirm) == false) return; if (File.Exists(SAVEPATH)) XmlDocument xd = new XmlDocument(); xd.load(savepath); XmlNode xnpuzzle = xd.getelementsbytagname("puzzle")[0]; CurPuzzleID = xnpuzzle.attributes[0].value; loadpuzzle(); // 保存したゲームの状態によってdgvPlayAreaに入力 for (int row = 0; row < 9; row++) XmlNode node = xnpuzzle.childnodes[row]; string[] number = node.innertext.split(new char[] ',' ); for (int col = 0; col < 9; col++) if (dgvplayarea[col, row].value.equals("") &&!number[col].equals("")) dgvplayarea.currentcell = dgvplayarea[col, row]; dgvplayarea[col, row].value = number[col]; tbmessage.text = ""; dgvplayarea.currentcell = null; isdirty = false; else MessageBox.Show(" 保存したゲームはありません "); 25
( イ )btnsavegame_click private void btnsavegame_click(object sender, EventArgs e) if (getconfirmation(saveconfirm) == true) XmlWriterSettings settings = new XmlWriterSettings(); settings.indent = true; try // ファイルを作成 Writer を作成 FileStream fs = new FileStream(SAVEPATH, FileMode.Create); XmlWriter w = XmlWriter.Create(fs, settings); //xml の宣言を書く w.writestartdocument(); //DTD を書く //<!DOCTYPE save [ //<!ELEMENT save (puzzle*)> //<!ELEMENT puzzle (row*)> //<!ATTLIST puzzle id ID #REQUIRED> //]> string dtd = "<!ELEMENT save (puzzle*)>" + "<!ELEMENT puzzle (row*)>" + "<!ATTLIST puzzle id ID #REQUIRED>"; w.writedoctype("save", null, null, dtd); // 内容を書く w.writestartelement("save"); w.writestartelement("puzzle"); w.writeattributestring("id", CurPuzzleID); ","; for (int row = 0; row < 9; row++) string numbers = ""; for (int col = 0; col < 9; col++) numbers += dgvplayarea[col, row].value.tostring() + numbers = numbers.substring(0, numbers.length - 1); w.writestartelement("row"); w.writevalue(numbers); w.writeendelement(); //row w.writeendelement(); //puzzle w.writeendelement(); //save w.writeenddocument(); w.flush(); fs.close(); isdirty = false; catch (Exception ex) MessageBox.Show(ex.Message, " 保存失敗 ", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning); 26
( ウ )btnhint_click private void btnhint_click(object sender, EventArgs e) if (dgvplayarea.currentcell == null) MessageBox.Show(" セルを選択してください "); else if (!dgvplayarea.currentcell.readonly && getconfirmation(" 選択したセルの答えを表示しますか ")) dgvplayarea.currentcell.value = dgvanswer[dgvplayarea.currentcell.columnindex, dgvplayarea.currentcell.rowindex].value; ( エ )btnanswer_click private void btnanswer_click(object sender, EventArgs e) dgvanswer.visible =!dgvanswer.visible; dgvanswer.currentcell = null; 完成 完成した 数独 を実行してみましょう 本シリーズで完成したプロジェクトは こちらからダウンロードできます 第 3 章で完成したプロジェクトのダウンロード 27
環境によって FrmSudoku の表示が多少異なります サズ調整などを行ってください まとめ本シリーズでは Visual Studio 2008 (C#) を使って 数独 パズルをプログラミングしてみました 一連の流れの中で フォーム ベントハンドラ XML フゔルのリード 入力判定など ソフトウェゕでよく使われる基本的なプログラミング手法を学習しました ここで作成したソースコードを参考にして また 新たなプログラムに挑戦してみてください 28