Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module Robot
- class CLI
- def initialize
- options = {:file => nil , :x => 5 , :y => 5}
- parser = OptionParser.new do|opts|
- opts.banner = "Usage: toyrobot [options]"
- opts.on('-f', '--file filepath', 'Filepath for input commands') do |filename|
- options[:file] = filename
- end
- opts.on('-x', '--xcoordinate X', 'Max X co-ordinate(Number)') do |max_x|
- begin
- options[:x] = Integer(max_x)
- rescue
- puts "Invalid x argument"
- puts opts
- exit
- end
- end
- opts.on('-y', '--ycoordinate Y', 'Max Y co-ordinate(Number)') do |max_y|
- begin
- options[:y] = Integer(max_y)
- rescue
- puts "Invalid y argument"
- puts opts
- exit
- end
- end
- opts.on('-h', '--help', 'Displays Help') do
- puts opts
- exit
- end
- end
- parser.parse!
- @application = Robot::App.new(options)
- end
- def start
- @application.start
- end
- end
- end
- module Robot
- class App
- def initialize(opts)
- @input_file = opts[:file].nil? ? STDIN : File.open(opts[:file])
- @simulator = Robot::Simulator.new opts[:x], opts[:y]
- end
- def start
- command = read_command
- while (command) do
- $logger.debug("Received command #{command}")
- begin
- @simulator.execute command
- rescue => e
- $logger.error(e)
- end
- command = read_command
- end
- end
- def read_command
- print "# " if @input_file == STDIN
- command = @input_file.gets
- exit if command.nil? || (command.chomp.downcase == ".quit")
- command
- end
- end
- end
- module Robot
- class CommandParser
- @@number_reg = /^d+$/
- # allowed_commnads is a hash
- # with value as :method => [[arg types],[regex_range_for_strings_only]]
- def initialize(allowed_commands)
- @allowed_commands = allowed_commands
- $logger.info("Allowed commands are #{@allowed_commands.keys}")
- end
- def parse command
- $logger.debug("Parsing command #{command}")
- args = command.split " "
- method = args.delete_at(0)
- if valid?(method, args)
- update_args! method , args
- yield method , args
- return true
- else
- $logger.warn("Parsing failed. Invalid #{command}")
- return false
- end
- end
- private
- def update_args! method , args
- @allowed_commands[method][0].each_with_index do |arg_type,i|
- case arg_type
- when :number
- args[i] = args[i].to_i
- when :string
- end
- end
- end
- def valid? (method , args)
- return false unless @allowed_commands.has_key? method
- unless @allowed_commands[method].nil?
- return false unless @allowed_commands[method][0].size == args.size
- @allowed_commands[method][0].each_with_index do |arg_type,i|
- case arg_type
- when :number
- return false unless args[i] =~ @@number_reg
- when :string
- allowed_reg = @allowed_commands[method][1][i]
- unless allowed_reg.nil?
- return false unless args[i] =~ /#{allowed_reg}/
- end
- end
- end
- end
- return true
- end
- end
- end
- module Robot
- class Direction
- attr_accessor :direction
- def initialize(direction)
- @direction = direction
- end
- @NORTH = Direction.new "NORTH"
- @SOUTH = Direction.new "SOUTH"
- @EAST = Direction.new "EAST"
- @WEST = Direction.new "WEST"
- @CLOCKWISE_DIRECTIONS = [@NORTH,@EAST,@SOUTH,@WEST]
- def to_s
- @direction
- end
- class << self
- attr_accessor :NORTH, :SOUTH, :EAST, :WEST
- end
- def self.find(direction)
- @CLOCKWISE_DIRECTIONS.find{|d| d.direction == direction.upcase }
- end
- def self.left(direction)
- @CLOCKWISE_DIRECTIONS[( @CLOCKWISE_DIRECTIONS.index(direction) - 1 ) % 4]
- end
- def self.right(direction)
- @CLOCKWISE_DIRECTIONS[( @CLOCKWISE_DIRECTIONS.index(direction) + 1 ) % 4]
- end
- end
- end
- module Robot
- class Position
- attr_accessor :x, :y, :direction
- def initialize(x,y,direction)
- @x = x
- @y = y
- @direction = direction
- end
- def to_s
- "X= #{@x} Y=#{@y} Facing=#{@direction.to_s}"
- end
- def equal?(another_position)
- self.x == another_position.x &&
- self.y == another_position.y &&
- self.direction == another_position.direction
- end
- def move
- curr_postion = self.dup
- case curr_postion.direction
- when Direction.NORTH
- curr_postion.y +=1
- when Direction.SOUTH
- curr_postion.y -=1
- when Direction.EAST
- curr_postion.x +=1
- when Direction.WEST
- curr_postion.x -=1
- end
- curr_postion
- end
- def left
- curr_postion = self.dup
- curr_postion.direction = Direction.left @direction
- curr_postion
- end
- def right
- curr_postion = self.dup
- curr_postion.direction = Direction.right @direction
- curr_postion
- end
- end
- end
- module Robot
- class Simulator
- attr_accessor :toy_robot
- def initialize max_x, max_y
- commands = {
- "PLACE" => [
- [:number , :number , :string],
- [nil,nil,"^NORTH$|^SOUTH$|^EAST$|^WEST$"]
- ],
- "MOVE" => [[],[]],
- "LEFT" => [[],[]],
- "RIGHT" => [[],[]],
- "REPORT" => [[],[]]
- }
- @command_parser = CommandParser.new(commands)
- @table = Table.new max_x , max_y
- @toy_robot = ToyRobot.new
- $logger.info "Simulator created successfully."
- end
- def execute(command)
- r = @command_parser.parse(command) do |method,args|
- $logger.debug("#{method.downcase} - args #{args}")
- self.send( method.downcase , * args)
- end
- $logger.debug(@toy_robot.to_s)
- end
- def place x , y , face
- if @table.inside?(x, y)
- @toy_robot.position = Position.new(x, y, Direction.find(face))
- @toy_robot.placed = true
- end
- end
- def move
- return unless @toy_robot.placed
- next_position = @toy_robot.position.move
- if @table.inside? next_position.x , next_position.y
- @toy_robot.position = next_position
- else
- ignore
- end
- end
- def left
- return unless @toy_robot.placed
- @toy_robot.position = @toy_robot.position.left
- end
- def right
- return unless @toy_robot.placed
- @toy_robot.position = @toy_robot.position.right
- end
- def report
- if @toy_robot.placed
- puts "#{@toy_robot.position.x} #{@toy_robot.position.y} #{@toy_robot.position.direction}"
- else
- puts "Robot is not placed yet. Please use PLACE command to place the robot."
- end
- end
- def ignore
- $logger.debug "Ignored step towards #{toy_robot.position.direction}"
- end
- end
- end
- module Robot
- class Table
- def initialize max_x , max_y
- @MAX_X = max_x
- @MAX_Y = max_y
- $logger.info "Table boundaries are #{@MAX_X},#{@MAX_Y}"
- end
- def inside? x,y
- return ((0..@MAX_X-1) === x) && ((0..@MAX_Y-1) === y)
- end
- end
- end
- module Robot
- class ToyRobot
- attr_accessor :position, :placed
- def initialize
- @position = nil
- @placed = false
- $logger.info "Toy Robot created successfully."
- end
- def to_s
- if @placed
- "Placed at #{@position.to_s}"
- else
- "Not placed"
- end
- end
- end
- end
- $LOAD_PATH << File.join(File.dirname(__FILE__))
- require "optparse"
- require "logger"
- require "robot/version"
- require 'robot/command_parser'
- require 'robot/table'
- require 'robot/position'
- require 'robot/toy_robot'
- require "robot/direction"
- require "robot/simulator"
- require "robot/app"
- require "robot/cli"
- $logger = Logger.new('log/toy_robot.log')
- require_relative '../spec_helper'
- require_relative '../../lib/robot'
- include Robot
- describe CommandParser do
- subject(:command_parser) {CommandParser.new({
- "Salute" => [
- [:string],
- ["^Hello$|^Namaste$"]
- ],
- "Name" => [
- [:string],
- []
- ] ,
- "Age" => [
- [:number],
- []
- ]
- })}
- context "#with valid command" do
- context "with range" do
- before {
- @ran = false
- @called = command_parser.parse "Salute Hello" do |m,a|
- @ran = true
- @m = m
- @a = a
- end
- }
- it { expect(@ran).to be true }
- it { expect(@called).to be true }
- it { expect(@a.size).to be 1 }
- it { expect(@a[0]).to match "Hello" }
- it { expect(@m).to match "Salute" }
- end
- context "without range" do
- context "with string" do
- before {
- @ran = false
- @called = command_parser.parse "Name Tom" do |m,a|
- @ran = true
- @m = m
- @a = a
- end
- }
- it { expect(@ran).to be true }
- it { expect(@called).to be true }
- it { expect(@a.size).to be 1 }
- it { expect(@a[0]).to match "Tom" }
- it { expect(@m).to match "Name" }
- end
- context "with number" do
- before {
- @ran = false
- @called = command_parser.parse "Age 50" do |m,a|
- @ran = true
- @m = m
- @a = a
- end
- }
- it { expect(@ran).to be true }
- it { expect(@called).to be true }
- it { expect(@a.size).to be 1 }
- it { expect(@a[0]).to be 50 }
- it { expect(@m).to match "Age"}
- end
- end
- end
- context "#with invalid command" do
- before {
- @ran = false
- @called = command_parser.parse "Salute Hi" do |m,a|
- @ran = true
- end
- }
- it { expect(@called).to be false }
- it { expect(@called).to be false }
- end
- end
- require_relative '../spec_helper'
- require_relative '../../lib/robot'
- include Robot
- describe Direction do
- describe ":: finds directions" do
- it { expect( Direction.find "NORTH" ).to be Direction.NORTH }
- it { expect( Direction.find "SOUTH" ).to be Direction.SOUTH }
- it { expect( Direction.find "EAST" ).to be Direction.EAST }
- it { expect( Direction.find "WEST" ).to be Direction.WEST }
- end
- describe ":: turns left" do
- it { expect( Direction.left Direction.NORTH ).to be Direction.WEST }
- it { expect( Direction.left Direction.SOUTH ).to be Direction.EAST }
- it { expect( Direction.left Direction.EAST ).to be Direction.NORTH }
- it { expect( Direction.left Direction.WEST ).to be Direction.SOUTH }
- end
- describe ":: turns right" do
- it { expect( Direction.right Direction.NORTH ).to be Direction.EAST }
- it { expect( Direction.right Direction.SOUTH ).to be Direction.WEST }
- it { expect( Direction.right Direction.EAST ).to be Direction.SOUTH }
- it { expect( Direction.right Direction.WEST ).to be Direction.NORTH }
- end
- end
- require_relative '../spec_helper'
- require_relative '../../lib/robot'
- include Robot
- describe Position do
- context "#moves correctly to north" do
- before {
- @position = Position.new(2, 3, Direction.NORTH)
- @curr_position = @position.move
- }
- it { expect(@curr_position.x).to be 2 }
- it { expect(@curr_position.y).to be 4 }
- it { expect(@curr_position.direction).to be Direction.NORTH }
- end
- context "#moves correctly to south" do
- before {
- @position = Position.new(2, 3, Direction.SOUTH)
- @curr_position = @position.move
- }
- it { expect(@curr_position.x).to be 2 }
- it { expect(@curr_position.y).to be 2 }
- it { expect(@curr_position.direction).to be Direction.SOUTH }
- end
- context "#moves correctly to east" do
- before {
- @position = Position.new(2, 3, Direction.EAST)
- @curr_position = @position.move
- }
- it { expect(@curr_position.x).to be 3 }
- it { expect(@curr_position.y).to be 3 }
- it { expect(@curr_position.direction).to be Direction.EAST }
- end
- context "#moves correctly to west" do
- before {
- @position = Position.new(2, 3, Direction.WEST)
- @curr_position = @position.move
- }
- it { expect(@curr_position.x).to be 1 }
- it { expect(@curr_position.y).to be 3 }
- it { expect(@curr_position.direction).to be Direction.WEST }
- end
- context "#turns left" do
- before {
- start_position = Position.new(2, 3, Direction.WEST)
- @position = start_position.left
- }
- it { expect(@position.x).to be 2 }
- it { expect(@position.y).to be 3 }
- it { expect(@position.direction).to be Direction.SOUTH }
- end
- context "#turns right" do
- before {
- start_position = Position.new(2, 3, Direction.WEST)
- @position = start_position.right
- }
- it { expect(@position.x).to be 2 }
- it { expect(@position.y).to be 3 }
- it { expect(@position.direction).to be Direction.NORTH }
- end
- end
- require_relative '../spec_helper'
- require_relative '../../lib/robot'
- include Robot
- describe Simulator do
- describe "#gets placed" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 3, "NORTH"
- }
- it { expect(@simulator.toy_robot.position).to be Position.new(2,3,Direction.NORTH) }
- end
- describe "#moves" do
- context "when inside table" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 3, "NORTH"
- @simulator.move
- }
- it { expect(@simulator.toy_robot.position).to be Position.new(2,4,Direction.NORTH) }
- end
- context "when at edge of table" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 4, 4, "NORTH"
- @simulator.move
- }
- it { expect(@simulator.toy_robot.position).to be Position.new(4,4,Direction.NORTH) }
- end
- end
- describe "# turns" do
- context "when faced north" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 2, "NORTH"
- }
- it { @simulator.left ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.WEST) }
- it { @simulator.right ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.EAST) }
- end
- context "when faced south" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 2, "SOUTH"
- }
- it { @simulator.left ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.EAST) }
- it { @simulator.right ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.WEST) }
- end
- context "when faced east" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 2, "EAST"
- }
- it { @simulator.left ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.NORTH) }
- it { @simulator.right ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.SOUTH) }
- end
- context "when faced west" do
- before {
- @simulator = Simulator.new 5,5
- @simulator.place 2, 2, "WEST"
- }
- it { @simulator.left ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.SOUTH) }
- it { @simulator.right ; expect(@simulator.toy_robot.position).to be Position.new(2,2,Direction.NORTH) }
- end
- end
- end
- require_relative '../spec_helper'
- require_relative '../../lib/robot'
- include Robot
- describe Table do
- context "#checks boundry" do
- before { @t = Table.new 5,5 }
- it {expect(@t.inside?(2,3)).to be true}
- it {expect(@t.inside?(0,0)).to be true}
- it {expect(@t.inside?(5,5)).to be false}
- it {expect(@t.inside?(5,3)).to be false}
- it {expect(@t.inside?(3,5)).to be false}
- it {expect(@t.inside?(6,3)).to be false}
- it {expect(@t.inside?(3,6)).to be false}
- it {expect(@t.inside?(-1,0)).to be false}
- it {expect(@t.inside?(0,-1)).to be false}
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement