スポンサーサイト

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

覆面算

BLUEPIXY日記でBLUEPIXYさんがとりあげていた覆面算に興味を引かれ、自分もコードを書いてみた。
はっきり言って遅いプログラムですが一応四則計算対応でありんす。(JINにはまる。)

実行例

>MaskedCalc send + more = money
send + more = money
9567 + 1085 = 10652

>MaskedCalc バナナ + バナナ = シナモン
バナナ + バナナ = シナモン
877 + 877 = 1754

>MaskedCalc ろんり + しようじよ = りんりよし
ろんり + しようじよ = りんりよし
502 + 19789 = 20291
702 + 19589 = 20291
603 + 29789 = 30392
703 + 29689 = 30392

>MaskedCalc みず * みず = 飲みみず
みず * みず = 飲みみず
76 * 76 = 5776

>MaskedCalc つらら / つる = おる
つらら / つる = おる
299 / 23 = 13

>MaskedCalc つらら - つる = おる
つらら - つる = おる
100 - 15 = 85

 

以下コード

open System.Collections.Generic
// 10のn乗
let tenOrd n =
    let rec sub m res =
        if m = n then
            res
        else
            sub (m + 1) res*10
    sub 0 1

//oder-1桁の数字を返す
let extractOrderNum num order =
    let t = num / (tenOrd order)
    t - (t / 10) * 10

// dictionary においてs->3 e->9 n->1 d->2で cDtoInt ' ' [|'d';'n';'e';'s';' ';' '|] 2 dic = 912;;
let cDtoInt (endChar :char) (cA : char[]) (orderIn : int) (cToDdic : Dictionary<char,int>) =
    let rec sub cALst res ord =
        if ord = orderIn + 1 then
            res
        else
            match cALst with
            |h :: tl  when h = endChar ->
                res
            |h :: tl ->
                sub tl (res + (tenOrd ord) * cToDdic.[h]) (ord + 1)
            | _  ->
                failwith "something wrong"
    sub (List.ofArray cA) 0  0        

let calNorderNum (endChar :char) (c1A : char[]) (c2A : char[]) (orderIn : int) (cToDdic : Dictionary<char,int>) op =
    let num1 = cDtoInt endChar c1A orderIn cToDdic
    let num2 = cDtoInt endChar c2A orderIn cToDdic
    let resTemp  = op num1 num2
    extractOrderNum resTemp orderIn 
   
