スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門 Windowsアプリケーション編 ListBox(3)

今回はListBoxを利用して、次のようなアプリを作成してみたいと思います。 
 
814-1.jpg 



814-2.jpg 



814-3.jpg 

まず、スーツ、カード、ブラックジャックの結果をDiscriminated Unionを使って定義しておきます。
 
type CardSuit = 
    | Spade 
    | Club 
    | Diamond 
    | Heart 
    
    override this.ToString()=
        match this with
        |Spade -> "?"  //文字コードの関係でここでは正常に表示されていませんが、スペードマークです。
        | Club -> "?"
        | Diamond -> "?"
        | Heart -> "?"
 
type Card = 
    | Ace of CardSuit 
    | King of CardSuit 
    | Queen of CardSuit 
    | Jack of CardSuit 
    | NumCard of int * CardSuit 
 
    member this.valueBJ = 
        match this with 
        | NumCard (x,_) -> [x] 
        | Ace (_)       -> [1;11]  //エースは1と11の二通りの可能性がある
        | _             -> [10] 
 
    override this.ToString()=
        match this with
        | Ace(s)   -> s.ToString() + "A"
        | King(s)  -> s.ToString() + "K" 
        | Queen(s) -> s.ToString() + "Q"
        | Jack(s)  -> s.ToString() + "J"
        |NumCard(num,s) -> s.ToString() + num.ToString()
 
 
//setEleToStr (Set [6]) で "6"という文字列 ,setEleToStr (Set [3;4;5])で”3か4か5"という文字列を返す
//下のBJResult型用のヘルパー関数
let setEleToStr (iSet:Set<int>) =
    if Set.count iSet = 0 then
        failwith "this cannot happen" //実際には使われない
    else
      if  Set.count iSet = 1 then
            (List.head (Set.toList iSet)).ToString()
      else
        let iLst = Set.toList iSet
        iLst 
        |> List.map (fun i -> i.ToString())
        |> List.reduce (fun s i -> s + "か" + i.ToString())
 
type BJResult =
    | Over
    | BlackJack
    | Under of (Set<int>)
    
    member this.resultString =
        match this with
        | Over -> "残念です。バーストしました。"
        | BlackJack ->"おめでとうございます。ブラックジャックです。"
        | Under (iSet)  -> sprintf "ブラックジャックまであと%sです。" (setEleToStr iSet)
        
 
次に総当たり関数を定義しておきます。
 
