chronicle_bot/lib/addons/roller.rb
Bill Niblock 6fe1a7a251 Update how Addons are used
After some more reading, update the logic for handling the addons.

Leverage an "addons module" (Addon), and require that each addon be a
class within that module. Within that class, optionally include a
`self.register` method, which will be called when the bot is
initialized. This method takes one parameter: the bot
instance.Registering the addon adds the bot's instance to an instance of
the addon, and vice versa, allowing the instances to communicate.
Additionally, registering adds the addons commands.

Each registered addon must also include a `matrix_command` method, which
takes the message String from Matrix. The intention here is to include
additional `*_command` methods for different protocols, without having
to change much else. Adding additional protocols will determine how well
that works.

chronicle_bot.rb: Redo addon logic (details above)
addons/utils.rb: Update for new addon logic (details above)
addons/roller.rb: Update for new addon logic (details above)
2021-02-14 21:06:46 -05:00

120 lines
3.2 KiB
Ruby

# frozen_string_literal: true
module Chronicle
module Addon
# Roll dice and get the results
class Roller
def self.register(bot)
addon_instance = new(bot)
addon_command = ['roll']
[addon_instance, addon_command]
end
def initialize(bot)
@bot = bot
end
# Handle a command from the Matrix protocol
#
# @param message [hash] The message data from Matrix
def matrix_command(message)
msgstr = message.content[:body]
.gsub(/!roll\s*/, '')
.strip
room = @bot.client.ensure_room(message.room_id)
res = roll(msgstr)
final_msg = res.reduce('') { |x, y| x + y + "\n" }
room.send_notice(final_msg)
end
# Solve an arithmatic forumla from a string
#
# @param string [String] The string representation of the formula
# @return Integer of the solution
def solve(string)
formatted = string.gsub(/\s+/, '')
formatted = formatted.gsub(/\[[\d,]*\]/) do |a|
a.scan(/\d*/).reduce(0) { |x, y| x + y.to_i }
end
if formatted.match(/\(.*\)/)
formatted = formatted.sub(/\(.*\)/) do |m|
solve(m[1..-2])
end
solve(formatted)
elsif formatted.match(/\d+\*\d+/)
formatted = formatted.sub(/\d+\*\d+/) do |m|
m.split('*').reduce(1) { |x, y| x * y.to_i }
end
solve(formatted)
elsif formatted.match(/\d+\/\d+/)
formatted = formatted.sub(/\d*\/\d*/) do |m|
m.split('/').reduce { |x, y| x.to_i / y.to_i }
end
solve(formatted)
elsif formatted.match(/\d+\+\d+/)
formatted = formatted.sub(/\d+\+\d+/) do |m|
m.split('+').reduce(0) { |x, y| x + y.to_i }
end
solve(formatted)
elsif formatted.match(/\d+\-\d+/)
formatted = formatted.sub(/\d+\-\d+/) do |m|
m.split('-').reduce { |x, y| x.to_i + -(y.to_i) }
end
solve(formatted)
else
formatted.to_i
end
end
# Pretty-print a result
#
# @param func [String] The name of the function
# @param orig [String] The original request
# @param string [String] The processed request
# @param res [String] The result of the process
# @return String re-formatted
def pretty(func, orig, string, res)
orig.gsub!(/[\+\-*\/]/) { |s| " #{s} " }
string.gsub!(/[\+\-*\/]/) { |s| " #{s} " }
"#{func.capitalize}: #{orig} (#{string}) ==> #{res}"
end
# Roll dice
#
# @param string [String] The string representation of the dice roll
# example: 2d4+6
# @return Array of the message and the result
def roll(string)
results = []
string.gsub(/\s+/,'').split(',').each do |roll|
orig = roll
res = roll.gsub(/[0-9]*d[0-9]*/) do |d|
num,sides = d.split('d')
num = num.empty? ? '1' : num
Array.new(num.to_i.abs) { Random.new.rand(sides.to_i) + 1 }
end
results << pretty("Roll", orig, res, solve(res))
end
results
end
end
end
end