stephancom/xkcd-287

View on GitHub
bin/exord

Summary

Maintainability
Test Coverage
#!/usr/bin/env ruby

#       by stephan.com    _
#   _____  _____  _ __ __| |
#  / _ \ \/ / _ \| '__/ _` |
# |  __/>  < (_) | | | (_| |
#  \___/_/\_\___/|_|  \__,_|

# exord - for exact orders
# based on XKCD 287 - https://xkcd.com/287/
# in fulfillment of a programming challenge

require 'methadone'
require 'pry'
require 'exord'

include Methadone::Main
include Methadone::CLILogging
include Exord

Money.locale_backend = :currency

main do |filename|
  total = 0
  menu = Menu.new(options[:restaurant])
  File.open(filename) do |f|
    total_string = f.readline
    total_string = options[:total] if options.key?(:total)
    total = Monetize.parse(total_string)
    menu.parse_lines(f)
  end

  Logger.info "Finding orders with total: #{total.format} in menu:"
  Logger.info menu.inspect

  exactinator = case options[:method]
                when 'recursive'
                  Exactinator::Recursive.new(menu, total)
                when 'montecarlo'
                  Exactinator::MonteCarlo.new(menu, total)
                end

  exactinator.run

  if exactinator.orders.any?
    Logger.info "Success!  Found #{exactinator.orders.count} order(s)"
  else
    Logger.info 'No orders were found fulfilling the desired total'
  end

  exactinator.orders.each_with_index do |order, i|
    Logger.info "\nOrder #{i + 1} of #{exactinator.orders.count}"
    Logger.info order.inspect
  end
end

options[:restaurant] = 'Menu'
options[:method] = 'recursive'

description 'Given an input file containing a target total and menu items, find all possible combinations of menu items that meet the total exactly'

on('-r VALUE', '--restaurant', 'name of restaurant')
on('-t VALUE', '--total', 'override total in the input file (don\'t forget to escape \$!)')
methods = %w[recursive montecarlo]
on('-m VALUE', '--method', methods, 'possible methods to use', "(#{methods.join('|')})")

arg :filename, :required, 'input filename. first line must have target total, remaining lines each have a menu item name a price, separated by a comma'

version Exord::VERSION, compact: true

go!