> let crossProduct (ingred : 'a list list) = 
    let rec product rem res = 
        match rem with 
        | [] -> res 
        | h ::tl -> product tl [for i in h do for j in res do yield (i :: j) ]  
 
    product (ingred.Tail) (List.map (fun x -> [x]) ingred.Head) 
    |> List.map (fun lst -> List.rev lst)  ;;
 
val crossProduct : 'a list list -> 'a list list
 
(実行例)
> crossProduct [[1;2];[9;10;11]];;
val it : int list list = [[1; 9]; [2; 9]; [1; 10]; [2; 10]; [1; 11]; [2; 11]]
 
Cardのリストを引数としてとりうる値のすべての場合を返す関数を定義します。
 
> let getPossibleNumList (cards:list<Card>) =
     cards
     |> List.map(fun c -> c.valueBJ)
     |> crossProduct;;
 
val getPossibleNumList : Card list -> int list list
 
(実行例)
> getPossibleNumList [Ace(Spade);Ace(Heart);NumCard(3,Spade)];;
 
val it : int list list = [[1; 1; 3]; [11; 1; 3]; [1; 11; 3]; [11; 11; 3]]
 
次に[[1; 1; 3]; [11; 1; 3]; [1; 11; 3]; [11; 11; 3]]のようなリストから、BJResult型の値を返す関数を定義します。
 
> let judgeBJ (numLstLst :list<list<int>>) =
    let sumSet = 
        numLstLst
        |> List.map (fun lst -> List.sum lst) //ここまでで、和のリスト[5;15;15;25]ができあがる
        |> Set.ofList
    let  result =
        if Set.exists (fun n -> n = 21) sumSet then
            BlackJack
        else
            if Set.minElement sumSet > 21 then
                Over
            else
               let under21s  = Set.filter (fun n -> n < 21) sumSet
               Under(Set.map (fun n -> 21 - n) under21s) //21まであといくつかのリスト
    result   ;;
 
val judgeBJ : int list list -> BJResult
 
(実行例)
> judgeBJ [[1; 1; 3]; [11; 1; 3]; [1; 11; 3]; [11; 11; 3]];;
 
val it : BJResult = Under (set [6; 16])
 
あとは、全部のカードを生成して、リストボックス等を配置して、イベントハンドラを追加すればできあがりです。全ソースは以下の通りです。
 
open System
open System.Windows.Forms
open System.Drawing
 
 
let crossProduct (ingred : 'a list list) = 
    let rec product rem res = 
        match rem with 
        | [] -> res 
        | h ::tl -> product tl [for i in h do for j in res do yield (i :: j) ]  
 
    product (ingred.Tail) (List.map (fun x -> [x]) ingred.Head) 
    |> List.map (fun lst -> List.rev lst)  
 
type CardSuit = 
    | Spade 
    | Club 
    | Diamond 
    | Heart 
    
    override this.ToString()=
        match this with
        |Spade -> "?"
        | Club -> "?"
        | Diamond -> "?"
        | Heart -> "?"
 
type Card = 
    | Ace of CardSuit 
    | King of CardSuit 
    | Queen of CardSuit 
    | Jack of CardSuit 
    | NumCard of int * CardSuit 
 
    member this.valueBJ = 
        match this with 
        | NumCard (x,_) -> [x] 
        | Ace (_)       -> [1;11] 
        | _             -> [10] 
 
    override this.ToString()=
        match this with
        | Ace(s)   -> s.ToString() + "A"
        | King(s)  -> s.ToString() + "K" 
        | Queen(s) -> s.ToString() + "Q"
        | Jack(s)  -> s.ToString() + "J"
        |NumCard(num,s) -> s.ToString() + num.ToString()
 
//setEleToStr (Set [6]) で "6" ,setEleToStr (Set [3;4;5])で”3か4か5"を返す
//下のBJResult型のヘルパー関数
let setEleToStr (iSet:Set<int>) =
    if Set.count iSet = 0 then
        failwith "this cannot happen" //実際には使われない
    else
      if  Set.count iSet = 1 then
            (List.head (Set.toList iSet)).ToString()
      else
        let iLst = Set.toList iSet
        iLst 
        |> List.map (fun i -> i.ToString())
        |> List.reduce (fun s i -> s + "か" + i.ToString())
 
type BJResult =
    | Over
    | BlackJack
    | Under of (Set<int>)
    
    member this.resultString =
        match this with
        | Over -> "残念です。バーストしました。"
        | BlackJack ->"おめでとうございます。ブラックジャックです。"
        | Under (iSet)  -> sprintf "ブラックジャックまであと%sです。" (setEleToStr iSet)
 
let getPossibleNumList (cards:list<Card>) =
     cards
     |> List.map(fun c -> c.valueBJ)
     |> crossProduct
 
let judgeBJ (numLstLst :list<list<int>>) =
    let sumSet = 
        numLstLst
        |> List.map (fun lst -> List.sum lst) //和のリストとなる[5;5;25;25]
        |> Set.ofList
    let  result =
        if Set.exists (fun n -> n = 21) sumSet then
            BlackJack
        else
            if Set.minElement sumSet > 21 then
                Over
            else
               let under21s  = Set.filter (fun n -> n < 21) sumSet
               Under(Set.map (fun n -> 21 - n) under21s) //21まであといくつかのリスト
    result   
 
let allCard = [ for cs in [Spade;Club;Diamond;Heart] do
                    yield Ace(cs)
                    for num in [2 .. 10] do
                       yield NumCard (num,cs)
                    yield Jack(cs)
                    yield Queen(cs)
                    yield King(cs)
                ]
 
let add2ListBox (lbx:ListBox) (lst:List<'a>) =
    List.iter (fun x -> lbx.Items.Add x |> ignore) lst
 
let mainForm = new Form(Width = 480, Height = 250, Text = "MyBlackJack Window")
mainForm.Show() |> ignore
 
let myListBox1 = new ListBox( Location = new Point(10,40),SelectionMode = SelectionMode.MultiSimple)
let myListBox2 = new ListBox( Location = new Point(150,40))
let myLabel = new Label(Location = new Point(290,40),AutoSize = true)
 
myListBox1.SelectedIndexChanged.Add(fun _ ->
        let selectedCards = [for e in myListBox1.SelectedItems -> (e :?> Card)]
        myListBox2.Items.Clear()
        add2ListBox myListBox2 selectedCards
        let resultBJ =  judgeBJ (getPossibleNumList(selectedCards))
        myLabel.Text <- resultBJ.resultString
        )
 
add2ListBox myListBox1 allCard
mainForm.Controls.Add(myListBox1)
mainForm.Controls.Add(myListBox2)
mainForm.Controls.Add(myLabel)
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。