Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
FidelElie committed Aug 17, 2018
0 parents commit d90911e
Show file tree
Hide file tree
Showing 14 changed files with 1,001 additions and 0 deletions.
Empty file added .gitignore
Empty file.
53 changes: 53 additions & 0 deletions DoCalculations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from Libraries.ProblemManipulator import ProblemManipulator
from Libraries.DoMath import DoMath
from Libraries.FileHandler import FileHandler
import os

def read_file():
"""Function to open the file to get the problem to be calculated"""
open_file = FileHandler("r") # calls the file handler class
problem_string = open_file.mod_string()
open_file.close_file()
return problem_string

def manipulate_problem(problem_string):
"""Function that manipulates the lists of string to be used for the calculations"""
math_problem = ProblemManipulator(problem_string) # calls problem manipulator class
math_problem.check_operators()
math_problem.ensure_single_ops()
outputs = math_problem.prob_manip()
return outputs[0], outputs[1], outputs[2]

def do_calculations(problem_numbers, problem_operators, op_start):
"""Function to do the main calculation"""
do_the_math = DoMath(problem_numbers, problem_operators, op_start) # calls the do math class
do_the_math.calculation()
answer = do_the_math.answer()
return answer

def write_file(answer):
"""Function to write answer back to file"""
open_file_to_write = FileHandler("w") # calls the file handler class again in a different file mode
open_file_to_write.write_answer(answer)
open_file_to_write.close_file()

def main():
"""Main Running Function"""
os.chdir(os.path.abspath("TextFiles"))
# calls function to read the text file to get the problem
problem_string = read_file()
# checks whether a problem was actually entered
if len(problem_string) != 0:
# calls function to sort and manipulate the problem so it can be calculated
problem_numbers, problem_operators, op_start = manipulate_problem(problem_string)
# calls function to calcualte the answer to the problem provided
answer = do_calculations(problem_numbers, problem_operators, op_start)
# calls function to write the calculated answer back to the file
write_file(answer)
else: # if there wasn't one entered then the answer is set to error so that can be sent back
answer = "Error"
write_file(answer)
# deletes the nul file created in the autohotkey script, so the while loop can be broken
os.remove("Nulfile.txt")
os.chdir("..")
main()
38 changes: 38 additions & 0 deletions DoMath.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
; Perliminary
DetectHiddenWindows, On ; needed to control a hidden window
; ------------ Hotstring Used -----------
::domath::

; ------------- Autohotkey Front End Initial ------------
; takes user problem, creates the file, puts problem in the file, creates nul file
FileDelete, TextFiles\ProblemAndAnswer.txt
Input, OutputVariable, IV *, {esc}, eq ; asks the user to enter their problem
LengthOfCalculation:= StrLen(OutputVariable) + 1 ; checks the string length
Send {ShiftDown} {Left %LengthOfCalculation%}{ShiftUp} {Backspace}
Sleep 5
Send Calculating ; just show the script is working
; adds the problem to the output file
FileAppend, %OutputVariable% , TextFiles\ProblemAndAnswer.txt
; adds a nul file to be deleted later in the python file (important)
FileAppend, , TextFiles\Nulfile.txt

; ---------- Python Back End ---------
; runs python script in hidden command prompt, modifies output file with answer
Run, cmd.exe, , Hide, pid2 ; opens a hidden comand prompt
Sleep 5 ; makes sure that the command prompt has come up
; While loop so as long as the nulfile exists the python command can run its entiriety
; without having to use sleep commands
While, FileExist("TextFiles\Nulfile.txt")
{
ControlSend, , python DoCalculations.py {enter}, ahk_pid %pid2% ; sends python command to hidden cmd
} ; only broken when the python command has run all the way through to the end
Process, Close, %pid2% ; closes the command prompt
Process, WaitClose, %pid2% ; waits for the command prompt to close

; ---------- Autohotkey Front End Final ---------
; reads the file with answer, and posts it in window
FileRead, OutputCalculation, TextFiles\ProblemAndAnswer.txt
Send {ShiftDown} {Left 12}{ShiftUp} {Backspace} ; deletes the calculating string
Sleep 5
Send, %OutputCalculation% ; Send the aswer of the problem back to the user
return
672 changes: 672 additions & 0 deletions LICENSE.md

Large diffs are not rendered by default.

113 changes: 113 additions & 0 deletions Libraries/DoMath.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import math

class DoMath(object):
"""Class that does the mathematics calculations"""
def __init__(self, numbers, operators, op_position):
self.numbers = numbers
self.operators = operators
self.op_position = op_position

