Problem Statement

  1. When the program is executed, a single command-line argument should be provided. That argument will be the path to a file containing descriptions for each tool in the toolbox. If the argument is not provided, or the input file cannot be successfully read or parsed, the program should print "Invalid Input" and terminate.
  2. The input file will contain at least two lines of input. The first line will give the number of tools included in the input file as an integer. Each subsequent line will identify a particular tool using the name of the class representing the tool, followed by values for each attribute of the tool. The values will be separated by spaces, and listed in the same order as those attributes are accepted in the tool's constructor.
  3. Once the input is read, the program will then accept a query as input via the terminal. That input should consist of multiple parts on a single line, separated by a space. The first part will be the name of an action that needs to be performed, and then following that will be one or more values to be provided to that action as arguments, separated by spaces.
  4. The program will review its list of available tools, finding any tool that supports that action. It will then call the method in that tool that corresponds with the action (the method and action names will be the same), providing the values as an arguments. If the tool responds with true to that method call, then that tool is able to perform that action. The program should print the description of the appropriate tool to the terminal and terminate. In this example, each query will only result in one matching tool, if any.
  5. If a matching tool cannot be found, or there is any errors reading the input from the terminal, the program should print "Invalid Tool" and terminate.

Head → Desk

Image Credit: Giphy

Let's break it down into classes

from abc import ABC, abstractmethod

class Tool(ABC):

def init(self): pass

@abstractmethod def describe(self): pass

from Tool import *
from abc import ABC, abstractmethod

class Wrench(Tool, ABC):

def init(self, length): self.__length = length

@property def length(self): return self.__length

@abstractmethod def tighten(self, clearance, size): pass

from Tool import *
from abc import ABC, abstractmethod

class Saw(Tool, ABC):

def init(self, length): self.__length = length

@property def length(self): return self.__length

@abstractmethod def cut(self, length, material): pass

Check Structure!

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

other methods go here

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

def describe(self): return “AdjustableWrench: Length: {} MinSize: {} MaxSize: {}".format(self.__length, self.__min_size, self.__max_size)

other methods go here

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

def describe(self): return “AdjustableWrench: Length: {} MinSize: {} MaxSize: {}".format(self.__length, self.__min_size, self.__max_size)

other methods go here

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

def describe(self): return “AdjustableWrench: Length: {} MinSize: {} MaxSize: {}".format(self.__length, self.__min_size, self.__max_size)

other methods go here

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

def describe(self): return “AdjustableWrench: Length: {} MinSize: {} MaxSize: {}".format(self.length, self.__min_size, self.__max_size)

other methods go here

Adjustable Wrench

from Wrench import *

class AdjustableWrench(Wrench):

def init(self, length, min_size, max_size): super().init(length) self.__min_size = min_size self.__max_size = max_size

@property def min_size(self): return self.__min_size

@property def max_size(self): return self.__max_size

def describe(self): return “AdjustableWrench: Length: {} MinSize: {} MaxSize: {}".format(self.length, self.min_size, self.max_size)

def tighten(self, clearance, size): return clearance >= self.length and size >= self.min_size and size <= self.max_size

Combination Wrench

from Wrench import *

class CombinationWrench(Wrench):

def init(self, length, size): super().init(length) self.__size = size

@property def size(self): return self.__size

def describe(self): return “CombinationWrench Length: {} Size: {}” .format(self.length, self.size)

def tighten(self, clearance, size): return clearance >= self.length and size == self.size

Open End Wrench

from Wrench import *

class OpenEndWrench(Wrench):

def init(self, length, size_one, size_two): super().init(length) self.__size_one = size_one self.__size_two = size_two

@property def size_one(self): return self.__size_one

@property def size_two(self): return self.__size_two

def describe(self): return “CombinationWrench Length: {} SizeOne: {} SizeTwo: {}".format(self.length, self.size_one, self.size_two)

def tighten(self, clearance, size): return clearance >= self.length and (size == self.size_one or size == self.size_two)

Check Structure!

from Saw import *

class CrossCutSaw(Saw):

def init(self, length, materials): super().init(length) self.__materials = materials.split(":")

@property def materials(self): return “, “.join(self.__materials)

def describe(self): “CrossCutSaw Length: {} Materials: {}".format( self.length, self.materials)

additional methods here

from Saw import *

class CrossCutSaw(Saw):

def init(self, length, materials): super().init(length) self.__materials = materials.split(":")

@property def materials(self): return ”, “.join(self.__materials)

def describe(self): “CrossCutSaw Length: {} Materials: {}".format( self.length, self.materials)

additional methods here

from Saw import *

class CrossCutSaw(Saw):

def init(self, length, materials): super().init(length) self.__materials = materials.split(":")

@property def materials(self): return “, “.join(self.__materials)

def describe(self): “CrossCutSaw Length: {} Materials: {}".format( self.length, self.materials)

def __find_material(self, material): for m in self.__materials: if m == material: return True return False

additional methods here

from Saw import *

class CrossCutSaw(Saw):

def init(self, length, materials): super().init(length) self.__materials = materials.split(":")

@property def materials(self): return “, “.join(self.__materials)

def describe(self): “CrossCutSaw Length: {} Materials: {}".format( self.length, self.materials)

def __find_material(self, material): for m in self.__materials: if m == material: return True return False

def cut(self, length, material): return length < self.length and self.__find_material(material)

from Saw import *

class HackSaw(Saw):

def init(self, length): super().init(length)

def describe(self): return “HackSaw Length: {} Material: metal”. format(self.length)

def cut(self, length, material): return length < self.length and material == “metal”

