Visual Studio 2008 でゲームを作ろう
- 気軽に始めるプログラミング -
第 1 回
Visual Studio 2008 でゲームを作る
- 「数独」を作ってみよう ① -
■はじめに
本シリーズは全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 にゕクセスする
ダウンロードしたフゔルを実行し、下記のVisual Studio 2008 セットゕップ画面が表示すれば、
「次へ」ボタンを押します。
「同意する」を選択し、DreamSparkから発行されたプロダクトキーと名前を入力します。そして、
「次へ」のボタンを押します。
ンストールが終わったら、「完了」ボタンを押す前に、Visual Studio 2008 の更新プログラムを確
認することをお勧めします。「セキュリテゖ メモ」のWindows Update Web サトにゕクセスして
ください。
DreamSpark では、Visual Studio の他にも Windows Server、Expression などの製品を無償でダ
ウンロードできます。→Dream Spark の提供製品
■「数独」パズルのルール
本シリーズでは、実際に「数独」パズルを作ってみますが、「数独」というパズルゲームをご存じな
い方のために、今回はまずこの「数独」についてご説明しておきましょう。
「数独」ルール
上記のような 9 行× 9 列のマス目の空欄のすべてを、下記の 3 つの条件に沿って 1 ~ 9 の数字
で埋めていきます。
<条件>
・ 同じ横一行には同じ数字は入りません。
・ 同じ縦一列にも同じ数字は入りません。
・ 赤線で囲まれた 3 × 3 の各ミニブロックにも同じ数字は入りません。
■「数独」ゲームを作ってみよう
では実際に Visual Studio 2008 を使って「数独」を作ってみましょう。
ひとつひとつの工程を完璧に理解できなくても、ひととおり手順に従って作成してみてください。何
をすれば、どのようになるのかを体感してみることで、プログラミングの流れを理解できるようにな
ります。
第 1 章「数独」を作ってみよう ①
■ イントロダクション
今回は Visual Basic (VB) を使って下記のような「数独」ゲームを作成してみましょう。
■ プロジェクトを作成する
Visual Studio 2008 を起動したら、以下の手順に従って、プロジェクトを新規作成します。
1. 「フゔル」-「新規作成」-「プロジェクト」を選択します。
※あるいは、ツールバーの
をクリックします。
2. 「新しいプロジェクト」ウゖンドウの右上で、.NET Framework のバージョンを設定できます
( Visual Studio 2008 の新しい機能です )。今回は「.NET Framework 3.5」をそのまま選択し
ておきます。
3. 「プロジェクト名」の欄を “MySudoku” と変更し「OK」をクリックします。
4. Form1.vb が自働的に作成されます。フォームは、ユーザーンターフェースになる部分です。
フ ォ ー ム の 名 前 を わ か り や す く す る た め に 、 “ FrmSudoku.vb ” に 変 更 し ま す 。
「ソリューションエクスプローラー」ウゖンドウの Form1.vb を選択して F2 キーを押し、
“FrmSudoku.vb” へ変更します。
5. フォームのサズを丁度良い大きさに変更します。「プロパテゖ」ウゖンドウが表示されていない
場合は「表示」メニューの「プロパテゖウゖンドウ」をクリックして開きます。そして、下記のプ
ロパテゖを編集します。
ShowIcon
False
Size
Width
Height
600
500
Text
数独
■ コントロールを追加する
6. DataGridView、ボタンなどのコントロールを FrmSudoku.vb[デザン]に追加します。マウスを
「ツールボックス」に近づけるとツールボックスの内容が表示されます。
を押すと、ツール
ボックスの内容がそのまま表示されます。
7. 「ツールボックス」-「データ」-「DataGridView」を選択してドラッグし、FrmSudoku.vb[デ
ザン]にドロップします。そして、DataGridView のプロパテゖを変更します。dgvPlayArea は
「数独」のゲーム画面の表示(と入力)部分です。
(Name)
dgvPlayArea
AllowUserToAddRows
False
AllowUserToDeleteRows
False
AllowUserToResizeColumns
False
AllowUserToResizeRows
False
EditMode
EditOnKeystroke
ScrollBars
None
Size
364,363
BorderStyle
None
ColumnHeadersVisible
False
DefaultCellStyle
( をクリックして CellStyle ビルダを開
きます。下記の図を参照)
Alignment: MiddleCenter
Font:MS UI Gothic, 24pt
RowHeadersVisible
False
RowTemplate
Height
40
8. DataGridView に列を追加します。[デザン]ウゖンドウの dgvPlayArea を選択し、 をクリッ
クして「DataGridView タスク」を開きます。
9. 「列の編集」ウゖンドウが表示されたら、「追加」ボタンをクリックすると「列の追加」ウゖンド
ウが表示されます。
10. 「列の追加」ウゖンドウで、列を追加します。今回は、名前と型はデフォルト値のまま利用します
(デフォルトの型:「DataGridViewTextColumn」)。9つの列を作成するので、「追加」ボタ
ンを 9 回押します。列の追加が終わったら「キャンセル」ボタンを押します。
11. 「列の編集」ウゖンドウで、各列のプロパテゖを下記のように設定します。
MaxInputLength
1
Width
40
12. これで dgvPlayArea の設定が完了しました。解答のエリゕのためにもうひとつ DataGridView
を用意する必要があります。この作業を楽にするために、先ほど作成した dgvPlayArea をコピー
ゕンド ペーストして、プロパテゖを必要な箇所だけ変更します。
(Name)
dgvAnswer
ReadOnly
true
Size
182,182
DefaultCellStyle
Font:MS UI Gothic, 12pt
RowTemplate
Height
20
13. dgvAnswer の「DataGridView タスク」から、列の Width を編集します。
Width
20
14. 「TextBox」コントロールを追加して、プロパテゖを編集します。
15. 「Button」コントロールを 5 つ追加し、プロパテゖを編集します。
(Name)
btnNewGame
Width
100
Text
ニューゲーム
(Name)
btnOpenGame
Width
100
Text
ゲームを開く
(Name)
btnSaveGame
Width
100
Text
ゲームを保存
(Name)
btnHint
Width
100
Text
ヒント
(Name)
btnAnswer
(Name)
tbMessage
Multiline
True
ReadOnly
True
Size
364,60
([デザン]のTextBoxを選択し、角をドラッグするとリ サズできます)Width
100
Text
解答
16. 最後に、各コントロールの TabIndex プロパテゖを設定します。
■ 実行する
17. 「デバッグ」メニューの「デバッグ開始」を選択して、ゲームを実行します(あるいは、F5 キー
を押して実行します)。ここでは、「数独」はまだ表示されません。
■ プロジェクトファイルのダウンロード
ここで使用したプロジェクトフゔルは、こちらからダウンロードできます。
→プロジェクトフゔルのダウンロード
※ 環境によって、FrmSudoku の表示が多少異なります。サズなど微調整してください。
btnNewGame
0
btnOpenGame
1
btnSaveGame
2
btnHint
3
btnAnswer
4
dgvPlayArea
5
tbMessage
6
dgvAnswer
7
■ まとめ
第 1 章では、「数独」パズルを表示するフォームを作成し、各コントロールのプロパテゖの設定を学
習しました。次回は、何かの事象が起こったら特定の処理を実行する「ベント ハンドラ」について
学習し、また、パズル中のデータを保管する XML フゔルの作成方法を学びます。
第 2 回
Visual Studio 2008 でゲームを作る
- 「数独」を作ってみよう ② -
「数独」パズルを作ってみよう 第 2 章
■ はじめに
第 1 章では「数独」パズルを表示するフォームを作成しました。この章では「ニューゲーム」ボタン
をクリックしてゲームを開始する、パズルに問題となる数字を表示させるようにします。
そのために、次の 3 つのことを行います。
(a) btnNewGame にベントハンドラを追加する
(b) 「数独」パズルのデータを保管するために XML フゔルを作成する
(c) XMLフゔルを読んで dgvPlayArea と dgvAnswer にデータを入力します。
■ イベントハンドラの追加
1. ボタンの Click ベントの処理を作成するには、二つの方法があります。ボタンのデフォルトベ
ントは Click なので、FrmSudoku.vb[デザン]にあるボタンをダブルクリックすると、ベント
ハンドラーが自働作成されます。(※FrmSudoku.vb[デザン]が表示されていない場合は、「ソ
リューション エクスプローラー」の FrmSudoku.vb をダブルクリックしてください)。
2. 各ボタンの Click ベントに処理を追加します。
■ XMLファイルの新規作成
3. ゲームの情報は XML フゔルとして保存します。
4. 「ソリューション エクスプローラー」-「MySudoku」プロジェクトを選択し、右クリックし、
「追加」-「新しい項目」を選択します。
5. 「新しい項目の追加」ウゖンドウで「XML フゔル」のテンプレートを選択し、「フゔル名」
に “PuzzleData” と入力し「追加」ボタンを押します。
6. PuzzleData.xml のプロパテゖを設定します。
出力デゖレクトリにコピー
新しい場合はコピーする
7. PuzzleData.xml に記述する内容は下記のようになります。
<?xmlversion="1.0" encoding="utf-8" ?> <!DOCTYPEsudoku [
<!ELEMENTsudoku (puzzle*)> <!ELEMENTpuzzle (question, answer)> <!ELEMENTquestion (row*)>
<!ELEMENTanswer (row*)>
<!ATTLISTpuzzleid ID #REQUIRED> ]> <sudoku> <puzzleid="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>
<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> <puzzleid="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> <puzzleid="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>
■ コンストラクター、Subプロシージャ、関数の生成
8. 今回の開発には初期化が必要なので、コンストラクターの中に Sub プロシージャなどを追加しま
す。通常、コンストラクターはコードに表示されていません。「Public Sub New()」を入力して、
「Enter」キーを押すことで、コンストラクターが完成します
※FrmSudoku.vb のコードが表示されない場合は、FrmSudoku.vb[デザン]を選んで、「表
示」メニューの「コード」を選択してください。
9. コンストラクターには、XML フゔルのパズルの数を数えるために「countPuzzles」という関数
を追加します(countPuzzles の出力は整数のンスタンス変数 TotalPuzzles に割り当てます)。
<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> 「Enter」キーを押すと■ インテリセンス
10. XML フゔルを読むために XmlDocument クラスを用意します。「XmlDocument」を入力し
ている途中で、ンテリセンスが候補のクラスを表示してきます。この中に利用したいクラスがあ
れば、それを選択して、タブキーを押すと、コードとクラスが自働的に追加されます。
11. XmlDocument はンテリセンスの候補にはないので、最後まで、手動で入力して、赤いスマー
トタグをクリックし、「!」をクリックし、「System.Xml をンポートします。」を選択すると、
「Imports System.Xml」が追加されます。
「Enter」キーを押すと12. 完成した countPuzzle 関数(文字列定数 DATAPATH の値は「”PuzzleData.xml”」です)。
1. Write code to read and load data from PuzzleData.xml into dgvPlayArea and
2.
3.
PrivateFunction countPuzzles() AsInteger
Dim xd AsNew XmlDocument() xd.Load(DATAPATH)
Return xd.GetElementsByTagName("puzzle").Count
13. PuzzleData.xml から dgvPlayArea と dgvAnswer へデータを読み込むためのコードを書きま
す。(btnNewGame_Click の文字列のンスタンス変数 CurPuzzleID はランダムな ID を保存
します)。
PrivateSub btnNewGame_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnNewGame.Click
CurPuzzleID = New Random().Next(TotalPuzzles).ToString() loadPuzzle()
EndSub
PrivateSub loadPuzzle()
' リセット
tbMessage.Text = ""
If dgvPlayArea.Rows.Count > 0 Then
For row AsInteger = 0 To 8
dgvPlayArea.Rows.RemoveAt(0) dgvAnswer.Rows.RemoveAt(0) Next row
EndIf
' PuzzleData.xmlからデータを抽出
Dim xd AsNew XmlDocument() xd.Load(DATAPATH)
Dim xePuzzle As XmlElement = xd.GetElementById(CurPuzzleID) ' DataGridViewにゲームの情報を入力
ForEach node As XmlNode In xePuzzle.FirstChild.ChildNodes
dgvPlayArea.Rows.Add(node.InnerText.Split(New [Char]() {","c})) Next
' DataGridViewに解答の情報を入力
ForEach node As XmlNode In xePuzzle.ChildNodes(1).ChildNodes dgvAnswer.Rows.Add(node.InnerText.Split(New [Char]() {","c})) Next
' dgvPlayAreaにある初期値したセルをReadOnlyに設定
For row AsInteger = 0 To 8 For col AsInteger = 0 To 8
Dim cell As DataGridViewCell = dgvPlayArea(col, row) IfNot cell.Value.Equals("") Then
cell.ReadOnly = True
cell.Style.ForeColor = Color.Blue
cell.Style.Font = New Font(cell.InheritedStyle.Font, FontStyle.Bold) EndIf
14. dgvPlayArea と dgvAnswer にカラーフレームを描くために、それぞれに Paint ベントハンド
ラを追加します。そして、各 Paint ベントハンドラに drawFrame Sub プロシージャを実行し
ます(定数 CELL_WIDTH と CELL_WIDTH_ANSWER の値はそれぞれ「40」と「20」です)。
Next col Next row ' dgvPlayAreaを表示 dgvPlayArea.Visible = True ' 初期のセルハラトを無効に dgvPlayArea.CurrentCell = Nothing dgvAnswer.CurrentCell = Nothing ' タトルを更新MyBase.Text = "数独[" + CurPuzzleID + "]"
EndSub
PrivateSub dgvPlayArea_Paint(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles dgvPlayArea.Paint drawFrame(e, CELL_WIDTH, Color.Red)
EndSub
PrivateSub dgvAnswer_Paint(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles dgvAnswer.Paint drawFrame(e, CELL_WIDTH_ANSWER, Color.Gray)
EndSub
PrivateSub drawFrame(ByVal e As PaintEventArgs, ByVal cellWidth AsInteger, ByVal
frameColor As Color)
Dim curPoint As Point = New Point(0, 0)
Dim size As Size = New Size(cellWidth * 3, cellWidth * 3) Dim myPen As Pen = New Pen(frameColor, 3)
For i AsInteger = 0 To 2 For j AsInteger = 0 To 2
curPoint.X = i * cellWidth * 3 curPoint.Y = j * cellWidth * 3
Dim rect As Rectangle = New Rectangle(curPoint, size) e.Graphics.DrawRectangle(myPen, rect)
Next j Next i
15. ユーザーが 「Delete」キーか「Back Space」キーを押したときに “消す” 処理のために、
dgvPlayArea に KeyDown ベントハンドラを追加します。
16. FrmSudoku を開始したときに dgvPlayArea と dgvAnswer を非表示にさせておくように、コ
ンストラクターに下記のコードを追加します。
17. ゲームを実行すると、下記のように表示されます。
PrivateSub dgvPlayArea_KeyDown(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.KeyEventArgs) Handles dgvPlayArea.KeyDown
If dgvPlayArea.CurrentCell.ReadOnly = FalseAndAlso (e.KeyCode = Keys.Delete OrElse
e.KeyCode = Keys.Back) Then
dgvPlayArea.CurrentCell.Value = ""
dgvPlayArea.CurrentCell.Style.BackColor = SystemColors.Window isDirty = true
EndIf
EndSub
PublicSubNew()
' この呼び出しは、Windows フォーム デザナで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 TotalPuzzles = countPuzzles() ' DataGridViewを隠す dgvPlayArea.Visible = False dgvAnswer.Visible = False EndSub
■ プロジェクトファイルのダウンロード
1 章と 2 章までのデザンとコーデゖングはこちらからダウンロードできます。
→デザンとコードのダウンロード
※環境によって、FrmSudoku の表示が多少異なります。サズ調整などを行ってください。
■ まとめ
第 2 章では、ベントハンドラを利用してゲーム開始の処理を作成し、XML フゔルを使って問題
データを画面に準備しました。次回、第 3 回目では「数独」のルールを実装してゲームを完成させま
す。
第 3 回
Visual Studio 2008 でゲームを作る
- 「数独」を作ってみよう ③ -
「数独」パズルを作ってみよう 第 3 章
■ はじめに
本章では、「数独」のルールを設定して入力された値をチェックする機能を加えます。ゲームの本質
的な動作にあたる部分です。
■入力された値をチェックする
1. dgvPlayArea に CellValueChanged のベントハンドラを追加する。
2. 主な 3 つのチェックの処理を作成します。
① 数字であるかどうか:checkInputIsNumber
② 行・列・ミニブロック内に数字の重複がないかどうか:checkHaveDuplicates
③ すべてのセルが入力されたかどうか:checkHaveCompleted
PrivateSub dgvPlayArea_CellValueChanged(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvPlayArea.CellValueChanged If canExecuteEventHandler Then
' メッセージをリセット
tbMessage.Text = ""
IfNot dgvPlayArea.CurrentCell.Value.Equals("") Then
If checkInputIsNumber() = TrueThen
checkHaveDuplicates() checkHaveCompleted() EndIf isDirty = True EndIf EndIf EndSub
checkInputIsNumber
checkHaveDuplicates
PrivateFunction checkInputIsNumber()
Dim input AsString = dgvPlayArea.CurrentCell.Value.ToString() Dim r As Regex = New Regex("^[1-91-9]$")
IfNot r.IsMatch(input) Then
tbMessage.Text = NOTNUMBER dgvPlayArea.CurrentCell.Style.BackColor = Color.Red ReturnFalse EndIf r = New Regex("^[1-9]$") If r.IsMatch(input) Then dgvPlayArea.CurrentCell.Value = input.Replace("1"c, "1"c) _ .Replace("2"c, "2"c) _ .Replace("3"c, "3"c) _ .Replace("4"c, "4"c) _ .Replace("5"c, "5"c) _ .Replace("6"c, "6"c) _ .Replace("7"c, "7"c) _ .Replace("8"c, "8"c) _ .Replace("9", "9"c) EndIf ReturnTrue EndFunction
PrivateSub checkHaveDuplicates()
Dim hasDuplicateInRow AsBoolean = False
Dim hasDuplicateInCol AsBoolean = False
Dim hasDuplicateInBox AsBoolean = False
Dim input AsObject = dgvPlayArea.CurrentCell.Value
Dim curRowIndex AsInteger = dgvPlayArea.CurrentCell.RowIndex Dim curColIndex AsInteger = dgvPlayArea.CurrentCell.ColumnIndex ' 当行を確認
For i AsInteger = 0 To 8
If dgvPlayArea(i, curRowIndex).Value.Equals(input) AndAlso i <> curColIndex Then
tbMessage.Text += "行" + (curRowIndex + 1).ToString() + SAMENUMBER hasDuplicateInRow = True
ExitFor
EndIf
' 当列を確認
For i AsInteger = 0 To 8
If dgvPlayArea(curColIndex, i).Value.Equals(input) AndAlso i <> curRowIndex Then
tbMessage.Text += "列" + (curColIndex + 1).ToString() + SAMENUMBER hasDuplicateInCol = True
ExitFor
EndIf
Next i
' 3x3ミニブロックを確認
Dim blockX AsInteger = Math.Floor(curColIndex / 3) Dim blockY AsInteger = Math.Floor(curRowIndex / 3) For i AsInteger = 0 To 2
For j AsInteger = 0 To 2
Dim curX AsInteger = blockX * 3 + i Dim curY AsInteger = blockY * 3 + j
If (dgvPlayArea(curX, curY).Value.Equals(input) AndAlsoNot (curX = curColIndex
AndAlso curY = curRowIndex)) Then
tbMessage.Text += "ミニブロック[" + (blockX + 1).ToString() + "," + (blockY + 1).ToString() + "]" + SAMENUMBER hasDuplicateInBox = True ExitFor EndIf Next j Next i ' 当セルを色付ける
If hasDuplicateInRow = FalseAndAlso _ hasDuplicateInCol = FalseAndAlso _ hasDuplicateInBox = FalseThen
dgvPlayArea.CurrentCell.Style.BackColor = SystemColors.Window Else
dgvPlayArea.CurrentCell.Style.BackColor = Color.Red EndIf
checkHaveCompleted
3. 残りのボタンの Click ベントハンドラに、次の処理のコードを書く。
(ゕ) btnOpenGame_Click:保存データを開く
() btnSaveGame_Click:現在のゲームデータを保存する
(ウ) btnHint_Click:選んだセルの答えを表示する
(エ) btnAnswer_Click:答えの表示/非表示を切り替えるボタン
PrivateSub checkHaveCompleted()Dim pass AsBoolean = True
' 各セルに値が入力されているかどうか、エラーがないか、を確認
For row AsInteger = 0 To 8 For col AsInteger = 0 To 8
If dgvPlayArea(col, row).Value.Equals("") OrElse _
dgvPlayArea(col, row).Style.BackColor.Equals(Color.Red) Then
Return EndIf Next col Next row ' 各セルには値があり、かつエラーなし、 ' 念のため、入力と解答を一致することを確認
For row AsInteger = 0 To 8 For col AsInteger = 0 To 8
IfNot dgvPlayArea(col, row).Value.Equals(dgvAnswer(col, row).Value) Then
dgvPlayArea(col, row).Style.BackColor = Color.Red
tbMessage.Text += "[" + col.ToString() + "," + row.ToString() + "]の答えは違います。" + vbCrLf
pass = False
EndIf
Next col Next row
If pass Then tbMessage.Text = "正解!おめでとうございます!"
(ア)btnOpenGame_Click
PrivateSub btnOpenGame_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnOpenGame.Click
If isDirty AndAlso getConfirmation(LOADCONFIRM) = FalseThen
Return
EndIf
If File.Exists(SAVEPATH) Then
Dim xd As XmlDocument = New XmlDocument() xd.Load(SAVEPATH)
Dim xnPuzzle As XmlNode = xd.GetElementsByTagName("puzzle")(0) CurPuzzleID = xnPuzzle.Attributes(0).Value
loadPuzzle()
' 保存したゲームの状態によってdgvPlayAreaに入力
For row AsInteger = 0 To 8
Dim node As XmlNode = xnPuzzle.ChildNodes(row)
Dim number() AsString = node.InnerText.Split(New [Char]() {","c}) For col AsInteger = 0 To 8
If dgvPlayArea(col, row).Value.Equals("") AndAlso _ Not number(col).Equals("") Then
dgvPlayArea.CurrentCell = dgvPlayArea(col, row) dgvPlayArea(col, row).Value = number(col) EndIf Next col Next row tbMessage.Text = "" dgvPlayArea.CurrentCell = Nothing isDirty = False Else MessageBox.Show("保存したゲームはありません。") EndIf EndSub
(イ)btnSaveGame_Click
PrivateSub btnSaveGame_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnSaveGame.Click
If getConfirmation(SAVECONFIRM) = TrueThen
Dim settings As XmlWriterSettings = New XmlWriterSettings() settings.Indent = True
Try
' フゔルを作成、Writerを作成
Dim fs As FileStream = New FileStream(SAVEPATH, FileMode.Create) Dim w As XmlWriter = XmlWriter.Create(fs, settings)
' xmlの宣言を書く
w.WriteStartDocument() ' DTDを書く
' <!DOCTYPE save [
' <!ELEMENT save (puzzle*)>
' <!ELEMENT puzzle (row*)>
' <!ATTLIST puzzle id ID #REQUIRED>
' ]>
Dim dtd AsString = "<!ELEMENT save (puzzle*)>" + _ "<!ELEMENT puzzle (row*)>" + _ "<!ATTLIST puzzle id ID #REQUIRED>"
w.WriteDocType("save", Nothing, Nothing, dtd) ' 内容を書く
w.WriteStartElement("save") w.WriteStartElement("puzzle")
w.WriteAttributeString("id", CurPuzzleID) For row AsInteger = 0 To 8
Dim numbers AsString = ""
For col AsInteger = 0 To 8
numbers += dgvPlayArea(col, row).Value.ToString() + ","
Next col
numbers = numbers.Substring(0, numbers.Length - 1) w.WriteStartElement("row") w.WriteValue(numbers) w.WriteEndElement() 'row Next row w.WriteEndElement() 'puzzle w.WriteEndElement() 'save w.WriteEndDocument() w.Flush() fs.Close() isDirty = False Catch ex As Exception MessageBox.Show(ex.Message, "保存失敗", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning) EndTry EndIf EndSub
(ウ)btnHint_Click
(エ)btnAnswer_Click
■ 完成
完成した「数独」を実行してみましょう。
本シリーズで完成したプロジェクトは、こちらからダウンロードできます。
→第 3 章で完成したプロジェクトのダウンロード
※環境によって、FrmSudoku の表示が多少異なります。サズ調整などを行ってください。
PrivateSub btnHint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnHint.Click
If dgvPlayArea.CurrentCell IsNothingThen
MessageBox.Show("セルを選択してください。") Else
IfNot dgvPlayArea.CurrentCell.ReadOnly AndAlso _
getConfirmation("選択したセルの答えを表示しますか。") Then dgvPlayArea.CurrentCell.Value = _ dgvAnswer(dgvPlayArea.CurrentCell.ColumnIndex, dgvPlayArea.CurrentCell.RowIndex).Value EndIf EndIf EndSub
PrivateSub btnAnswer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles btnAnswer.Click
dgvAnswer.Visible = Not dgvAnswer.Visible dgvAnswer.CurrentCell = Nothing