def float_convert(self):
"""Method that converts the numbers strings to floats"""
for i in range(0, len(self.numbers)):
self.numbers[i] = float(self.numbers[i]) # maps all numbers to their float value

def check_first_op_position(self):
"""Method to check if the first position in the problem is an operation"""
if self.op_position == True: # operator was first in the calculation
mod_numb = float("{}{}".format(self.operators[0], self.numbers[0])) # add the operator to its number
self.numbers[0] = mod_numb # modify the number
del self.operators[0] # delete operator from list
else:
None

def check_special_chars(self):
"""Method for taking into account special constants"""
for i in range(0, len(self.numbers)):
if self.numbers[i].lower() == "e":
self.numbers[i] = math.e # converts e to its numerical value
elif self.numbers[i].lower() == "pi":
self.numbers[i] == math.pi # converts pi to its numerical value
else:
None

def calculation(self):
"Method loop used to calculate the problem"""
self.check_special_chars() # check for the constants
self.float_convert() # converts all the nunbers to floats
self.check_first_op_position() # - check method -
while len(self.operators) != 0: # loops calculation method over the amount of operators
self.idmas_procedure()

def idmas_procedure(self):
"""Method that uses idmas order for calculations"""
i = 0
while i < len(self.operators): # checks indices
if self.operators[i] == "**" or self.operators[i] == "^":
calculation = self.det_calc(self.numbers[i], self.numbers[i + 1], "ind")
self.remapper(i, calculation)
i += 1
else:
break
i = 0
while i < len(self.operators): # checks division
if self.operators[i] == "/":
calculation = self.det_calc(self.numbers[i], self.numbers[i + 1], "div")
self.remapper(i, calculation)
i += 1
else:
break
i = 0
while i < len(self.operators): # checks multiplication
if self.operators[i] == "x" or self.operators[i]=="*":
calculation = self.det_calc(self.numbers[i], self.numbers[i + 1], "mult")
self.remapper(i, calculation)
i += 1
else:
break
i = 0
while i < len(self.operators): # checks addition
if self.operators[i] == "+":
calculation = self.det_calc(self.numbers[i], self.numbers[i + 1], "add")
self.remapper(i, calculation)
i += 1
else:
break
i = 0
while i < len(self.operators): # checks subtraction
if self.operators[i] == "-":
calculation = self.det_calc(self.numbers[i], self.numbers[i + 1], "sub")
self.remapper(i, calculation)
i += 1
else:
break

def remapper(self, i, calculation):
"""Method used to modify the different lists for further calculations"""
del self.numbers[i +1]
del self.numbers[i]
del self.operators[i]
self.numbers.insert(i, calculation) # replaces both values with the new calcualted value

def answer(self):
"""Method to print final answer"""
check_for_integer = self.numbers[0].is_integer() # check if answer is an integer float
if check_for_integer == True:
self.numbers[0] = int(self.numbers[0]) # make it an integer i.e get rid of the decimal place
else:
None
return self.numbers[0]

def det_calc(self, A, B, operation_to_do):
"""Method to do the calculations between two of the numbers"""
if operation_to_do == "add": # adds two values
sub_calc = A + B
if operation_to_do == "sub": # subtracts two values
sub_calc = A - B
if operation_to_do == "mult": # multiplies two values
sub_calc = A * B
if operation_to_do == "div": # divides two values
sub_calc = A / B
if operation_to_do == "ind": # puts one value to the power of the other
sub_calc = A ** B
return sub_calc
Binary file added Libraries/DoMath.pyc
Binary file not shown.
25 changes: 25 additions & 0 deletions Libraries/FileHandler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os

class FileHandler(object):
"""Class that handles reading and writing to file"""
def __init__(self, mode):
self.file_name = "ProblemAndAnswer.txt"
self.mode = mode # defines what mode the file should be opened in
self.file_object = open(self.file_name, self.mode)

def mod_string(self):
"""Method used to read string from file and make it usable
byt the rest of the programme"""
defined_string = self.file_object.read()
defined_string = defined_string.split(" ") #gets rid of the spaces in between numbers and operators
del defined_string[-1] # deletes the "eq" that was used to show that the user was done entering the problem
return defined_string

def write_answer(self, answer):
"""Method to overwrite the file with the answer to the calculation"""
self.file_object.write(str(answer)) # converts the answer to a string to be written to the file

def close_file(self):
"""Method to close the file after use"""
self.file_object.close()

Binary file added Libraries/FileHandler.pyc
Binary file not shown.
57 changes: 57 additions & 0 deletions Libraries/ProblemManipulator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
class ProblemManipulator(object):
"""Class for doing the first manipulations of the problem object"""
def __init__(self, problem):
self.problem = problem
self.numbers = []
self.operations = []

