Skip to content
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::Parser #147

Merged
merged 21 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d2f634a
AddDice::Parser
ysakasin Apr 2, 2020
e3921d1
Remove rollDiceAddingUp
ysakasin Apr 2, 2020
391b860
Move add_dice files
ysakasin Apr 3, 2020
eee8f97
AddDice::Parser: テストケースを追加する
ochaochaocha3 Apr 4, 2020
22c54f7
Merge pull request #153 from bcdice/add_dice_parser-add_tests
ysakasin Apr 5, 2020
d13475c
init value of #inject
ysakasin Apr 5, 2020
693851e
Merge branch 'master' into add_dice_parser
ysakasin Apr 5, 2020
a7066a2
AddDice::Node: ノードのS式を返すメソッドを追加する
ochaochaocha3 Apr 12, 2020
b76769b
Merge pull request #156 from bcdice/add_dice_parser-s_exp
ysakasin Apr 12, 2020
d897938
AddDice: 定数畳み込み関連のテストケースを追加する
ochaochaocha3 Apr 18, 2020
1536c21
AddDice: 符号反転を含む場合のテストケースを追加する
ochaochaocha3 Apr 19, 2020
147820f
Fix folding negative numbers
ysakasin Apr 19, 2020
1fc1bb4
Merge pull request #157 from bcdice/add_dice_parser-add_constant_fold…
ysakasin Apr 19, 2020
146da3c
Remove ConstantFolding
ysakasin Apr 20, 2020
ae7a956
Merge branch 'add_dice_parser' of github.com:bcdice/BCDice into add_d…
ysakasin Apr 20, 2020
a24e968
Add test and remove duplicated test
ysakasin Apr 20, 2020
7d7e66f
AddDice::Parser: コメントを追加する
ochaochaocha3 Apr 23, 2020
466f7de
AddDice::Node: コメントを追加する
ochaochaocha3 Apr 23, 2020
30a0ee9
AddDice::Node: 二項演算子をリファクタリングする
ochaochaocha3 Apr 23, 2020
dc8bf1d
AddDice::Node: 端数処理方法の定数名を変更する
ochaochaocha3 Apr 25, 2020
1db5580
Merge pull request #162 from bcdice/add_dice_parser-refactor_binary_op
ysakasin Apr 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace :test do
'src/test/test_srs_help_messages.rb',
'src/test/test_detailed_rand_results.rb',
'src/test/range_table_test.rb',
'src/test/add_dice_parser_test.rb',
]
end
end
Expand Down
20 changes: 7 additions & 13 deletions src/bcdiceCore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1485,14 +1485,13 @@ def sendMessageToChannels(message)
def parren_killer(string)
debug("parren_killer input", string)

while /^(.*?)\[(\d+[Dd]\d+)\](.*)/ =~ string
str_before = ""
str_after = ""
dice_cmd = Regexp.last_match(2)
str_before = Regexp.last_match(1) if Regexp.last_match(1)
str_after = Regexp.last_match(3) if Regexp.last_match(3)
rolled, = rollDiceAddingUp(dice_cmd)
string = "#{str_before}#{rolled}#{str_after}"
string = string.gsub(/\[\d+D\d+\]/i) do |matched|
# Remove '[' and ']'
command = matched[1..-2].upcase
times, sides = command.split("D").map(&:to_i)
rolled, = roll(times, sides)

rolled
end

string = changeRangeTextToNumberText(string)
Expand All @@ -1513,11 +1512,6 @@ def parren_killer(string)
return string
end

def rollDiceAddingUp(*arg)
dice = AddDice.new(self, @diceBot)
dice.rollDiceAddingUp(*arg)
end

# [1...4]D[2...7] -> 2D7 のように[n...m]をランダムな数値へ変換
def changeRangeTextToNumberText(string)
debug('[st...ed] before string', string)
Expand Down
326 changes: 23 additions & 303 deletions src/dice/AddDice.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-

require "utils/normalize"
require "dice/add_dice/parser"
require "dice/add_dice/randomizer"

class AddDice
def initialize(bcdice, diceBot)
Expand All @@ -14,320 +16,38 @@ def initialize(bcdice, diceBot)
#################### 加算ダイス ########################

def rollDice(string)
debug("AddDice.rollDice() begin string", string)
parser = Parser.new(string)

m = %r{(^|\s)S?(([\d\+\*\-]*[\d]+D[\d/UR@]*[\d\+\*\-D/UR]*)(([<>=]+)([?\-\d]+))?)($|\s)}i.match(string)
return "1" unless m

string = m[2]
judgeText = m[4] # '>=10'といった成否判定文字
judgeOperator = m[5] # '>=' といった判定の条件演算子 文字
diffText = m[6]

signOfInequality = ""
isCheckSuccess = false

if judgeText
isCheckSuccess = true
string = m[3]
signOfInequality = @bcdice.marshalSignOfInequality(judgeOperator)
end

