スポンサーサイト

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

どう書く?org F# 麻雀の和了判定

「どう書く?org」http://ja.doukaku.org/に挑戦6問目です。 
さて今回の問題は次のような内容。 
 
(問題) 
麻雀の手牌が和了形か否かを判定するコードを書いてください。  http://ja.doukaku.org/237/
手牌を表すのは、mn+h 枚を表す配列です。フォーマットは A, B の2つから任意に選んだものを受け取ってください。以下の2つは同じものです: 
handA = [2,1,1,1,1,2,2,1,3] # 牌1が2個、牌2が1個、牌3が1個、牌4が1個、牌5が1個、牌6が2個、牌7が2個、牌8が1個、牌9が3個 
handB = [1,1,2,3,4,5,6,6,7,7,8,9,9,9] # 牌1、牌1、牌2、牌3、牌4、牌5、牌6、牌7、牌7、牌8、牌9、牌9、牌9 
 
ある配列が和了形であるとは、手牌が「刻子」「順子」を合計 n 個と「対子」1 個との和であることをいうものとします。 
「刻子」とは1種の牌が m 個あることをいいます。 
「順子」とは連続したインデクスを持つ牌が m 種各1個あることをいいます。 
「対子」とは1種の牌が h 個あることをいいます。 
 
上の例は、和了形です。なぜなら、当該配列が 
Bタイプで表記すると、刻子 [9,9,9], 順子 [2,3,4], [5,6,7], [6,7,8], 対子 [1,1] の、 
Aタイプで表記すると、刻子 [0,0,0,0,0,0,0,0,3], 順子 [0,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,0,0], [0,0,0,0,0,1,1,1,0], 対子 [2,0,0,0,0,0,0,0,0] の、 
和だからです。 
 
・ n は任意のものを受け取れるようにしてください。 
・ 牌のインデクスの数 (Aタイプの長さ、Bタイプの要素の最大値) M も任意としてください。 
・ 1種の牌の最大個数 (Aタイプの要素の最大値、Bタイプの1種の要素の最大重複度) L も任意としてください。 
・ 一般の麻雀の場合は、m=3, n=4, h=2, M=9, L=4 です。この条件に特化した高速化が可能なら行ってもかまいません。 
 
と問題だけでもとても長いのですが、Aタイプに対してプログラムを作成してみました。
ついでにmもhも設定可能にしてみました。
 
m=3でh=2の場合 
 
> isFinished 3 2 [|2;1;1;1;1;2;2;1;3|];; 
 
val it : bool = true
 
 
以下コード
 
let isMoreEqM m  (arr : int []) (index : int) =
    arr.[index] >= m
 
//配列arrにおいてindexから始まる連続したm個の要素が全部1以上か
let isConsecMoreEq1 m  (arr : int []) (index : int) =
    let mutable res = true
    for i in 0 .. (m - 1) do
        if arr.[index + i] = 0 then
            res <- false
    res
 
//後ろにk個の0を付け加えた配列を返す
let addEle k (arr : int []) =
    let t = Array.zeroCreate (arr.Length + k)
    for i in 0 .. (arr.Length - 1) do
        t.[i] <- arr.[i]
    t
 
let isFinished mIn hIn (arrIn : int []) =
    let targetArr = addEle (mIn - 1) arrIn
    let canRevoveAll m (arr : int []) =
        let searchIndexEnd = arr.Length - m
        let result = ref false
        let rec reMoveM (arr : int []) index =
            if index = searchIndexEnd + 1 then
                    result := true
            elif arr.[index] = 0 then
                    reMoveM arr (index + 1) 
            elif  (isMoreEqM m arr index = true) && (isConsecMoreEq1 m arr index = true) then
                    reMoveKousi m arr index
                    reMoveJyunsi m arr index  
            elif  isMoreEqM m arr index = true then
                    reMoveKousi m arr index
            elif  isConsecMoreEq1 m arr index = true then
                    reMoveJyunsi m arr index
            else
                    ()     
        and reMoveKousi mA (arrA :int []) indexA =
             arrA.[indexA] <- arrA.[indexA] - mA; 
             reMoveM arrA indexA 
             arrA.[indexA] <- arrA.[indexA] + mA; 
        
        and reMoveJyunsi mB (arrB :int []) index =
             for i in 0 .. (mB-1) do
                 arrB.[index+i] <- arrB.[index+i] - 1
             reMoveM arrB index 
             for i in 0 .. (mB-1) do
                 arrB.[index+i] <- arrB.[index+i] + 1
  
        reMoveM arr 0
        !result                  
   
    let rec reMoveH m h (arr : int []) index =
        let searchIndexEnd = arr.Length - m
        if index = searchIndexEnd + 1 then
            false
        else
            if arr.[index] >= h then
                arr.[index] <- arr.[index] - h
                if canRevoveAll m arr = true then
                    true
                else
                    arr.[index] <- arr.[index] + h
                    reMoveH m h arr (index + 1)
            else
              reMoveH m h arr (index + 1)  
    
    reMoveH mIn hIn targetArr 0
スポンサーサイト

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

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

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

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

この人とブロともになる

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