From 56c35b282e92599d1aee168fc945f2fa67418382 Mon Sep 17 00:00:00 2001 From: Nokyen Date: Fri, 5 Jun 2020 21:56:37 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E5=B0=82=E7=94=A8=E3=81=AE=E5=88=A4?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E3=81=99=E3=82=8B=E3=82=B3=E3=83=9E=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=92=E8=BF=BD=E5=8A=A0=E3=80=82=E5=9B=A0=E7=B8=81?= =?UTF-8?q?=E8=A1=A8=E3=82=92=E6=8C=AF=E3=82=8B=E3=82=B3=E3=83=9E=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=82=92=E8=BF=BD=E5=8A=A0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/diceBot/ChaosFlare.rb | 146 ++++++++++++++++++++++++++++++++++- src/test/data/ChaosFlare.txt | 43 +++++++++++ 2 files changed, 186 insertions(+), 3 deletions(-) diff --git a/src/diceBot/ChaosFlare.rb b/src/diceBot/ChaosFlare.rb index fce2f1423..2a970af4a 100644 --- a/src/diceBot/ChaosFlare.rb +++ b/src/diceBot/ChaosFlare.rb @@ -12,10 +12,21 @@ class ChaosFlare < DiceBot # ダイスボットの使い方 HELP_MESSAGE = <=目標値] +  (例1) CF (2d6で普通に判定) +  (例2) CF+10@10 (+10の修正値で、クリティカル値10で判定) +  (例3) CF+10#3 (+10の修正値で、ファンブル値3で判定) +  (例4) CF+10>=10 (+10の修正値で、目標値を指定。差分値が出ます) +  (例5) 3CF (ダイス3つで判定) +  (例6) 3CF+10@10#3>=10 (ダイス3つ、修正値10、クリティカル値10、ファンブル値3、目標値10で判定) +  (例7) CF+5-3#3+3>=10 (修正値は計算できます。修正値は、ファンブル値の後、目標値の前の場所にも書けます) + +各種表 +  FT:因縁表 INFO_MESSAGE_TEXT + setPrefixes(['\d*CF.*', 'FT\d*']) + # ダイスボット設定後に行う処理 # @return [void] def postSet @@ -28,7 +39,7 @@ def postSet end end - # ゲーム別成功度判定(2D6) + # ゲーム別成功度判定(2D6)。以前の処理をそのまま残しています。 def check_2D6(total, dice_total, _dice_list, cmp_op, target) output = '' @@ -52,4 +63,133 @@ def check_2D6(total, dice_total, _dice_list, cmp_op, target) return output end + + # コマンドを分岐する場所。 + def rollDiceCommand(command) + case command + when /FT\d*/i + return getFate(command) + end + + return getRollResult(command) + end + + # 因縁表を振る場所。 + def getFate(command) + debug("getFate", "begin") + matched = /FT(\d*)/i.match(command) + debug("matched", matched) + + if matched[1] == "" + #ランダムに振る処理。 + first_die = roll(1,6)[0] + first_index = first_die + second_die = roll(1,6)[0] + second_index = ((second_die) / 2).ceil - 1 + return "(#{first_die},#{second_die}) → #{FATE_TABLE[first_index][second_index]}" + else + #出目を指定して因縁表を振る処理の場所です。気力のある方お願いします。腐れ縁と任意はすでにtableに入っています。 + return "" + end + end + + #カオスフレア用の判定を処理する場所。べた書きです。 + def getRollResult(command) + #まずはコマンドが合っているか。 + roll_regex = /(?:(\d+))?CF((?:[+-]\d+)*)(?:@(\d+))?(?:#(\d+))?((?:[+-]\d+)*)(?:>=(\d+))?/i + matched = roll_regex.match(command) + debug("match", matched) + unless matched + return nil + end + + #指定された各種数字を取得。 + dice_num = 2 + if matched[1] != nil + dice_num = matched[1].to_i + end + + critical = 12 + if matched[3] != nil + critical = matched[3].to_i + end + + fumble = 2 + if matched[4] != nil + fumble = matched[4].to_i + end + debug("fumble", fumble) + + #素のダイスで振る。 + dice_result = roll(dice_num, 6) + debug("result", dice_result) + + dice_sum = dice_result[0] + debug("sum", dice_sum) + + #クリティカルなら30に、ファンブルなら-20に。 + critical_flag = false + fumble_flag = false + if dice_sum >= critical + dice_sum = 30 + critical_flag = true + elsif dice_sum <= fumble + dice_sum = -20 + fumble_flag = true + end + + #修正値を計算して出目に加える。evalで手抜きです。 + adjust = 0 + if matched[2] != "" + adjust += eval(matched[2]) + end + if matched[5] != "" + adjust += eval(matched[5]) + end + + dice_sum = dice_sum + adjust + debug("sum", dice_sum) + + #必要なら差分値を出す。 + diff = 0 + if matched[6] != nil + diff = dice_sum + if dice_sum < 0 + diff = 0 + end + diff -= matched[6].to_i + end + + #結果の文字列を作る。 + result_string = "(#{dice_result[1]}) → #{dice_sum}" + if dice_sum < 0 + result_string += "(0)" + end + if critical_flag + result_string += " (クリティカル)" + end + if fumble_flag + result_string += " (ファンブル)" + end + if matched[6] != nil + result_string += " [差分値:#{diff}]" + end + + #お疲れ様でした。 + return result_string + end + + + #表を振るのに使う定数的なやつ。 + FATE_TABLE = [ + ["腐れ縁"], + ["純愛", "親近感", "庇護"], + ["信頼", "感服", "共感"], + ["友情", "尊敬", "慕情"], + ["好敵手", "期待", "借り"], + ["興味", "憎悪", "悲しみ"], + ["恐怖", "執着", "利用"], + ["任意"] + ].freeze + end diff --git a/src/test/data/ChaosFlare.txt b/src/test/data/ChaosFlare.txt index 7a1b48894..cf1af83dc 100644 --- a/src/test/data/ChaosFlare.txt +++ b/src/test/data/ChaosFlare.txt @@ -237,3 +237,46 @@ input: output: Chaos Flare : (2D6>=7) > 9[4,5] > 9 > 成功 > 差分値2 rand:4/6,5/6 +============================ +input: +FT +output: +Chaos Flare : (4,5) → 期待 +rand:4/6,5/6 +============================ +input: +3CF+10+5-10@10#3+3>=10 +output: +Chaos Flare : (4,5,1) → 38 (クリティカル) [差分値:28] +rand:4/6,5/6,1/6 +============================ +input: +CF +output: +Chaos Flare : (4,5) → 9 +rand:4/6,5/6 +============================ +input: +3CF +output: +Chaos Flare : (4,5,1) → 10 +rand:4/6,5/6,1/6 +============================ +input: +CF@9 +output: +Chaos Flare : (4,5) → 30 (クリティカル) +rand:4/6,5/6 +============================ +input: +CF#5 +output: +Chaos Flare : (1,3) → -20(0) (ファンブル) +rand:1/6,3/6 +============================ +input: +CF+10@10>=10 +output: +Chaos Flare : (4,5) → 19 [差分値:9] +rand:4/6,5/6 + From f861b57aae77965d6023f9d3285595dbd4763776 Mon Sep 17 00:00:00 2001 From: SAKATA Sinji Date: Thu, 11 Jun 2020 20:31:04 +0900 Subject: [PATCH 2/2] Refactor ChaosFlare --- src/diceBot/ChaosFlare.rb | 201 +++++++++++++++++------------------ src/test/data/ChaosFlare.txt | 64 +++++++++-- src/utils/command_parser.rb | 50 ++++++++- 3 files changed, 200 insertions(+), 115 deletions(-) diff --git a/src/diceBot/ChaosFlare.rb b/src/diceBot/ChaosFlare.rb index 2a970af4a..b5d792a33 100644 --- a/src/diceBot/ChaosFlare.rb +++ b/src/diceBot/ChaosFlare.rb @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # frozen_string_literal: true +require 'utils/command_parser' + class ChaosFlare < DiceBot # ゲームシステムの識別子 ID = 'Chaos Flare' @@ -12,17 +14,30 @@ class ChaosFlare < DiceBot # ダイスボットの使い方 HELP_MESSAGE = <=目標値] -  (例1) CF (2d6で普通に判定) -  (例2) CF+10@10 (+10の修正値で、クリティカル値10で判定) -  (例3) CF+10#3 (+10の修正値で、ファンブル値3で判定) -  (例4) CF+10>=10 (+10の修正値で、目標値を指定。差分値が出ます) -  (例5) 3CF (ダイス3つで判定) -  (例6) 3CF+10@10#3>=10 (ダイス3つ、修正値10、クリティカル値10、ファンブル値3、目標値10で判定) -  (例7) CF+5-3#3+3>=10 (修正値は計算できます。修正値は、ファンブル値の後、目標値の前の場所にも書けます) +判定 +CF + 書式: [ダイスの数]CF[修正値][@クリティカル値][#ファンブル値][>=目標値] + CF以外は全て省略可能 + 例: + - CF 2D6,クリティカル値12,ファンブル値2で判定 + - CF+10@10 修正値+10,クリティカル値10で判定 + - CF+10#3 修正値+10,ファンブル値3で判定 + - CF+10>=10 目標値を指定した場合、差分値も出力する + - 3CF+10@10#3>=10 3D6での判定 + - CF@9#3+8>=10 + +2D6 + ファンブル値2で判定する。クリティカルの判定は行われない。 + 目標値が設定された場合、差分値を出力する。 + - 2D6+4>=10 各種表 -  FT:因縁表 + FT: 因縁表 + FTx: 数値を指定すると因果表の値を出力する + - FT -> 11から66の間でランダム決定 + - FT23 -> 23の項目を出力 + - FT0 + - FT7 INFO_MESSAGE_TEXT setPrefixes(['\d*CF.*', 'FT\d*']) @@ -64,123 +79,100 @@ def check_2D6(total, dice_total, _dice_list, cmp_op, target) return output end - # コマンドを分岐する場所。 def rollDiceCommand(command) - case command - when /FT\d*/i - return getFate(command) + if command.start_with? "FT" + roll_fate_table(command) + else + cf_roll(command) end - - return getRollResult(command) end - # 因縁表を振る場所。 - def getFate(command) - debug("getFate", "begin") - matched = /FT(\d*)/i.match(command) - debug("matched", matched) - - if matched[1] == "" - #ランダムに振る処理。 - first_die = roll(1,6)[0] - first_index = first_die - second_die = roll(1,6)[0] - second_index = ((second_die) / 2).ceil - 1 - return "(#{first_die},#{second_die}) → #{FATE_TABLE[first_index][second_index]}" + private + + # 因縁表 + def roll_fate_table(command) + m = /^FT(\d+)?/.match(command) + if m[1] + num = m[1].to_i + if [0, 7].include?(num) + return "因果表(#{num}) > #{FATE_TABLE[num][0]}" + end + + dice1 = num / 10 + dice2 = num % 10 + if !(1..6).include?(dice1) || !(1..6).include?(dice2) + return nil + end else - #出目を指定して因縁表を振る処理の場所です。気力のある方お願いします。腐れ縁と任意はすでにtableに入っています。 - return "" + dice1, = roll(1, 6) + dice2, = roll(1, 6) end + + index1 = dice1 + index2 = (dice2 / 2) - 1 + return "因果表(#{dice1}#{dice2}) > #{FATE_TABLE[index1][index2]}" end - #カオスフレア用の判定を処理する場所。べた書きです。 - def getRollResult(command) - #まずはコマンドが合っているか。 - roll_regex = /(?:(\d+))?CF((?:[+-]\d+)*)(?:@(\d+))?(?:#(\d+))?((?:[+-]\d+)*)(?:>=(\d+))?/i - matched = roll_regex.match(command) - debug("match", matched) - unless matched - return nil - end + # カオスフレア専用コマンド + # @param command [String] + # @return [String, nil] + def cf_roll(command) + parser = CommandParser.new(/\d*CF/) - #指定された各種数字を取得。 - dice_num = 2 - if matched[1] != nil - dice_num = matched[1].to_i + @cmd = parser.parse(command) + unless @cmd + return nil end - critical = 12 - if matched[3] != nil - critical = matched[3].to_i - end + times = @cmd.command == "CF" ? 2 : @cmd.command.to_i + critical = @cmd.critical || 12 + fumble = @cmd.fumble || 2 + @cmd.dollar = nil - fumble = 2 - if matched[4] != nil - fumble = matched[4].to_i - end - debug("fumble", fumble) - - #素のダイスで振る。 - dice_result = roll(dice_num, 6) - debug("result", dice_result) - - dice_sum = dice_result[0] - debug("sum", dice_sum) - - #クリティカルなら30に、ファンブルなら-20に。 - critical_flag = false - fumble_flag = false - if dice_sum >= critical - dice_sum = 30 - critical_flag = true - elsif dice_sum <= fumble - dice_sum = -20 - fumble_flag = true + if times < 0 || ![:>=, nil].include?(@cmd.cmp_op) + return nil end - #修正値を計算して出目に加える。evalで手抜きです。 - adjust = 0 - if matched[2] != "" - adjust += eval(matched[2]) - end - if matched[5] != "" - adjust += eval(matched[5]) - end + dice_total, dice_list_text = roll(times, 6) - dice_sum = dice_sum + adjust - debug("sum", dice_sum) + is_critical = dice_total >= critical + is_fumble = dice_total <= fumble - #必要なら差分値を出す。 - diff = 0 - if matched[6] != nil - diff = dice_sum - if dice_sum < 0 - diff = 0 + total = + if is_critical + 30 + elsif is_fumble + -20 + else + dice_total end - diff -= matched[6].to_i - end - #結果の文字列を作る。 - result_string = "(#{dice_result[1]}) → #{dice_sum}" - if dice_sum < 0 - result_string += "(0)" - end - if critical_flag - result_string += " (クリティカル)" - end - if fumble_flag - result_string += " (ファンブル)" - end - if matched[6] != nil - result_string += " [差分値:#{diff}]" - end + total += @cmd.modify_number + + sequence = [ + "(#{@cmd.to_s(:after_modify_number)})", + "#{dice_total}[#{dice_list_text}]", + total.to_s, + ("0" if total < 0), + ("クリティカル" if is_critical), + ("ファンブル" if is_fumble), + ("差分値 #{difference(total)}" if @cmd.target_number), + ].compact - #お疲れ様でした。 - return result_string + return sequence.join(" > ") end + # @param total [Integer] 合計値 + # @return [Integer] 差分値 + def difference(total) + if total < 0 + -@cmd.target_number + else + total - @cmd.target_number + end + end - #表を振るのに使う定数的なやつ。 + # 表を振るのに使う定数的なやつ。 FATE_TABLE = [ ["腐れ縁"], ["純愛", "親近感", "庇護"], @@ -191,5 +183,4 @@ def getRollResult(command) ["恐怖", "執着", "利用"], ["任意"] ].freeze - end diff --git a/src/test/data/ChaosFlare.txt b/src/test/data/ChaosFlare.txt index cf1af83dc..081be9f0c 100644 --- a/src/test/data/ChaosFlare.txt +++ b/src/test/data/ChaosFlare.txt @@ -241,42 +241,90 @@ rand:4/6,5/6 input: FT output: -Chaos Flare : (4,5) → 期待 +Chaos Flare : 因果表(45) > 期待 rand:4/6,5/6 ============================ input: -3CF+10+5-10@10#3+3>=10 +FT45 output: -Chaos Flare : (4,5,1) → 38 (クリティカル) [差分値:28] +Chaos Flare : 因果表(45) > 期待 +rand: +============================ +input: +SFT +output: +Chaos Flare : 因果表(45) > 期待###secret dice### +rand:4/6,5/6 +============================ +input: +FT0 +output: +Chaos Flare : 因果表(0) > 腐れ縁 +rand: +============================ +input: +FT7 +output: +Chaos Flare : 因果表(7) > 任意 +rand: +============================ +input: +3CF+10+5-10@10#3>=10 +output: +Chaos Flare : (3CF+5@10#3>=10) > 10[4,5,1] > 35 > クリティカル > 差分値 25 +rand:4/6,5/6,1/6 +============================ +input: +3CF@10#3+10+5-10>=10 +output: +Chaos Flare : (3CF+5@10#3>=10) > 10[4,5,1] > 35 > クリティカル > 差分値 25 +rand:4/6,5/6,1/6 +============================ +input: +S3CF+10+5-10@10#3>=10 +output: +Chaos Flare : (3CF+5@10#3>=10) > 10[4,5,1] > 35 > クリティカル > 差分値 25###secret dice### rand:4/6,5/6,1/6 ============================ input: CF output: -Chaos Flare : (4,5) → 9 +Chaos Flare : (CF) > 9[4,5] > 9 +rand:4/6,5/6 +============================ +input: +SCF +output: +Chaos Flare : (CF) > 9[4,5] > 9###secret dice### rand:4/6,5/6 ============================ input: 3CF output: -Chaos Flare : (4,5,1) → 10 +Chaos Flare : (3CF) > 10[4,5,1] > 10 rand:4/6,5/6,1/6 ============================ input: CF@9 output: -Chaos Flare : (4,5) → 30 (クリティカル) +Chaos Flare : (CF@9) > 9[4,5] > 30 > クリティカル rand:4/6,5/6 ============================ input: CF#5 output: -Chaos Flare : (1,3) → -20(0) (ファンブル) +Chaos Flare : (CF#5) > 4[1,3] > -20 > 0 > ファンブル rand:1/6,3/6 ============================ input: CF+10@10>=10 output: -Chaos Flare : (4,5) → 19 [差分値:9] +Chaos Flare : (CF+10@10>=10) > 9[4,5] > 19 > 差分値 9 +rand:4/6,5/6 +============================ +input: +CF-10@10>=10 +output: +Chaos Flare : (CF-10@10>=10) > 9[4,5] > -1 > 0 > 差分値 -10 rand:4/6,5/6 diff --git a/src/utils/command_parser.rb b/src/utils/command_parser.rb index a53a1ddbc..84ac1a847 100644 --- a/src/utils/command_parser.rb +++ b/src/utils/command_parser.rb @@ -1,5 +1,6 @@ require "utils/ArithmeticEvaluator" require "utils/normalize" +require "utils/modifier_formatter" class CommandParser < ArithmeticEvaluator def initialize(*literals) @@ -7,6 +8,52 @@ def initialize(*literals) @round_type = :omit end + # @!attribute [rw] command + # @return [String] + # @!attribute [rw] critical + # @return [Integer, nil] + # @!attribute [rw] fumble + # @return [Integer, nil] + # @!attribute [rw] dollar + # @return [Integer, nil] + # @!attribute [rw] modify_number + # @return [Integer] + # @!attribute [rw] cmp_op + # @return [Symbol, nil] + # @!attribute [rw] target_number + # @return [Integer, nil] + class Parsed + attr_accessor :command, :critical, :fumble, :dollar, :modify_number, :cmp_op, :target_number + + include ModifierFormatter + + def initialize + @critical = nil + @fumble = nil + @dollar = nil + end + + def to_s(suffix_position = :after_command) + c = @critical ? "@#{@critical}" : nil + f = @fumble ? "##{@fumble}" : nil + d = @dollar ? "$#{@dollar}" : nil + m = format_modifier(@modify_number) + + case suffix_position + when :after_command + [@command, c, f, d, m, @cmp_op, @target_number].join() + when :after_modify_number + [@command, m, c, f, d, @cmp_op, @target_number].join() + when :after_target_number + [@command, m, @cmp_op, @target_number, c, f, d].join() + end + end + end + + # @param expr [String] + # @param rount_type [Symbol] + # @return [CommandParser::Parsed] + # @return [nil] def parse(expr, round_type = :omit) @tokens = tokenize(expr) @idx = 0 @@ -30,10 +77,9 @@ def parse(expr, round_type = :omit) return @parsed end - Parsed = Struct.new(:command, :critical, :fumble, :dollar, :modify_number, :cmp_op, :target_number) - private + # @return [Array] def tokenize(expr) expr.gsub(%r{[\(\)\+\-*/@#\$]|[<>!=]+}) { |e| " #{e} " }.split(' ') end