やじゅ@アプリケーション・ラボ わんくま支局

目次

Blog 利用状況

ニュース

プロフィール

MSMVP

[VB]遅れてやってきたYield その3

これは、Visual Basic Advent Calendar 2012 12/11日の記事。

Yieldの特徴として、関数の実行を一時的に中断しておいて、次回にその関数が呼び出されたときにその続きを実行する機能があります。
これはSchemeで言うcontinuation(継続)である。

継続 continuation
http://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A

今までのその1その2では、「Yield 式」にて式には値を使用してリスト生成しておりましたが、式には値以外の匿名メソッドを使用することが出来るため、今回はそれを使ったサンプルとしてゲームを作成してみました。

今回のYieldネタを書くにあたってネット検索した際に、やねうらお氏の下記の記事を参考にしようと考えたしだいです。
記事には無名delegate本体のなかでdelegateを設定する例を示しておりますが、今回あえてYieldで作成してみました。

C#2.0時代のゲームプログラミング(49) ~ delegateを用いたcontinuation
http://d.hatena.ne.jp/yaneurao/20070207
”ウィンドウ内にダイアログを(DirectXやら何やらを用いて)自前で描画したい。
ダイアログは「はい」「いいえ」ボタンがあり、そこがクリックされたときにハンドラが呼び出されるコードはすでに書いてある。
「それでファイナルアンサー?」のダイアログを表示して、「はい」が押されれば「ここでやめたら250万円持ち帰れますがいいんですね?」のダイアログを表示する。さらに「はい」が押されれば「ファイナルアンサー?」と表示する。さらに「はい」が押されたら「残念」と表示する。
このようなプログラムは、常識的には、1度目の「はい」が押された状態と2度目の「はい」が押された状態、3度目の「はい」が押された状態etc..に状態番号(か何か)を割り振り、その状態番号に応じてswitch~caseで処理するコードをどこかに書く必要がある。”


「クイズ$ミリオネア」と違って、問題は4択ではなく乱数値が上か下かを選択する2択になっております。
また、クイズ問題以外で「いいえ」を選択すると、ゲームが終了してしまうのはご愛嬌ってことで…。
匿名メソッドを使わなくても、Yieldの前に処理を書いてしまっても同様なことが出来るのですが、あえて勉強もかねて使っております。

 

Public Class question
    Public Property money As Integer
    Public Property quiz As String
    Public Property value As Integer
End Class

Public Class Form1

    Private Delegate Function DelegateType(i As Integer) As DialogResult
    Private rnd As Random = New Random()

    Private questionList As New List(Of question) From
        {New question() With {.money = 1, .quiz = "乱数値は{0}以下である", .value = 10},
         New question() With {.money = 2, .quiz = "乱数値は{0}以下である", .value = 20},
         New question() With {.money = 3, .quiz = "乱数値は{0}以下である", .value = 30},
         New question() With {.money = 5, .quiz = "乱数値は{0}以下である", .value = 40},
         New question() With {.money = 100, .quiz = "乱数値は{0}以下である", .value = 50},
         New question() With {.money = 150, .quiz = "乱数値は{0}以下である", .value = 60},
         New question() With {.money = 250, .quiz = "乱数値は{0}以下である", .value = 70},
         New question() With {.money = 500, .quiz = "乱数値は{0}以下である", .value = 80},
         New question() With {.money = 750, .quiz = "乱数値は{0}以下である", .value = 90},
         New question() With {.money = 1000, .quiz = "乱数値は{0}以下である", .value = 100}
        }

    Private Function YesNoDialog(message As String, Optional title As String = "確認") As DialogResult

        Return MessageBox.Show(message, title,
                              MessageBoxButtons.YesNo,
                              MessageBoxIcon.Question,
                              MessageBoxDefaultButton.Button2)

    End Function

    Private Function QestionDialog(i As Integer) As DialogResult

        Dim message As String

        message = String.Format("【{0}万円の問題】" & vbCrLf & "{1}",
                                questionList(i).money, String.Format(questionList(i).quiz, questionList(i).value / 2))

        YesNoDialog(message, String.Format("第{0}問", i + 1))

        Return Windows.Forms.DialogResult.Yes

    End Function


    Private Function AnswerDialog(i As Integer) As DialogResult

        Dim result As DialogResult
        Dim answer As Integer = rnd.Next(1, questionList(i).value)

        If answer <= questionList(i).value / 2 Then
            MessageBox.Show("正解")
            result = Windows.Forms.DialogResult.Yes
        Else
            MessageBox.Show(String.Format("残念 正解は{0}でした", answer))
            If i > 0 Then
                MessageBox.Show(String.Format("獲得賞金 {0}万円", questionList(i - 1).money))
            End If
            result = Windows.Forms.DialogResult.No
        End If

        Return result

    End Function

    Private Iterator Function FinalAnswer(i As Integer) As IEnumerable(Of DelegateType)

        Yield Function() QestionDialog(i)
        If i > 0 Then
            Yield Function() YesNoDialog("それでファイナルアンサー?")
            Yield Function() YesNoDialog(String.Format("ここでやめたら{0}万円持ち帰れますがいいんですね?", questionList(i - 1).money))
        End If
        Yield Function() YesNoDialog("ファイナルアンサー?")
        Yield Function() AnswerDialog(i)

    End Function

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        For i As Integer = 0 To questionList.Count - 1
            Dim statementList As IEnumerable(Of DelegateType) = FinalAnswer(i)
            For Each statement As DelegateType In statementList
                If statement(i) = Windows.Forms.DialogResult.No Then
                    Exit Sub
                End If
            Next
        Next

        MessageBox.Show(String.Format("獲得賞金 {0}万円 おめでとう", questionList(questionList.Count - 1).money))

    End Sub

End Class


次回は、Yieldの特徴を利用して線を描画する簡易グラフィックエディタを作成してみます。

投稿日時 : 2012年12月11日 22:21

コメントを追加

No comments posted yet.
タイトル
名前
URL
コメント