Skip to main content
3 of 4
edited tags
200_success
  • 145.6k
  • 22
  • 191
  • 481

Calculator using variable names

I've recently been assigned an assignment to create a word calculator, and given my knowledge in python is still quite lacking, I want to ask if anybody has any better ideas for any possible solutions.

The question is here:

Jimmy has invented a new kind of calculator that works with words
rather than numbers.

  • Input is read from stdin and consists of up to 1000 commands, one per line.

  • Each command is a definition, a calculation or clear.

  • All tokens within a command are separated by single spaces.

  • A definition has the format def x y where x is a variable name and y is an integer in the range [-1000, 1000].

  • Existing definitions are replaced by new ones i.e. if x has been defined previously, defining x again erases its old definition.

  • Variable names consist of 1-30 lowercase characters.

  • No two variables are ever defined to have the same value at the same time.

  • The clear command erases all existing variable definitions.

  • A calculation command starts with the word calc, and is followed by one or more variable names separated by addition or subtraction operators.

  • The end of a calculation command is an equals sign.

The goal is to write a program for Jimmy's calculator. Some rules are:

  • The program should produce no output for definitions, but for calculations it should output the value of the calculation.
  • Where there is no word for the result, or some word in a calculation has not been defined, then the output should be unknown. (The word unknown is never used as a variable name.)
  • Your solution may only import content from the sys module.
  • Your solution may not use the eval() function.

Here is a sample input below:

calc foo + bar =
def bar 7
def programming 10
calc foo + bar =
def is 4
def fun 8
calc programming - is + fun =
def fun 1
calc programming - is + fun =
clear

And the corresponding output:

foo + bar = unknown
foo + bar = programming
programming - is + fun = unknown
programming - is + fun = bar

My current solution is this:

import sys
lines = sys.stdin.readlines()

d_define = {}
numsInDict = []
operators = ["+", "-", "="]

# IN : word to checked it is in the dictionary
# OUT : returns unknown or value for word
def lookup(word):
    if word in d_define:
        return d_define[word]
    else:
        return "unknown"

# IN : answer to check if there is a word assigned to it a dictionary
# OUT : returns unknown or word assigned to answer
def getAnswer(answer):
    for k, v in d_define.items():
        if v == answer:
            return k
    return "unknown"

# IN : All values to calc (includes operators)
# OUT : print unknown or word if in dict
def calc(args):
    equation = 0
    lastOperator = "+"
    for word in args:
        if word not in operators:
            res = lookup(word)
            if res == "unknown":
                return "unknown"
            else:
                #print(res)
                if lastOperator == "+":
                    equation += res
                else:
                    equation -= res
        else:
            lastOperator = word
    if equation in numsInDict:
        res = getAnswer(equation)
        return res
    else:
        return "unknown"

# IN : word to be added and its value
# OUT : updated dictionary
def define(word, num):
    num = int(num)
    if num in numsInDict or word in d_define:
        # print(f'NEEDS REPLACE')
        # print(f'same value -> {num in numsInDict}')
        # print(f'same word -> {word in d_define}')
        # print(f'same word -> {d_define}')
        # print(f'same word -> {numsInDict}')
        topop = ""
        for k, v in d_define.items():
            if k == word:
                d_define[word] = num  # Update Word with new value
            elif v == num:
                topop = k  # Saves value to pop later
        if topop != "":
            d_define.pop(topop)
            d_define[word] = num
    else:
        d_define[word] = num
        numsInDict.append(num)
    #print(f'{word} - {d_define[word]}')

for line in lines:
    #print(f'-------------------------------------- LOOP START ------------------------------------')
    line = line.rstrip().split()
    #print(f'Line Split - {line}')
    if len(line) == 3 and line[0] == "def":
        define(line[1], line[2])
    elif len(line) > 1 and line[len(line) - 1] == "=":
        result = calc(line[1:])
        print(f'{" ".join(line[1:]) + " " + result}')
    elif len(line) == 1 and line[0] == "clear":
        d_define = {}
        wordsInDict = []
        numsInDict = []
        #print(f'Cleared d_define - {d_define} {wordsInDict}')
    #print(d_define)
    #print(f'--------------------------------------- LOOP END -------------------------------------')

It does feel quite clunky but it gets the job done. I am just wondering if anybody has any better ways in which it could be improved upon - and hearing your own different approaches and solutions would be awesome!