結果
問題 | No.708 (+ー)の式 |
ユーザー |
|
提出日時 | 2018-10-24 23:03:19 |
言語 | Python3 (3.13.1 + numpy 2.2.1 + scipy 1.14.1) |
結果 |
AC
|
実行時間 | 37 ms / 2,000 ms |
コード長 | 5,706 bytes |
コンパイル時間 | 244 ms |
コンパイル使用メモリ | 12,928 KB |
実行使用メモリ | 11,136 KB |
最終ジャッジ日時 | 2024-11-19 05:38:19 |
合計ジャッジ時間 | 1,468 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 12 |
ソースコード
import sys# 演算子(ホントは二項演算子もクラス化したい)class Operator:def __init__(self):self.name = ''def calc(self):passdef __str__(self):return self.name# +演算子(二項演算子)class PlusOperator(Operator):def __init__(self):self.name = '+'# 項を与えて演算を行うdef calc(self, val1, val2):return val1.calc_value() + val2.calc_value()# -演算子(二項演算子)class MinusOperator(Operator):def __init__(self):self.name = '-'# 項を与えて演算を行うdef calc(self, val1, val2):return val1.calc_value() - val2.calc_value()# 値# 値を最後まで評価するには calc_value() を使うclass Value:def __init__(self, v):self.__val = vdef add_char(self, c):self.__val = self.value() * 10 + int(c)def value(self):return self.__valdef calc_value(self):v = self.value()#sys.stderr.write("v={}\n".format(v))while isinstance(v, Value):if v is Value:return v.__valv = v.value()return vdef make_exp(self, ope, v2):return BinominalExpression(ope, self, v2)def __str__(self):return "{0}".format(self.__val)# 式(値のサブクラス)class Expression(Value):def __init__(self, ope):self.operator = ope# 式を評価(1段階だけ)def value(self):raise 'Not implemented!'# 二項式(式のサブクラス)# 演算子と右辺値と左辺値を持つclass BinominalExpression(Expression):def __init__(self, ope, v1, v2):super().__init__(ope)self.val1 = v1self.val2 = v2# 式を評価(1段階だけ)def value(self):return self.operator.calc(self.val1, self.val2)def __str__(self):return "{0} {1} {2}".format(self.val1, self.operator, self.val2)# カッコ(値のサブクラス)# 値をカッコで囲んだ状態を表現するclass Brackets(Value):def __init__(self, v):super().__init__(v)def __str__(self):return "({0})".format(super().__str__())# 式文字列のパーサーclass Parser:def __init__(self):self.__v1 = Value(0) # パース中の左辺値self.__v2 = Value(0) # パース中の右辺値self.__operator = None # パース中の演算子# 式が生成可能であれば生成するdef try_make_exp(self):if self.__operator != None:self.__v1 = self.__v1.make_exp(self.__operator, self.__v2)self.__operator = Noneself.__v2 = Value(0)# パーサー本体の処理def parse(self, chars):while len(chars) > 0:c = chars.pop(0)sys.stderr.write("c={0} # {1}\n".format(c, self))if c == '(':p = Parser()sys.stderr.write("new parser = {0}\n".format(p))b = Brackets(p.parse(chars)) # カッコの中を別のパーサーで処理してカッコで囲うif self.__operator == None:self.__v1 = belse:self.__v2 = belif c == ')':self.try_make_exp()break # カッコが終われば処理終了elif c == '+':self.try_make_exp()self.__operator = PlusOperator()elif c == '-':self.try_make_exp()self.__operator = MinusOperator()else:if self.__operator == None:self.__v1.add_char(c)else:self.__v2.add_char(c)self.try_make_exp()return self.__v1def __str__(self):return "{3}: v1={0}, operator={1}, v2={2}".format(self.__v1, self.__operator, self.__v2, super().__str__())chars = list(input())p = Parser()val = p.parse(chars)print(val.calc_value())# 【感想】# パーサーでは1文字ずつ線形に解析できるようにし、カッコは再帰処理で対応した。# 式の構造を完全にオブジェクトで保持できるようにし、最後に評価を行うことで木構造を評価していくようにした。# C# の Expression 関連のクラス構造を思い浮かべながら、近いものを構築していった。# こうすることで動的に式構造を変更できるようなライブラリに発展させていける可能性が広がる## クラス構成について# 値 > 式 > 二項式 というクラスの継承関係にし、# カッコも 値 のサブクラスとすることでネストに対応できるようにした。# 二項式には2つの値と1つの演算子を所有させ、値を評価させると演算子のcalc()を呼んでくれる仕掛けにした。# 値を評価することで、そのサブクラスが実際の評価処理を行っていく構造であり、、木構造のどのポイントからでも# 評価が可能となっている。## Python について# 初挑戦の Python だったが、ググる際に Python と Python3 の区別ししないといけないことに気づいた。# クラスのインスタンスメソッドの第1引数に self を書かないといけない点、また、インスタンスメンバに# アクセスする際に self. を付けないといけない点など、JavaScriptのような感じでとても冗長な記述と感じた。# この辺は Ruby とは違い、明示的に書く文化が良しとされているようだ。