challenge 小町算

古典的なパズルである小町算を解くプログラムを作成してください。

小町算とは:

1□2□3□4□5□6□7□8□9=100

四角の中に、空白、+、-、×、÷のいずれかを一つ入れ、等式が成り立つようにするパズルです。

解答例:

1-2-3+4×56÷7+8×9=100

1+234×5÷6-7-89=100

参考: http://ja.wikipedia.org/wiki/%E5%B0%8F%E7%94%BA%E7%AE%97

  • evalやそれに類するものを使うか否かは自由です。
  • 割り算の際には小数点以下の切捨てが起こらないのが望ましいです。(必須ではない)
    • 切捨てが起こる場合の解答例:1÷2÷3+4+5÷6+7+89=100
  • 余裕があれば括弧を含むようにしてもいいかもしれません。

手元で20数行ほどのPythonスクリプトを書いてみたところ、101個の解答が得られました。

Posted feedbacks - C#

「C# には eval が無いなぁ。動的コンパイルでもしようかな。あ待てよアレがあったな」 ということで C#2.0 + IronPython1.1 です。ところてんさんの #4728 を参考に、Python のコードを片っ端から生成して IronPython で Execute しています。komachi 関数は C# 側で作成。括弧なしで 101 個を、6分程度(orz)で調べ上げます。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
using System.Collections.Generic;
using IronPython;
using IronPython.Hosting;
using IronPython.Runtime;
using IronPython.Runtime.Calls;
class Program {
    static void Main() {
        PythonEngine python = new PythonEngine();
        EngineModule module = python.CreateModule();
        Dictionary<string, object> locals = new Dictionary<string, object>();
        int count = 0;
        locals["komachi"] = new CallTarget2(delegate(object obj, object obj2) {
            if (obj2.Equals(100.0)) {
                count++;
                Console.WriteLine(obj + " = " + obj2);
            }
            return null;
        });
        DateTime before = DateTime.Now;
        foreach (string code in GenPythonCode()) {
            python.Execute(code, module, locals);
        }
        Console.WriteLine("time: {0}", DateTime.Now - before);
        Console.WriteLine("total: {0}", count);
    }
    static IEnumerable<string> GenPythonCode()
    {
        string[] ops = { "", ".0+", ".0-", ".0*", ".0/" };
        for (int i = 0; i < Math.Pow(ops.Length, 8); i++) {
            string code = "1";
            int j = i;
            foreach (char num in "23456789") {
                code += ops[j % ops.Length] + num;
                j /= ops.Length;
            }
            yield return string.Format("komachi(\"{0}\", {0})", code + ".0");
        }
    }
}

AMD Sempron 3400+ 1.99 GHz, 480 MB RAM で11秒。 書きあがるまでに6時間掛かりましたorz

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System;
using System.Text;
using System.Collections.Generic;
class Program {
    static void Main(string[] args) {
        StringBuilder ans = new StringBuilder();
        long ticks = System.DateTime.Now.Ticks;
        int count = 0;
        List<string> Q = new List<string>(new string[] { "1", "□", "2", "□", "3", "□", "4", "□", "5", "□", "6", "□", "7", "□", "8", "□", "9" });
        string[] MDPM = new string[] { "+", "-", "*", "/", " " };
        foreach(string a in MDPM) {
            foreach(string b in MDPM) {
                foreach(string c in MDPM) {
                    foreach(string d in MDPM) {
                        foreach(string e in MDPM) {
                            foreach(string f in MDPM) {
                                foreach(string g in MDPM) {
                                    foreach(string h in MDPM) {
                                        try {
                                            Q[1] = a; Q[3] = b; Q[5] = c; Q[7] = d; Q[9] = e; Q[11] = f; Q[13] = g; Q[15] = h;
                                        } catch(ArgumentOutOfRangeException) { }
                                        if(Eval(Q) == 100d) {
                                            foreach(string str in Q) {
                                                if(str != " ") {
                                                    ans.Append(str);
                                                }
                                            }
                                            ans.AppendLine();
                                            count++;
                                        }
                                    }
                                }

                            }

                        }

                    }

                }

            }

        }
        Console.Write(ans);
        Console.WriteLine(count);
        Console.WriteLine((System.DateTime.Now.Ticks - ticks) / 10000000L + "秒");
        Console.ReadLine();
    }

    static double Eval(List<string> formula) {
        List<string> fm = new List<string>(formula);
        while(fm.Contains(" ")) {
            int i = fm.IndexOf(" ");
            string tmp = fm[i - 1] + fm[i + 1];
            fm.RemoveAt(i - 1);
            fm.RemoveAt(i - 1);
            fm.RemoveAt(i - 1);
            fm.Insert(i - 1, tmp);
        }
        AnyCalc[] ac = new AnyCalc[] { Multi, Div };
        Calc("*", "/", "+", "-", fm, ac);
        ac = new AnyCalc[] { Plus, Minus };
        Calc("+", "-", "*", "/", fm, ac);

        return double.Parse(fm[0]);
    }

    static void Calc(string xc, string yc, string ac, string bc, List<string> fm, AnyCalc[] anyCalc) {
        while(fm.IndexOf(xc) != -1 || fm.IndexOf(yc) != -1) {
            List<string> x = new List<string>();
            List<string> y = new List<string>();
            string f = " ";
            int p = -1;
            for(int i = 0; i < fm.Count; i++) {
                double s;
                if(double.TryParse(fm[i], out s)) {
                    if(x.Count == 0) {
                        x.Add(fm[i]);
                    } else {
                        y.Add(fm[i]);
                    }
                } else if(fm[i] == xc || fm[i] == yc || fm[i] == ac || fm[i] == bc) {
                    p = i;
                    if(fm[i] == xc) {
                        f = xc;
                    } else if(fm[i] == yc) {
                        f = yc;
                    } else x.Clear();
                }
                if(y.Count >= 1) {
                    string tmp;
                    tmp = anyCalc[f == xc ? 0 : 1](fm[p - 1], fm[p + 1]);
                    for(int j = 1; j <= 3; j++) { fm.RemoveAt(p - 1); }
                    fm.Insert(p - 1, tmp);
                    break;
                }
            }
        }
    }

    delegate string AnyCalc(string x, string y);

    static string Plus(string x, string y) {
        return (double.Parse(x) + double.Parse(y)).ToString();
    }
    static string Minus(string x, string y) {
        return (double.Parse(x) - double.Parse(y)).ToString();
    }
    static string Multi(string x, string y) {
        return (double.Parse(x) * double.Parse(y)).ToString();
    }
    static string Div(string x, string y) {
        return (double.Parse(x) / double.Parse(y)).ToString();
    }
}

Eval使いました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.JScript.Vsa;
using Microsoft.JScript;

static class Program {
    [STAThread]
    static void Main() {
        string[] s1 = new string[] { "2","3","4","5","6","7","8","9" };
        string[] s2 = new string[] { "","+","-","*","/" };
        int max = (int)Math.Pow(5,8);
        for(int i = 0;i <= max;i++) {
            string rslt = "1";
            int iCopy = i;
            foreach(string s in s1) {
                rslt += s2[iCopy % 5] + s;
                iCopy /= 5;
            }
            VsaEngine ve = VsaEngine.CreateEngine();
            double r = System.Convert.ToDouble(Eval.JScriptEvaluate(rslt,ve));
            if(r == 100.0) {
                Console.WriteLine(rslt);
            }
        }
    }
}

Index

Feed

Other

Link

Pathtraq

loading...