Skip to content

Commit

Permalink
振り足しの条件の演算子を指定できるようにする
Browse files Browse the repository at this point in the history
  • Loading branch information
ysakasin committed Jun 30, 2020
1 parent 32940ae commit 05b01b5
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 42 deletions.
1 change: 0 additions & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ Style/GlobalVars:
- src/test/others/testCard.rb
- src/irc/ircBot.rb
- src/dice/AddDice.rb
- src/dice/RerollDice.rb
- src/diceBot/RecordOfSteam.rb
- src/diceBot/TokumeiTenkousei.rb
- src/diceBot/BattleTech.rb
Expand Down
140 changes: 101 additions & 39 deletions src/dice/RerollDice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@
require "utils/format"

# 個数振り足しダイス
#
# ダイスを振り、条件を満たした出目の個数だけダイスを振り足す。振り足しがなくなるまでこれを繰り返す。
# 成功条件を満たす出目の個数を調べ、成功数を表示する。
#
# 例
# 2R6+1R10[>3]>=5
# 2R6+1R10>=5@>3
#
# 振り足し条件は角カッコかコマンド末尾の @ で指定する。
# [>4] の場合、4より大きい出目が出たら振り足す。
# [4] のように数値のみ指定されている場合、成功条件の比較演算子を流用する。
# 上記の例の時、出目が
# "2R6" -> [5,6] [5,4] [1,3]
# "1R10" -> [9] [1]
# だとすると、 >=5 に該当するダイスは5つなので成功数5となる。
#
# 成功条件が書かれていない場合、成功数0として扱う。
# 振り足し条件が数値のみ指定されている場合、比較演算子は >= が指定されたとして振舞う。
class RerollDice
def initialize(bcdice, diceBot)
@bcdice = bcdice
Expand All @@ -12,43 +30,21 @@ def initialize(bcdice, diceBot)
end

def rollDice(string)
output = rollDiceCatched(string)

return "#{@nick_e}: #{output}"
end

def rollDiceCatched(string)
debug('RerollDice.rollDice string', string)
string = string.strip

m = /^S?(\d+R\d+(?:\+\d+R\d+)*)(?:\[(\d+)\])?(?:([<>=]+)(\d+))?(?:@(\d+))?$/.match(string)
unless m
debug("is invaild rdice", string)
return '1'
end

notation = m[1]
cmp_op = Normalize.comparison_operator(m[3])
target_number = cmp_op ? m[4].to_i : nil
unless cmp_op
cmp_op, target_number = target_from_default()
unless parse(string)
return nil
end

reroll_cmp_op = cmp_op || :>=
reroll_threshold = decide_reroll_threthold(m[2] || m[5], target_number)

unless reroll_threshold
return "#{string}#{msg_invalid_reroll_number}"
unless @reroll_threshold
return msg_invalid_reroll_number(string)
end

dice_queue = []
notation.split("+").each do |xRn|
dice_queue = @notation.split("+").map do |xRn|
x, n = xRn.split("R").map(&:to_i)
unless valid_reroll_rule?(n, cmp_op, target_number)
return "#{string}#{msg_invalid_reroll_number}"
end
[x, n, 0]
end

dice_queue.push([x, n, 0])
unless dice_queue.all? { |d| valid_reroll_rule?(d[1], @reroll_cmp_op, @reroll_threshold) }
return msg_invalid_reroll_number(string)
end

success_count = 0
Expand All @@ -66,8 +62,8 @@ def rollDiceCatched(string)
dice_total_count += x

dice_list = roll_(x, n)
success_count += dice_list.count() { |val| val.send(cmp_op, target_number) } if cmp_op
reroll_count = dice_list.count() { |val| val.send(reroll_cmp_op, reroll_threshold) }
success_count += dice_list.count() { |val| compare(val, @cmp_op, @target_number) } if @cmp_op
reroll_count = dice_list.count() { |val| compare(val, @reroll_cmp_op, @reroll_threshold) }

dice_str_list.push(dice_list.join(","))

Expand All @@ -80,21 +76,41 @@ def rollDiceCatched(string)
end
end

cmp_op_text = Format.comparison_operator(cmp_op)
grich_text = @diceBot.getGrichText(one_count, dice_total_count, success_count)

sequence = [
"(#{notation}[#{reroll_threshold}]#{cmp_op_text}#{target_number})",
expr(),
dice_str_list.join(" + "),
"成功数#{success_count}",
trim_prefix(" > ", grich_text),
].compact

return sequence.join("")
return "#{@nick_e}: #{sequence.join('')}"
end

private

# @param command [String]
# @return [Boolean]
def parse(command)
m = /^S?(\d+R\d+(?:\+\d+R\d+)*)(?:\[([<>=]+)?(\d+)\])?(?:([<>=]+)(\d+))?(?:@([<>=]+)?(\d+))?$/.match(command)
unless m
return false
end

