class BCDice::UserDefinedDiceTable

テキストで定義したダイス表を実行するクラス

@example

text = <<~TEXT
  飲み物表
  1D6
  1:水
  2:緑茶
  3:麦茶
  4:コーラ
  5:オレンジジュース
  6:選ばれし者の知的飲料
TEXT
table = BCDice::UserDefinedDiceTable.new(text)
table.valid?() #=> true
table.roll().text #=> "飲み物表(6) > 選ばれし者の知的飲料"
BCDice::UserDefinedDiceTable.eval(text) #=> #<BCDice::Result>

Public Class Methods

new(text) click to toggle source

@param text [String] ダイス表のテキストデータ

# File lib/bcdice/user_defined_dice_table.rb, line 32
def initialize(text)
  @text = text
  @rows = nil
end
roll(text) click to toggle source

@param text [String] @return [Result nil]

# File lib/bcdice/user_defined_dice_table.rb, line 26
def roll(text)
  new(text).roll()
end

Public Instance Methods

roll(randomizer: Randomizer.new) click to toggle source

ダイス表をロールする @param randomizer [Randomizer] @return [Result, nil]

# File lib/bcdice/user_defined_dice_table.rb, line 40
def roll(randomizer: Randomizer.new)
  parse()

  index = roll_index(randomizer)
  unless valid? && index
    return nil
  end

  key = "#{index}:"
  row = @rows.find { |l| l.start_with?(key) }
  unless row
    return nil
  end

  chosen = row.delete_prefix(key).gsub('\n', "\n").strip
  Result.new.tap do |r|
    r.text = "#{@name}(#{index}) > #{chosen}"
    r.rands = randomizer.rand_results
    r.detailed_rands = randomizer.detailed_rand_results
  end
end
valid?() click to toggle source

有効なダイス表かをチェックする。テキスト形式のミスだけではなく、抜けている出目や範囲外の出目がないか確認する。 @return [Boolean]

# File lib/bcdice/user_defined_dice_table.rb, line 64
def valid?
  parse()

  has_index = @rows.all? { |row| /^\d+:/.match?(row) }
  unless has_index
    return false
  end

  index_list = @rows.map(&:to_i).uniq.sort

  case @type
  when /^\d+D\d+$/
    valid_d?(index_list)
  when "D66", "D66N"
    valid_d66?(index_list)
  when "D66A", "D66S"
    valid_d66_asc_sort?(index_list)
  when "D66D"
    valid_d66_desc_sort?(index_list)
  else
    false
  end
end

Private Instance Methods

parse() click to toggle source
# File lib/bcdice/user_defined_dice_table.rb, line 108
def parse
  return if @rows

  lines = @text.split(/\R/).map(&:rstrip).reject(&:empty?)
  @name = lines.shift
  @type = lines.shift.upcase
  @rows = lines
end
roll_index(randomizer) click to toggle source

@return [Integer, nil]

# File lib/bcdice/user_defined_dice_table.rb, line 91
def roll_index(randomizer)
  if (m = /^(\d+)D(\d+)$/.match(@type))
    times = m[1].to_i
    sides = m[2].to_i
    return randomizer.roll_sum(times, sides)
  end

  case @type
  when "D66", "D66N"
    randomizer.roll_d66(D66SortType::NO_SORT)
  when "D66A", "D66S"
    randomizer.roll_d66(D66SortType::ASC)
  when "D66D"
    randomizer.roll_d66(D66SortType::DESC)
  end
end
valid_d66?(index_list) click to toggle source
# File lib/bcdice/user_defined_dice_table.rb, line 130
def valid_d66?(index_list)
  if index_list.size != 36
    return false
  end

  expected_index = (1..6).map do |tens|
    (1..6).map { |ones| tens * 10 + ones }
  end.flatten

  return index_list == expected_index
end
valid_d66_asc_sort?(index_list) click to toggle source
# File lib/bcdice/user_defined_dice_table.rb, line 142
def valid_d66_asc_sort?(index_list)
  if index_list.size != 21
    return false
  end

  expected_index = (1..6).map do |tens|
    (tens..6).map { |ones| tens * 10 + ones }
  end.flatten

  return index_list == expected_index
end
valid_d66_desc_sort?(index_list) click to toggle source
# File lib/bcdice/user_defined_dice_table.rb, line 154
def valid_d66_desc_sort?(index_list)
  if index_list.size != 21
    return false
  end

  expected_index = (1..6).map do |ones|
    (ones..6).map { |tens| tens * 10 + ones }
  end.flatten.sort

  return index_list == expected_index
end
valid_d?(index_list) click to toggle source
# File lib/bcdice/user_defined_dice_table.rb, line 117
def valid_d?(index_list)
  m = /^(\d+)D(\d+)$/.match(@type)
  times = m[1].to_i
  sides = m[2].to_i

  expected_size = times * sides - times + 1
  if index_list.size != expected_size
    return false
  end

  return index_list.first == times && index_list.last == times * sides
end