-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AddDice::Node: 二項演算子をリファクタリングする #162
Merged
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,36 @@ | ||
# -*- coding: utf-8 -*- | ||
# frozen_string_literal: true | ||
|
||
class AddDice | ||
# 加算ロールの構文解析木のノードを格納するモジュール | ||
module Node | ||
# 加算ロールコマンドのノード。 | ||
# | ||
# 目標値が設定されていない場合は +lhs+ のみを使用する。 | ||
# 目標値が設定されている場合は、+lhs+、+cmp_op+、+rhs+ を使用する。 | ||
class Command | ||
attr_reader :lhs, :cmp_op, :rhs | ||
|
||
# 左辺のノード | ||
# @return [Object] | ||
attr_reader :lhs | ||
# 比較演算子 | ||
# @return [Symbol] | ||
attr_reader :cmp_op | ||
# 右辺のノード | ||
# @return [Integer, String] | ||
attr_reader :rhs | ||
|
||
# ノードを初期化する | ||
# @param [Object] lhs 左辺のノード | ||
# @param [Symbol] cmp_op 比較演算子 | ||
# @param [Integer, String] rhs 右辺のノード | ||
def initialize(lhs, cmp_op, rhs) | ||
@lhs = lhs | ||
@cmp_op = cmp_op | ||
@rhs = rhs | ||
end | ||
|
||
# 文字列に変換する | ||
# @return [String] | ||
def to_s | ||
@lhs.to_s + cmp_op_text + @rhs.to_s | ||
end | ||
|
@@ -27,6 +47,8 @@ def s_exp | |
|
||
private | ||
|
||
# メッセージ中で比較演算子をどのように表示するかを返す | ||
# @return [String] | ||
def cmp_op_text | ||
case @cmp_op | ||
when :'!=' | ||
|
@@ -39,83 +61,210 @@ def cmp_op_text | |
end | ||
end | ||
|
||
# 二項演算子のノード | ||
class BinaryOp | ||
def initialize(lhs, op, rhs, round_type = nil) | ||
# ノードを初期化する | ||
# @param [Object] lhs 左のオペランドのノード | ||
# @param [Symbol] op 演算子 | ||
# @param [Object] rhs 右のオペランドのノード | ||
def initialize(lhs, op, rhs) | ||
@lhs = lhs | ||
@op = op | ||
@rhs = rhs | ||
@round_type = round_type | ||
end | ||
|
||
# ノードを評価する | ||
# | ||
# 左右のオペランドをそれぞれ再帰的に評価した後で、演算を行う。 | ||
# | ||
# @param [Randomizer] randomizer ランダマイザ | ||
# @return [Integer] 評価結果 | ||
def eval(randomizer) | ||
lhs = @lhs.eval(randomizer) | ||
rhs = @rhs.eval(randomizer) | ||
|
||
calc(lhs, rhs) | ||
return calc(lhs, rhs) | ||
end | ||
|
||
# 文字列に変換する | ||
# @return [String] | ||
def to_s | ||
@lhs.to_s + @op.to_s + @rhs.to_s + round_type_suffix() | ||
"#{@lhs}#{@op}#{@rhs}" | ||
end | ||
|
||
# メッセージへの出力を返す | ||
# @return [String] | ||
def output | ||
@lhs.output + @op.to_s + @rhs.output + round_type_suffix() | ||
"#{@lhs.output}#{@op}#{@rhs.output}" | ||
end | ||
|
||
# ノードのS式を返す | ||
# @return [String] | ||
def s_exp | ||
"(#{@op}#{round_type_suffix} #{@lhs.s_exp} #{@rhs.s_exp})" | ||
"(#{op_for_s_exp} #{@lhs.s_exp} #{@rhs.s_exp})" | ||
end | ||
|
||
private | ||
|
||
# 演算を行う | ||
# @param [Integer] lhs 左のオペランド | ||
# @param [Integer] rhs 右のオペランド | ||
# @return [Integer] 演算の結果 | ||
def calc(lhs, rhs) | ||
if @op != :/ | ||
return lhs.send(@op, rhs) | ||
end | ||
lhs.send(@op, rhs) | ||
end | ||
|
||
# S式で使う演算子の表現を返す | ||
# @return [String] | ||
def op_for_s_exp | ||
@op | ||
end | ||
end | ||
|
||
# 除算ノードの基底クラス | ||
# | ||
# 定数 +ROUNDING_METHOD_SYMBOL+ で端数処理方法を示す記号 | ||
# ( +'U'+, +'R'+, +''+ ) を定義すること。 | ||
# また、除算および端数処理を行う +divide_and_round+ メソッドを実装すること。 | ||
class DivideBase < BinaryOp | ||
# ノードを初期化する | ||
# @param [Object] lhs 左のオペランドのノード | ||
# @param [Object] rhs 右のオペランドのノード | ||
def initialize(lhs, rhs) | ||
super(lhs, :/, rhs) | ||
end | ||
|
||
# 文字列に変換する | ||
# | ||
# 通常の結果の末尾に、端数処理方法を示す記号を付加する。 | ||
# | ||
# @return [String] | ||
def to_s | ||
"#{super}#{rounding_method_symbol}" | ||
end | ||
|
||
# メッセージへの出力を返す | ||
# | ||
# 通常の結果の末尾に、端数処理方法を示す記号を付加する。 | ||
# | ||
# @return [String] | ||
def output | ||
"#{super}#{rounding_method_symbol}" | ||
end | ||
|
||
private | ||
|
||
# 端数処理方法を示す記号を返す | ||
# @return [String] | ||
def rounding_method_symbol | ||
self.class::ROUNDING_METHOD_SYMBOL | ||
end | ||
|
||
# S式で使う演算子の表現を返す | ||
# @return [String] | ||
def op_for_s_exp | ||
"#{@op}#{rounding_method_symbol}" | ||
end | ||
|
||
# 演算を行う | ||
# @param [Integer] lhs 左のオペランド | ||
# @param [Integer] rhs 右のオペランド | ||
# @return [Integer] 演算の結果 | ||
def calc(lhs, rhs) | ||
if rhs.zero? | ||
return 1 | ||
end | ||
|
||
case @round_type | ||
when :roundUp | ||
(lhs.to_f / rhs).ceil | ||
when :roundOff | ||
(lhs.to_f / rhs).round | ||
else | ||
lhs / rhs | ||
end | ||
return divide_and_round(lhs, rhs) | ||
end | ||
|
||
def round_type_suffix | ||
case @round_type | ||
when :roundUp | ||
"U" | ||
when :roundOff | ||
"R" | ||
else | ||
"" | ||
end | ||
# 除算および端数処理を行う | ||
# @param [Integer] _dividend 被除数 | ||
# @param [Integer] _divisor 除数(0以外) | ||
# @return [Integer] | ||
def divide_and_round(_dividend, _divisor) | ||
raise NotImplementedError | ||
end | ||
end | ||
|
||
# 除算(切り上げ)のノード | ||
class DivideWithRoundingUp < DivideBase | ||
# 端数処理方法を示す記号 | ||
ROUNDING_METHOD_SYMBOL = 'U' | ||
|
||
private | ||
|
||
# 除算および端数処理を行う | ||
# @param [Integer] dividend 被除数 | ||
# @param [Integer] divisor 除数(0以外) | ||
# @return [Integer] | ||
def divide_and_round(dividend, divisor) | ||
(dividend.to_f / divisor).ceil | ||
end | ||
end | ||
|
||
# 除算(四捨五入)のノード | ||
class DivideWithRoundingOff < DivideBase | ||
# 端数処理方法を示す記号 | ||
ROUNDING_METHOD_SYMBOL = 'R' | ||
|
||
private | ||
|
||
# 除算および端数処理を行う | ||
# @param [Integer] dividend 被除数 | ||
# @param [Integer] divisor 除数(0以外) | ||
# @return [Integer] | ||
def divide_and_round(dividend, divisor) | ||
(dividend.to_f / divisor).round | ||
end | ||
end | ||
|
||
# 除算(切り捨て)のノード | ||
class DivideWithRoundingDown < DivideBase | ||
# 端数処理方法を示す記号 | ||
ROUNDING_METHOD_SYMBOL = '' | ||
|
||
private | ||
|
||
# 除算および端数処理を行う | ||
# @param [Integer] dividend 被除数 | ||
# @param [Integer] divisor 除数(0以外) | ||
# @return [Integer] | ||
def divide_and_round(dividend, divisor) | ||
dividend / divisor | ||
end | ||
end | ||
|
||
# 符号反転のノード | ||
class Negate | ||
# 符号反転の対象 | ||
# @return [Object] | ||
attr_reader :body | ||
|
||
# ノードを初期化する | ||
# @param [Object] body 符号反転の対象 | ||
def initialize(body) | ||
@body = body | ||
end | ||
|
||
# ノードを評価する | ||
# | ||
# 対象オペランドを再帰的に評価した後、評価結果の符号を反転する。 | ||
# | ||
# @param [Randomizer] randomizer ランダマイザ | ||
# @return [Integer] 評価結果 | ||
def eval(randomizer) | ||
[email protected](randomizer) | ||
end | ||
|
||
# 文字列に変換する | ||
# @return [String] | ||
def to_s | ||
"-#{@body}" | ||
end | ||
|
||
# メッセージへの出力を返す | ||
# @return [String] | ||
def output | ||
"-#{@body.output}" | ||
end | ||
|
@@ -127,20 +276,36 @@ def s_exp | |
end | ||
end | ||
|
||
# ダイスロールのノード | ||
class DiceRoll | ||
# ノードを初期化する | ||
# @param [Number] times ダイスを振る回数のノード | ||
# @param [Number] sides ダイスの面数のノード | ||
# @param [Number, nil] critical クリティカル値のノード | ||
def initialize(times, sides, critical) | ||
@times = times.literal | ||
@sides = sides.literal | ||
@critical = critical.nil? ? nil : critical.literal | ||
|
||
# ダイスを振った結果の出力 | ||
@text = nil | ||
end | ||
|
||
# ノードを評価する(ダイスを振る) | ||
# | ||
# 評価結果は出目の合計値になる。 | ||
# 出目はランダマイザに記録される。 | ||
# | ||
# @param [Randomizer] randomizer ランダマイザ | ||
# @return [Integer] 評価結果(出目の合計値) | ||
def eval(randomizer) | ||
total, @text = randomizer.roll(@times, @sides, @critical) | ||
|
||
total | ||
end | ||
|
||
# 文字列に変換する | ||
# @return [String] | ||
def to_s | ||
if @critical | ||
"#{@times}D#{@sides}@#{@critical}" | ||
|
@@ -149,6 +314,8 @@ def to_s | |
end | ||
end | ||
|
||
# メッセージへの出力を返す | ||
# @return [String] | ||
def output | ||
@text | ||
end | ||
|
@@ -162,21 +329,32 @@ def s_exp | |
end | ||
end | ||
|
||
# 数値のノード | ||
class Number | ||
# 値 | ||
# @return [Integer] | ||
attr_reader :literal | ||
|
||
# ノードを初期化する | ||
# @param [Integer] literal 値 | ||
def initialize(literal) | ||
@literal = literal | ||
end | ||
|
||
# 符号を反転した結果の数値ノードを返す | ||
# @return [Number] | ||
def negate | ||
Number.new(-@literal) | ||
end | ||
|
||
# ノードを評価する | ||
# @return [Integer] 格納している値 | ||
def eval(_randomizer) | ||
@literal | ||
end | ||
|
||
# 文字列に変換する | ||
# @return [String] | ||
def to_s | ||
@literal.to_s | ||
end | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SYMBOL
だとどうしても Symbol が入っているのを連想してしまうので、何かしら名前を変更した方が良いと思います。ROUNDING_METHOD
ROUNDING_METHOD_PREFIX
ROUNDING_METHOD_SIGN
ROUNDING_METHOD_STR
ROUNDING_METHOD_TYPE
ROUNDING_TYPE
等
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
どうせ外部から使わないし、他に良い名前がないならこのままでもいいです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ありがとうございます。それでは
ROUNDING_METHOD
にしてみます。