@notation = m[1]
@cmp_op = Normalize.comparison_operator(m[4])
@target_number = @cmp_op ? m[5].to_i : nil
unless @cmp_op
@cmp_op, @target_number = target_from_default()
end

@reroll_cmp_op = decide_reroll_cmp_op(m)
@reroll_threshold = decide_reroll_threthold(m[3] || m[7], @target_number)

return true
end

# @return [Array<(Symbol, Integer)>]
# @return [Array<(nil, nil)>]
def target_from_default
Expand All @@ -108,6 +124,21 @@ def target_from_default
return cmp_op, target_number
end

# @param m [MatchData]
# @return [Symbol]
def decide_reroll_cmp_op(m)
op =
if m[2] && m[3]
m[2]
elsif m[6] && m[7]
m[6]
else
m[4]
end

Normalize.comparison_operator(op) || :>=
end

# @param captured_threthold [String, nil]
# @param target_number [Integer, nil]
# @return [Integer]
Expand All @@ -122,8 +153,18 @@ def decide_reroll_threthold(captured_threthold, target_number)
end
end

def msg_invalid_reroll_number()
"条件が間違っています。2R6>=5 あるいは 2R6[5] のように振り足し目標値を指定してください。"
# @return [String]
def expr()
reroll_cmp_op_text = @cmp_op != @reroll_cmp_op ? Format.comparison_operator(@reroll_cmp_op) : nil
cmp_op_text = Format.comparison_operator(@cmp_op)

"(#{@notation}[#{reroll_cmp_op_text}#{@reroll_threshold}]#{cmp_op_text}#{@target_number})"
end

# @param command [String]
# @return [String]
def msg_invalid_reroll_number(command)
"#{@nick_e}: #{command} > 条件が間違っています。2R6>=5 あるいは 2R6[5] のように振り足し目標値を指定してください。"
end

# @param sides [Integer]
Expand All @@ -147,20 +188,41 @@ def valid_reroll_rule?(sides, cmp_op, reroll_threshold) # 振り足しロール
end
end

# @param times [Integer]
# @param sides [Integer]
# @return [Array<Integer>]
def roll_(times, sides)
_, dice_list, = @bcdice.roll(times, sides, (@diceBot.sortType & 2))
dice_list.split(",").map(&:to_i)
end

# @param prefix [String]
# @param string [String]
# @param [String, nil]
def trim_prefix(prefix, string)
if string.start_with?(prefix)
string = string[prefix.size..-1]
end

if string.size.zero?
if string.empty?
nil
else
string
end
end

# 整数を比較する
# Ruby 1.8のケア用
#
# @param lhs [Integer]
# @param op [Symbol]
# @param rhs [Integer]
# @return [Boolean]
def compare(lhs, op, rhs)
if op == :'!='
lhs != rhs
else
lhs.send(op, rhs)
end
end
end
34 changes: 32 additions & 2 deletions src/test/data/None.txt
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,36 @@ DiceBot : (2R4+2R6[4]>=4) > 4,3 + 3,5 + 1 + 2 > 成功数2
rand:4/4,3/4,3/6,5/6,1/4,2/6
============================
input:
2R4+2R6[>4]>=4
output:
DiceBot : (2R4+2R6[>4]>=4) > 4,3 + 3,5 + 2 > 成功数2
rand:4/4,3/4,3/6,5/6,2/6
============================
input:
2R4+2R6>=4@>4
output:
DiceBot : (2R4+2R6[>4]>=4) > 4,3 + 3,5 + 2 > 成功数2
rand:4/4,3/4,3/6,5/6,2/6
============================
input:
2R4+2R6[<=2]>=4
output:
DiceBot : (2R4+2R6[<=2]>=4) > 4,2 + 3,5 + 2 + 4 > 成功数3
rand:4/4,2/4,3/6,5/6,2/4,4/4
============================
input:
2R4+2R6>=4@<=2
output:
DiceBot : (2R4+2R6[<=2]>=4) > 4,2 + 3,5 + 2 + 4 > 成功数3
rand:4/4,2/4,3/6,5/6,2/4,4/4
============================
input:
2R4+2R6[<>4]>=4
output:
DiceBot : (2R4+2R6[<>4]>=4) > 4,2 + 3,5 + 4 + 4,4 > 成功数5
rand:4/4,2/4,3/6,5/6,4/4,4/6,4/6
============================
input:
134 数値だけには反応しない
output:
rand:
Expand Down Expand Up @@ -1006,13 +1036,13 @@ rand:
input:
2R6[3]
output:
DiceBot : (2R6[3]) > 3,2 + 1 > 成功数0
DiceBot : (2R6[>=3]) > 3,2 + 1 > 成功数0
rand:3/6,2/6,1/6
============================
input:
S2R6[3]
output:
DiceBot : (2R6[3]) > 3,2 + 1 > 成功数0###secret dice###
DiceBot : (2R6[>=3]) > 3,2 + 1 > 成功数0###secret dice###
rand:3/6,2/6,1/6
============================
input:
Expand Down

0 comments on commit 05b01b5

Please sign in to comment.