dice_cnt = 0
dice_max = 0
total_n = 0
dice_n = 0
output = ""
n1 = 0
n_max = 0

addUpTextList = string.split("+")

addUpTextList.each do |addUpText|
subtractTextList = addUpText.split("-")

subtractTextList.each_with_index do |subtractText, index|
next if subtractText.empty?

debug("begin rollDiceAddingUp(subtractText, isCheckSuccess)", subtractText, isCheckSuccess)
dice_now, dice_n_wk, dice_str, n1_wk, n_max_wk, cnt_wk, max_wk = rollDiceAddingUp(subtractText, isCheckSuccess)
debug("end rollDiceAddingUp(subtractText, isCheckSuccess) -> dice_now", dice_now)

rate = (index == 0 ? 1 : -1)

total_n += dice_now * rate
dice_n += dice_n_wk * rate
n1 += n1_wk
n_max += n_max_wk
dice_cnt += cnt_wk
dice_max = max_wk if max_wk > dice_max

next if @diceBot.sendMode == 0

operatorText = getOperatorText(rate, output)
output += "#{operatorText}#{dice_str}"
end
end

if signOfInequality != ""
string += "#{signOfInequality}#{diffText}"
command = parser.parse()
if parser.error?
return '1'
end

# ダイス目による補正処理(現状ナイトメアハンターディープ専用)
addText, revision = @diceBot.getDiceRevision(n_max, dice_max, total_n)
debug('addText, revision', addText, revision)
randomizer = Randomizer.new(@bcdice, @diceBot, command.cmp_op)
total = command.lhs.eval(randomizer)

debug("@nick_e", @nick_e)
if @diceBot.sendMode > 0
if output =~ /[^\d\[\]]+/
output = "#{@nick_e}: (#{string}) > #{output} > #{total_n}#{addText}"
output =
if randomizer.dice_list.size <= 1 && command.lhs.is_a?(Node::DiceRoll)
"#{@nick_e}: (#{command}) > #{total}"
else
output = "#{@nick_e}: (#{string}) > #{total_n}#{addText}"
end
else
output = "#{@nick_e}: (#{string}) > #{total_n}#{addText}"
end

total_n += revision

if signOfInequality != "" # 成功度判定処理
cmp_op = Normalize.comparison_operator(signOfInequality)
target = Normalize.target_number(diffText)
successText = @diceBot.check_result(total_n, dice_n, @dice_list, dice_max, cmp_op, target)
debug("check_suc successText", successText)
output += successText
end

# ダイスロールによるポイント等の取得処理用(T&T悪意、ナイトメアハンター・ディープ宿命、特命転校生エクストラパワーポイントなど)
output += @diceBot.getDiceRolledAdditionalText(n1, n_max, dice_max)

if (dice_cnt == 0) || (dice_max == 0)
output = '1'
end

debug("AddDice.rollDice() end output", output)
return output
end

def rollDiceAddingUp(string, isCheckSuccess = false) # 加算ダイスロール(個別処理)
debug("rollDiceAddingUp() begin string", string)

dice_max = 0
dice_total = 1
dice_n = 0
output = ""
n1 = 0
n_max = 0
dice_cnt_total = 0
double_check = false

if @diceBot.sameDiceRerollCount != 0 # 振り足しありのゲームでダイスが二個以上
if @diceBot.sameDiceRerollType <= 0 # 判定のみ振り足し
debug('判定のみ振り足し')
double_check = true if isCheckSuccess
elsif @diceBot.sameDiceRerollType <= 1 # ダメージのみ振り足し
debug('ダメージのみ振り足し')
double_check = true unless isCheckSuccess
else # 両方振り足し
double_check = true
end
end

debug("double_check", double_check)

while (m = /(^([\d]+\*[\d]+)\*(.+)|(.+)\*([\d]+\*[\d]+)$|(.+)\*([\d]+\*[\d]+)\*(.+))/.match(string))
if m[2]
string = @bcdice.parren_killer('(' + m[2] + ')') + '*' + m[3]
elsif m[5]
string = m[4] + '*' + @bcdice.parren_killer('(' + m[5] + ')')
elsif m[7]
string = m[6] + '*' + @bcdice.parren_killer('(' + m[7] + ')') + '*' + m[8]
end
end

debug("string", string)

emptyResult = [dice_total, dice_n, output, n1, n_max, dice_cnt_total, dice_max]

mul_cmd = string.split("*")
mul_cmd.each do |mul_line|
if (m = mul_line.match(%r{([\d]+)D([\d]+)(@(\d+))?(/\d+[UR]?)?}i))
dice_count = m[1].to_i
dice_max = m[2].to_i
critical = m[4].to_i
slashMark = m[5]

return emptyResult if (critical != 0) && !@diceBot.is2dCritical
return emptyResult if dice_max > $DICE_MAXNUM

dice_max, dice_now, output_tmp, n1_count, max_number_tmp, result_dice_count =
rollDiceAddingUpCommand(dice_count, dice_max, slashMark, double_check, isCheckSuccess, critical)