type maskedCalc (t0in :string,t1in :string,opChar :char,t2in : string) =
    let op =
        match opChar with
        |'+'
        |'+' -> (+)
        |'*'
        |'*' -> (*)
        |'-'
        |'-' -> (+)
        |'/'
        |'÷' -> (*)
        | _ -> failwith "演算子が不正"
   
    let (a0in,a1in,r0in,needReplace) =
        match opChar with
        |'+'
        |'+'
        |'*'
        |'*' -> (t0in,t1in,t2in,false)
        |'-'
        |'-'
        |'/'
        |'÷' -> (t1in,t2in,t0in,true)
        | _ -> failwith "演算子が不正"


    let EndIndexChar = ' '
    let NotUsedInt = -1
   
    let setUpArr (str:string) len =
        let a = Array.create (len+1) EndIndexChar
        for i in 0 .. str.Length - 1 do
            a.[str.Length - i - 1] <-  str.Chars i
        a
   
    let makeUsedRArr (a0a : char[]) (a1a : char []) (r0a:char[]) =
        let rArr = new ResizeArray<char>()
        for i in 0 .. a0a.Length - 1 do
            if rArr.Contains a0a.[i] = false  && a0a.[i] <> EndIndexChar then rArr.Add(a0a.[i])
            if rArr.Contains a1a.[i] = false  && a1a.[i] <> EndIndexChar then rArr.Add(a1a.[i])
            if rArr.Contains r0a.[i] = false  && r0a.[i] <> EndIndexChar then rArr.Add(r0a.[i])
        rArr.Add EndIndexChar
        rArr
   
    let initNumDic (rArr :ResizeArray<char>) =
        let dic = new Dictionary<char,int>()
        for i in 0 .. rArr.Count - 2 do //最後のEndIndexCharは含めない   
            dic.Add(rArr.[i],NotUsedInt)
        dic
   
    let initIsTopDic (rArr :ResizeArray<char>) =
        let dic = new Dictionary<char,bool>()
        for i in 0 .. rArr.Count - 2 do //最後のEndIndexCharは含めない   
            if rArr.[i] <> a0in.Chars 0 && rArr.[i] <> a1in.Chars 0 && rArr.[i] <> r0in.Chars 0 then
                dic.Add(rArr.[i],false)
            else
                dic.Add(rArr.[i],true)
        dic
    let arrLen = r0in.Length
    do if a0in.Length > arrLen || a1in.Length > arrLen then failwith "解なし"
    let a0 = setUpArr a0in arrLen
    let a1 = setUpArr a1in arrLen
    let r0 = setUpArr r0in arrLen
    let cArr = [|a0;a1;r0|];
    let usedCharRArr = makeUsedRArr a0 a1 r0
    let numDic = initNumDic usedCharRArr
    do if numDic.Count > 10 then failwith "使用している文字の種類が10を超えています"                
    let isTopDic = initIsTopDic usedCharRArr
    let isUsedNumArr = Array.create 10 false
        
    let rec dealLine (res :ResizeArray<string>) row order  =
        match row with
        | 0
        | 1 ->
            //文字がない、すでに割り当てされた数字がある
            if cArr.[row].[order] = EndIndexChar || numDic.[cArr.[row].[order]] <> NotUsedInt then
                dealLine res (row+1) order
            else
                let start = if isTopDic.[cArr.[row].[order]] then 1 else 0
                for i in start .. 9 do
                    if isUsedNumArr.[i] = false then
                        numDic.[cArr.[row].[order]] <- i
                        isUsedNumArr.[numDic.[cArr.[row].[order]]] <- true
                        dealLine  res (row + 1) order
                        isUsedNumArr.[numDic.[cArr.[row].[order]]] <- false
                        numDic.[cArr.[row].[order]] <- NotUsedInt
        | 2 ->
            if  cArr.[row].[order] = EndIndexChar  then
                let a = cDtoInt EndIndexChar cArr.[0]  order numDic
                let b = cDtoInt EndIndexChar cArr.[1]  order numDic
                let c = cDtoInt EndIndexChar cArr.[2]  order numDic
                //最終チェック(計算結果の最高位が0の時等をはじく)
                //**********************************************************
                //(修正) && numDic.[cArr.[row].[order - 1]] <> 0 を追加
                //**********************************************************
                if op a b = c  && numDic.[cArr.[row].[order - 1]] <> 0 then 
                   let resultStr =
                        if needReplace = false then
                            sprintf "%d %c %d = %d" a opChar b c
                        else
                            sprintf "%d %c %d = %d" c opChar a b
                    res.Add resultStr //結果をResizeArrayに登録          
            else
                let t = calNorderNum EndIndexChar cArr.[0] cArr.[1] order numDic op
                //すでに割り当てされた数字がある
                if  numDic.[cArr.[row].[order]] <> NotUsedInt then
                    if t <> numDic.[cArr.[row].[order]]  then
                        ()
                    else
                        dealLine res 0 (order + 1)
                else //割り当てる 
                    if isUsedNumArr.[t] = false then
                        numDic.[cArr.[row].[order]] <- t
                        isUsedNumArr.[numDic.[cArr.[row].[order]]] <- true
                        dealLine res 0  (order + 1)
                        isUsedNumArr.[numDic.[cArr.[row].[order]]] <- false
                        numDic.[cArr.[row].[order]] <- NotUsedInt
               
        | _ -> failwith "program error"   


    member this.Calc () =
        let result = new ResizeArray<string>()      
        (dealLine result 0 0,numDic) |> ignore
        result

open System

[<STAThread()>]
[<EntryPoint>]
let main(args) =
    match args with
    | [| word1; word2; word3 ;word4; word5|] ->
        try
            printfn "%s" (word1 + " " + word2 + " " + word3 + " " + word4 + " " + word5)
            let t = new maskedCalc(word1,word3,word2.Chars 0,word5)
            let resStrs = t.Calc()
            if resStrs.Count = 0 then
                printfn "解なし"
            else
                Seq.iter(fun s -> printfn "%s" s) (t.Calc())
        with
        |ex ->  printfn "%s" ex.Message
           
    | _ ->
        printfn "\n使用例 (演算子は+-*/が仕様可能) MaskedCalc SEND +  MORE = MONEY \n"

    0

スポンサーサイト

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

trackback


この記事にトラックバックする(FC2ブログユーザー)

覆面算

【F#】覆面算

コメントの投稿

非公開コメント

No title

おおっ!すごいですね。
遅いだなんて、十分なスピードだと思います。
試しに実行してみたのですが、
ウチで実行してみると、

バナナ + バナナ = シナモン
377 + 377 = 754
877 + 877 = 1754


になります・

No title

すいません、直したとおもっていたバグが再発していました。
コード直しておきました。修正点は
//**********************************************************
//(修正) && numDic.[cArr.[row].[order - 1]] <> 0 を追加
//**********************************************************
の部分です。
「計算結果の最高位が0の時をはじく」といいながらはじいていませんでした。
暗黙的クラス定義を使ってみたのですが、これはとても便利でした。
プロフィール

T GYOUTEN

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

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

この人とブロともになる

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