diff --git a/lib/bcdice/arithmetic/node.rb b/lib/bcdice/arithmetic/node.rb index 763be5745..6a2e95b48 100644 --- a/lib/bcdice/arithmetic/node.rb +++ b/lib/bcdice/arithmetic/node.rb @@ -159,6 +159,38 @@ def divide_and_round(dividend, divisor, _round_type) end end + # べき乗(x^n)のノード + class Power + # ノードを初期化する + # @param [Object] base 底のノード + # @param [Object] exp 指数のノード + def initialize(base, exp) + @base = base + @exp = exp + end + + # @param round_type [Symbol] 端数処理方法 + # @return [Integer] 評価結果 + # @raise [ArgumentError] 指数が負の場合 + def eval(round_type) + b = @base.eval(round_type) + e = @exp.eval(round_type) + raise ArgumentError, "べき乗の指数に負の値は使用できません: #{e}" if e.negative? + + b**e + end + + # @return [String] メッセージへの出力 + def output + "#{@base.output}^#{@exp.output}" + end + + # @return [String] ノードのS式 + def s_exp + "(^ #{@base.s_exp} #{@exp.s_exp})" + end + end + class Negative def initialize(body) @body = body diff --git a/lib/bcdice/arithmetic/parser.y b/lib/bcdice/arithmetic/parser.y index 2658c54bb..e77fb4ab9 100644 --- a/lib/bcdice/arithmetic/parser.y +++ b/lib/bcdice/arithmetic/parser.y @@ -1,5 +1,5 @@ class BCDice::Arithmetic::Parser - token NUMBER R U C F PLUS MINUS ASTERISK SLASH PARENL PARENR + token NUMBER R U C F PLUS MINUS ASTERISK SLASH PARENL PARENR CARET rule add: add PLUS mul @@ -32,6 +32,10 @@ class BCDice::Arithmetic::Parser { result = val[1] } | MINUS unary { result = Arithmetic::Node::Negative.new(val[1]) } + | power + + power: term CARET power + { result = Arithmetic::Node::Power.new(val[0], val[2]) } | term term: PARENL add PARENR diff --git a/lib/bcdice/common_command/calc/parser.y b/lib/bcdice/common_command/calc/parser.y index ba5f0c153..7f69a690d 100644 --- a/lib/bcdice/common_command/calc/parser.y +++ b/lib/bcdice/common_command/calc/parser.y @@ -1,5 +1,5 @@ class BCDice::CommonCommand::Calc::Parser - token NUMBER R U C F S PLUS MINUS ASTERISK SLASH PARENL PARENR + token NUMBER R U C F S PLUS MINUS ASTERISK SLASH PARENL PARENR CARET rule expr: secret C add @@ -45,6 +45,10 @@ class BCDice::CommonCommand::Calc::Parser { result = val[1] } | MINUS unary { result = Arithmetic::Node::Negative.new(val[1]) } + | power + + power: term CARET power + { result = Arithmetic::Node::Power.new(val[0], val[2]) } | term term: PARENL add PARENR diff --git a/lib/bcdice/common_command/lexer.rb b/lib/bcdice/common_command/lexer.rb index b0c90185a..af5e8a6cd 100644 --- a/lib/bcdice/common_command/lexer.rb +++ b/lib/bcdice/common_command/lexer.rb @@ -17,6 +17,7 @@ class Lexer "]" => :BRACKETR, "?" => :QUESTION, "@" => :AT, + "^" => :CARET, }.freeze def initialize(source) diff --git a/test/data/Cthulhu.toml b/test/data/Cthulhu.toml index 47d0dd762..110eb1f34 100644 --- a/test/data/Cthulhu.toml +++ b/test/data/Cthulhu.toml @@ -1,3 +1,29 @@ +[[ test ]] +game_system = "Cthulhu" +input = "c(10^10)" +output = "c(10^10) > 10000000000" +rands = [ +] +[[ test ]] +game_system = "Cthulhu" +input = "c((2^3^4)-2^(3^4))" +output = "c((2^3^4)-2^(3^4)) > 0" +rands = [ +] +[[ test ]] +game_system = "Cthulhu" +input = "c((2^3^4)-(2^3)^4)" +output = "c((2^3^4)-(2^3)^4) > 2417851639229258349408256" +rands = [ +] +[[ test ]] +game_system = "Cthulhu" +input = "c(10*5)" +output = "c(10*5) > 50" +rands = [ +] + + [[ test ]] game_system = "Cthulhu" input = "1D100<=70 ファンブルなし"