class BCDice::CommonCommand::Repeat

リピート

繰り返し回数を指定して、特定のコマンドを複数回実行する 例)

x5 choice[A,B,C,D] #=> `choice[A,B,C,D]`を5回実行する
rep2 CC<=75        #=> `CC<=75`を2回実行する
repeat10 2D6+5     #=> `2D6+6`を10回実行する

このコマンドを入れ子させることは許容しない。繰り返し回数の爆発に繋がるためである。 以下は実行時にエラーとなる。

x10 repeat100 100D100

Constants

PREFIX_PATTERN
REPEAT_LIMIT

Public Class Methods

eval(command, game_system, randomizer) click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 24
def eval(command, game_system, randomizer)
  cmd = parse(command)
  cmd&.roll(game_system, randomizer)
end
new(secret:, times:, trailer:) click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 55
def initialize(secret:, times:, trailer:)
  @secret = secret
  @times = times
  @trailer = trailer
end

Private Class Methods

parse(command) click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 31
def parse(command)
  scanner = StringScanner.new(command)

  secret = !scanner.scan(/s/i).nil?
  keyword = scanner.scan(/repeat|rep|x/i)
  repeat_times = scanner.scan(/\d+/)&.to_i
  whitespace = scanner.scan(/\s+/)
  if keyword.nil? || repeat_times.nil? || whitespace.nil?
    return nil
  end

  trailer = scanner.post_match
  if trailer.nil? || trailer.empty?
    return nil
  end

  new(
    secret: secret,
    times: repeat_times,
    trailer: trailer
  )
end

Public Instance Methods

roll(game_system, randomizer) click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 61
def roll(game_system, randomizer)
  err = validate()
  return err if err

  results = Array.new(@times) do
    cmd = game_system.class.new(@trailer)
    cmd.randomizer = randomizer
    cmd.eval()
  end

  if results.count(nil) == @times
    return result_with_text("繰り返し対象のコマンドが実行できませんでした (#{@trailer})")
  end

  text = results.map.with_index(1) { |r, index| "\##{index}\n#{r.text}" }.join("\n\n")
  secret = @secret || results.any?(&:secret?)

  Result.new.tap do |r|
    r.secret = secret
    r.text = text
  end
end

Private Instance Methods

result_with_text(text) click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 94
def result_with_text(text)
  Result.new.tap do |r|
    r.secret = @secret
    r.text = text
  end
end
validate() click to toggle source
# File lib/bcdice/common_command/repeat.rb, line 86
def validate
  if /\A(repeat|rep|x)\d+/.match?(@trailer)
    result_with_text("Repeatコマンドの重複はできません")
  elsif @times < 1 || REPEAT_LIMIT < @times
    result_with_text("繰り返し回数は1以上、#{REPEAT_LIMIT}以下としてください")
  end
end