Check Structure!

from Wrench import *
from AdjustableWrench import *
from CombinationWrench import *
from OpenEndWrench import *
from Saw import *
from HackSaw import *
from CrossCutSaw import *

import sys

class Main:

methods go here

main guard

if name == “main": Main.main(sys.argv)

from Wrench import *
from AdjustableWrench import *
from CombinationWrench import *
from OpenEndWrench import *
from Saw import *
from HackSaw import *
from CrossCutSaw import *

import sys

class Main:

# methods go here

main guard

if name == “main": Main.main(sys.argv)

@staticmethod
def read_input(filename):
  try:
    with open(filename) as reader:
      num_tools = int(reader.readline())
      tools = []
  return tools

except Exception: print(“Invalid Input”) return []

@staticmethod
def read_input(filename):
  try:
    with open(filename) as reader:
      num_tools = int(reader.readline())
      tools = []
      for i in range(0, num_tools):
  return tools

except Exception: print(“Invalid Input”) return []

@staticmethod
def read_input(filename):
  try:
    with open(filename) as reader:
      num_tools = int(reader.readline())
      tools = []
      for i in range(0, num_tools):
        line = reader.readline().split(" ")
  return tools

except Exception: print(“Invalid Input”) return []

@staticmethod
def read_input(filename):
  try:
    with open(filename) as reader:
      num_tools = int(reader.readline())
      tools = []
      for i in range(0, num_tools):
        line = reader.readline().split(" ")
    if line[0] == "AdjustableWrench":

    elif line[0] == "OpenEndWrench":

    elif line[0] == "CombinationWrench":

    elif line[0] == "CrossCutSaw":

    elif line[0] == "HackSaw":

    else:
      raise Exception("Unknown Tool: " + line[0])
  return tools

except Exception: print(“Invalid Input”) return []

@staticmethod
def read_input(filename):
  try:
    with open(filename) as reader:
      num_tools = int(reader.readline())
      tools = []
      for i in range(0, num_tools):
        line = reader.readline().split(" ")
        length = int(line[1])
        if line[0] == "AdjustableWrench":
          min_size = int(line[2])
          max_size = int(line[3])
          tools.append(AdjustableWrench(length, min_size, max_size))
        elif line[0] == "OpenEndWrench":
          size_one = int(line[2])
          size_two = int(line[3])
          tools.append(OpenEndWrench(length, size_one, size_two))
        elif line[0] == "CombinationWrench":
          size = int(line[2])
          tools.append(CombinationWrench(length, size))
        elif line[0] == "CrossCutSaw":
          tools.append(CrossCutSaw(length, line[2]))
        elif line[0] == "HackSaw":
          tools.append(HackSaw(length))
        else:
          raise Exception("Unknown Tool: " + line[0])
      return tools
  except Exception:
    print("Invalid Input")
    return []
@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  
@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":

elif query_parts[0] == “cut”:

else:

@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])

elif query_parts[0] == “cut”: length = int(query_parts[1])

else:

@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])
    for t in tools:
      if isinstance(t, Wrench):

elif query_parts[0] == “cut”: length = int(query_parts[1]) for t in tools: if isinstance(t, Saw):

else:

@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])
    for t in tools:
      if isinstance(t, Wrench):
        if t.tighten(clearance, size):
          return t

elif query_parts[0] == “cut”: length = int(query_parts[1]) for t in tools: if isinstance(t, Saw): if t.cut(length, query_parts[2]): return t

else:

@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])
    for t in tools:
      if isinstance(t, Wrench):
        if t.tighten(clearance, size):
          return t
    return ??
  elif query_parts[0] == "cut":
    length = int(query_parts[1])
    for t in tools:
      if isinstance(t, Saw):
        if t.cut(length, query_parts[2]):
          return t
    return ??
  else:
    return ??
@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])
    for t in tools:
      if isinstance(t, Wrench):
        if t.tighten(clearance, size):
          return t
    return None
  elif query_parts[0] == "cut":
    length = int(query_parts[1])
    for t in tools:
      if isinstance(t, Saw):
        if t.cut(length, query_parts[2]):
          return t
    return None
  else:
    return None
@staticmethod
def find_tool(tools, query):
  query_parts = query.split(" ")
  if query_parts[0] == "tighten":
    clearance = int(query_parts[1])
    size = int(query_parts[2])
    for t in tools:
      if isinstance(t, Wrench):
        if t.tighten(clearance, size):
          return t
    return None
  elif query_parts[0] == "cut":
    length = int(query_parts[1])
    for t in tools:
      if isinstance(t, Saw):
        if t.cut(length, query_parts[2]):
          return t
    return None
  else:
    return None
@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return
@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return

tools = Main.read_input(args[1])

@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return

tools = Main.read_input(args[1])

if len(tools) == 0: return

@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return

tools = Main.read_input(args[1])

if len(tools) == 0: return

try: with sys.stdin as reader:

except Exception: print(“Invalid Tool”) return

@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return

tools = Main.read_input(args[1])

if len(tools) == 0: return

try: with sys.stdin as reader: query = reader.readline() t = Main.find_tool(tools, query)

except Exception: print(“Invalid Tool”) return

@staticmethod
def main(args):
  if len(args) != 2:
    print("Invalid Input")
    return

tools = Main.read_input(args[1])

if len(tools) == 0: return

try: with sys.stdin as reader: query = reader.readline() t = Main.find_tool(tools, query) if t is not None: print(t.describe()) else: print(“Invalid Tool”) except Exception: print(“Invalid Tool”) return

"/js/highlight.pack.js"