output += "*" if output != ""
output += output_tmp

dice_total *= dice_now

dice_n += dice_now
dice_cnt_total += result_dice_count
n1 += n1_count
n_max += max_number_tmp

else
mul_line = mul_line.to_i
debug('dice_total', dice_total)
debug('mul_line', mul_line)

dice_total *= mul_line

unless output.empty?
output += "*"
end

if mul_line < 0
output += "(#{mul_line})"
else
output += mul_line.to_s
end
end
end

debug("rollDiceAddingUp() end output", dice_total, dice_n, output, n1, n_max, dice_cnt_total, dice_max)
return dice_total, dice_n, output, n1, n_max, dice_cnt_total, dice_max
end

def rollDiceAddingUpCommand(dice_count, dice_max, slashMark, double_check, isCheckSuccess, critical)
result_dice_count = 0
dice_now = 0
n1_count = 0
max_number = 0
dice_str = ""
dice_arry = []
dice_arry.push(dice_count)
loop_count = 0

debug("before while dice_arry", dice_arry)

while !dice_arry.empty?
debug("IN while dice_arry", dice_arry)

dice_wk = dice_arry.shift
result_dice_count += dice_wk

debug('dice_wk', dice_wk)
debug('dice_max', dice_max)
debug('(sortType & 1)', (@diceBot.sortType & 1))

dice_dat = rollLocal(dice_wk, dice_max, (@diceBot.sortType & 1))
debug('dice_dat', dice_dat)

dice_new = dice_dat[0]
dice_now += dice_new

debug('slashMark', slashMark)
dice_now = getSlashedDice(slashMark, dice_now)

dice_str += "][" if dice_str != ""
debug('dice_str', dice_str)

dice_str += dice_dat[1]
n1_count += dice_dat[2]
max_number += dice_dat[3]

# 振り足しありでダイスが二個以上
if double_check && (dice_wk >= 2)
addDiceArrayByAddDiceCount(dice_dat, dice_max, dice_arry, dice_wk)
"#{@nick_e}: (#{command}) > #{command.lhs.output} > #{total}"
end

@diceBot.check2dCritical(critical, dice_new, dice_arry, loop_count)
loop_count += 1
end
dice_list = randomizer.dice_list
num_one = dice_list.count(1)
num_max = dice_list.count(randomizer.sides)

# ダイス目文字列からダイス値を変更する場合の処理(現状クトゥルフ・テック専用)
dice_now = @diceBot.changeDiceValueByDiceText(dice_now, dice_str, isCheckSuccess, dice_max)
suffix, revision = @diceBot.getDiceRevision(num_max, randomizer.sides, total)
output += suffix
total += revision

output = ""
if @diceBot.sendMode > 1
output += "#{dice_now}[#{dice_str}]"
elsif @diceBot.sendMode > 0
output += dice_now.to_s
if command.cmp_op
dice_total = dice_list.inject(&:+)
output += @diceBot.check_result(total, dice_total, dice_list, randomizer.sides, command.cmp_op, command.rhs)
end

return dice_max, dice_now, output, n1_count, max_number, result_dice_count
end

def addDiceArrayByAddDiceCount(dice_dat, _dice_max, dice_queue, roll_times)
values = dice_dat[1].split(",").map(&:to_i)
count_bucket = {}

values.each do |val|
count_bucket[val] ||= 0
count_bucket[val] += 1
end
output += @diceBot.getDiceRolledAdditionalText(num_one, num_max, randomizer.sides)

reroll_threshold = @diceBot.sameDiceRerollCount == 1 ? roll_times : @diceBot.sameDiceRerollCount
count_bucket.each do |_, num|
if num >= reroll_threshold
dice_queue.push(num)
end
end
end

def getSlashedDice(slashMark, lhs)
m = %r{^/(\d+)(.)?$}i.match(slashMark)
return lhs unless m

rhs = m[1].to_i
mark = m[2]

return lhs if rhs == 0

value = lhs.to_f / rhs

if mark == "U"
return value.ceil
elsif mark == "R"
return value.round
else
return value.floor
end
end

def rollLocal(dice_wk, dice_max, sortType)
if dice_max == 66
return rollD66(dice_wk)
end

ret = @bcdice.roll(dice_wk, dice_max, sortType)
@dice_list.concat(ret[1].split(",").map(&:to_i))

return ret
end

def rollD66(count)
d66List = []

count.times do
d66List << @bcdice.getD66Value()
end

total = d66List.inject { |sum, i| sum + i }
text = d66List.join(',')
n1Count = d66List.count(1)
nMaxCount = d66List.count(66)

@dice_list.concat(d66List)

return [total, text, n1Count, nMaxCount, 0, 0, 0]
end

def getOperatorText(rate, output)
if rate < 0
'-'
elsif output.empty?
''
else
"+"
end
return output
end
end
Loading