def check_operators(self):
"""Method for working out whether the signs should change e.g.
if there is a number subtracted from a negative - - becomes +"""
for i in range(0, len(self.problem) - 1):
if self.problem[i] == "-" and self.problem[i + 1] == "+": # a - and + become -
del self.problem[i]
elif self.problem[i] == "+" and self.problem[i + 1] == "-": # a + and - become -
del self.problem[i]
elif self.problem[i] == "-" and self.problem[i + 1] == "-": # a - and - become +
del self.problem[i]
self.problem[i+1] = "+"
else:
continue

def ensure_single_ops(self):
"""Method to ensure that no two operations are next to eachother so
they can be sorted into numbers and operators very easily"""
for i in range(0, len(self.problem) - 1):
if self.problem[i] == "*" and self.problem[i + 1] == "-": # checks if there is a multiply and subtract sign next to eachother
mod_number = "{}{}".format(self.problem[i + 1], self.problem[i + 2])
self.problem[i + 1] = mod_number
del self.problem[i + 2]
elif self.problem[i] == "x" and self.problem[i + 1] == "-": # alternate multuplication sign
mod_number = "{}{}".format(self.problem[i + 1], self.problem[i + 2])
self.problem[i + 1] = mod_number
del self.problem[i + 2]
elif self.problem[i] == "/" and self.problem[i + 1] == "-": # checks if there is a division and subtract sign next to eachother
mod_number = "{}{}".format(self.problem[i + 1], self.problem[i + 2])
self.problem[i + 1] = mod_number
del self.problem[i + 2]
else:
continue

def prob_manip(self):
"""Method that sorts the problem into two different lists, one for the numbers
and one for the operators to be used on them"""
if self.problem[0] == "-" or self.problem[0] == "+":
self.operations.append(self.problem[0])
for i in range(1, len(self.problem), 2):
self.numbers.append(self.problem[i])
for i in range(2, len(self.problem), 2):
self.operations.append(self.problem[i])
op_postion = True # this determines whether an operator is first in the problem
else:
for i in range(0, len(self.problem), 2):
self.numbers.append(self.problem[i])
for i in range(1, len(self.problem), 2):
self.operations.append(self.problem[i])
op_postion = False # false means that a number is first in the problem.
return self.numbers, self.operations, op_postion
Binary file added Libraries/ProblemManipulator.pyc
Binary file not shown.
Empty file added Libraries/__init__.py
Empty file.
Binary file added Libraries/__init__.pyc
Binary file not shown.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SolveIt
This project allows you to do quick inline calculations while writing. By using autohotkey to look for a hostring and python to calculate it.

## Getting Started
These instructions will get you a copy of the project up and running on your local machine for development and testing puposes.

### Prerequisites
* The latest version of autohotkey if you are planning to just run the raw script.
* The lastest distribution of Python 2.7 whether you are running the Autohotkey executable or the raw script.

### Installation and Use
1. Place the folder whether you like and either run the executable file or run the raw .ahk script for the script to run.
2. Type the hotsring "domath" to activate the input process.
3. Type your mathematics problem with spaces between each number and operation.
4. When you are finished entering your desired problem leave a space and type "eq" (for equals).
5. And your problem will be calculate and outputted back to your window/
6. Enjoy

### Supported Operations
The operations follow BIDMAS order of calculation without the B as brackets are not supported yet (IDMAS)
* Indices can be calculated with inputting either a " ^ " or " ** " between two numbers.
* Division can be calculated by inputting a " / " between two numbers
* Multiplication can be calculated with inputting either a " x " or " * " between two numbers
* Addition can be calculated by inputting a " + " between two numbers
* Subtraction can be calculated by inputting a "-" between two numbers
You are able to put two operations next to eachother, the program will resolve to one operation upon calculation
e.g if you input "11 - - 11 eq" the program will resolve the two negatives to "11 + 11 eq"

## Built With
* Autohotkey
* Python 2.7

### Things To Improve
Other than optimisations to the python code, I want to find an easier way for Autohotkey and python to communicate with eachother
effectively. Right now i am using a Run command for the cmd and sending the python command to it for them to communicate with
eachother. It works surpringly well but it is not ideal. This process is outlined in DoMath.ahk file.

Also I want to find a way to make the calculation happen in real-time. So the programme will recognize without the use of a hotkey or hotstring
that you are typing a problem and automatically solve it for you.

### License
This project is licensed under the GNU General Public License v3.0 - see the LICENSE.md file for details
1 change: 1 addition & 0 deletions TextFiles/ProblemAndAnswer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Error

0 comments on commit d90911e

Please sign in to comment.