小町算(4)

7月20日の日記のパーサを少し書き直した。以下の点が改善された。

  • komachi_parser.e()にlistとdequeのどちらでも渡せるようになった。
  • komachi_parser.e()に渡したリストの値を破壊しない。
  • インデックスを使うことによりパフォーマンスが少し改善された。
  • 123を['1', '', '2', '', '3']のように扱えるようになった(但し、エラー処理を省略した)。
# komachi_parser.py
# -*- coding: utf-8 -*-

def e(L, idx=0):
    '+, -を処理'
    v1, idx = t(L, idx)
    while True:
        if idx < len(L) and (L[idx] == '+' or L[idx] == '-'):
            op = L[idx]
            idx += 1
            v2, idx = t(L, idx)
            if op == '+':
                val = v1 + v2
            elif op == '-':
                val = v1 - v2
            v1 = val
        else:
            break
    return v1

def t(L, idx):
    '*, /を処理'
    v1, idx = f(L, idx)
    while True:
        if idx < len(L) and (L[idx] == '*' or L[idx] == '/'):
            op = L[idx]
            idx += 1
            v2, idx = f(L, idx)
            if op == '*':
                val = v1 * v2
            elif op == '/':
                val = v1 / v2
            v1 = val
        else:
            break
    return v1, idx

def f(L, idx):
    '数値を処理'
    v1 = 0
    while True:
        if idx < len(L) and L[idx] == '':
            idx += 1
        elif idx < len(L) and L[idx].isdigit():
            v = L[idx]
            idx += 1
            v1 = v1 * 10 + int(v)
        else:
            break
    return v1, idx

if __name__ == '__main__':
    print e( ['1', '', '2', '', '3', '', '4', '-', '5', '*', '6', '/', '7', '-', '8', '*', '9'] )
import komachi_parser
import re, time

a = [['1']]
for n in map(str, range(2, 10)):
    b = []
    for s in a:
        for o in ['+', '-', '*', '/', '']:
            b.append(s + [o, n])
    a = b

t = time.time()
cnt = 0
for e in a:
    if komachi_parser.e(e) == 100:
        cnt += 1
print '%d pattern(s), %g sec' % (cnt, time.time() - t)
# 303 pattern(s), 13.032 sec

計算機方式?(+, -と*, /の優先順位を同じにしたバージョン)をまだ解いていないが、気が向いたらやるつもり。