### commented and cleaned up code

parent 6d69bce5
No preview for this file type
 # base tree code from http://knuth.luther.edu/~leekent/CS2Plus/chap6/chap6.html # changed this code to allow for variable functions, and change infix expressions to postfix # added variable node class to consider when both nodes have variables in them ''' AICogSci Final Project base tree code from http://knuth.luther.edu/~leekent/CS2Plus/chap6/chap6.html Added: - EquationTree class to generate a specialized tree - Branch and Equals Node classes to make printing more legible - canEval, getInverse and inorder methods to most of the nodes to allow further functionality - VariableNode class was added to account for nodes with variables - add_to_tree and generate_tree methods used to create and change equation tree class''' import queue ... ... @@ -73,7 +80,6 @@ class EquationTree: q.enqueue(currentNode.right) print(q.dequeue().value, end =' ') class Branch: def __init__(self): self.value = "\n" ... ... @@ -93,19 +99,6 @@ class TimesNode: def eval(self): '''if check_if_variables(str(self.left.eval()), str(self.right.eval())) == "both_vars": v1 = str(self.left.eval()).split("x") v2 = str(self.right.eval()).split("x") evalStr = v1 + "*" + v2 return eval(evalStr) else: return self.left.eval() * self.right.eval()''' #if isinstance(self.left, VariableNode) and isinstance(self.right,VariableNode): # return self.left.eval()*self.right.eval() #elif isinstance(self.left,VariableNode) or isinstance(self.right,VariableNode): # print("can't combine variables of differing types") #need some sort of combined node here i think #else: return self.left.eval() * self.right.eval() def inorder(self): ... ... @@ -129,9 +122,6 @@ class PlusNode: return MinusNode(None,None) def eval(self): #print("left value ", self.left) #print(isinstance(self.left, NumNode)) #print("right value ", self.right.value()) return self.left.eval() + self.right.eval() ... ... @@ -187,44 +177,11 @@ class VariableNode: return int(self.value.split("x")) def canEval(self): return False #not an operator return False def inorder(self): return str(self.eval()) def check_if_variables(x, y): if 'x' in x and 'x' in y: return "both_vars" elif 'x' in x or 'x' in y: return "one_var" else: return "both_const" def E(q): if q.isEmpty(): raise ValueError("Invalid Prefix Expression") token = q.dequeue() if token == "+": return PlusNode(E(q),E(q)) if token == "*": return TimesNode(E(q),E(q)) if token == "-": return MinusNode(E(q), E(q)) #try: if "x" in token: output = VariableNode(token) # make a different class for variable node else: output = NumNode(int(token)) #except: # print("Not a valid operation, need variables of like terms") # output = NumNode(float(0)) return output OPERATORS = set(['+', '-', '*', '/', '(', ')']) PRIORITY = {'+':1, '-':1, '*':2, '/':2} ... ... @@ -251,8 +208,6 @@ def infix_to_prefix(formula): b = exp_stack.pop() exp_stack.append( op+" "+b+" "+a ) op_stack.append(ch) # leftover while op_stack: op = op_stack.pop() a = exp_stack.pop() ... ... @@ -312,67 +267,4 @@ def generate_tree(equation): add_to_tree(q2, t.root, False) # add expression tree to right side of equation tree t.printTree() return t def eval_tree(expression): '''x = NumNode(5) y = NumNode(4) p = PlusNode(x,y) t = TimesNode(p, NumNode(6)) root = PlusNode(t, NumNode(3)) print(root.eval()) print(root.inorder())''' #x = input("Please enter a prefix expression: ") x = infix_to_prefix(expression) lst = x.split() q = queue.Queue() for token in lst: q.enqueue(token) root = E(q) result = root.eval() print(root.eval()) print(root.inorder()) return result #print(infix_to_prefix("3 + 4 - 6")) def split_equation(equation): expressions = equation.split("=") return expressions def main(): #exp = split_equation("4x * 3x + 2") #x = eval_tree(exp) '''eqTree = EquationTree() x1 = VariableNode("4x") x2 = NumNode(3) x3 = NumNode(2) x4 = NumNode(7) t = PlusNode(x1,x2) t2 = PlusNode(x3,x4) eqTree.root.left = t eqTree.root.right = t2 eqTree.printTree()''' equationTree = generate_tree("4x + 3 = 2 + 7") print(equationTree.root.left.canEval()) print(equationTree.root.right.canEval()) newNode = NumNode(equationTree.root.right.eval()) equationTree.updateNode(equationTree.root, False, newNode) equationTree.printTree() equationTree.get_expression() ''' print("old node should be 2, is ", oldNum.value) print("moved node should be 7, is ", moveNode.value) print("new op is ", newOp.value) ''' if __name__ == "__main__": main() \ No newline at end of file return t \ No newline at end of file
 ... ... @@ -5,12 +5,19 @@ import tree import queue class TutorState: ''' Class to store the state that the tutor thinks the equation is in Tracks this by generating an equation tree from the tree.py file, and moving nodes accordingly ''' def __init__(self,equation): '''Initializes tree with an equation, and generates equation tree from this equation.''' self.equation = equation self.expressions = equation.split("=") self.tree = tree.generate_tree(equation) def move_values(self, left, constants): ''' If the user is moving either variables or constants, the tutor will call this function to rearrange nodes in the tree accordingly ''' moveNode = None newOp = None q = queue.Queue() ... ... @@ -26,11 +33,10 @@ class TutorState: else: # if moving variables nodeType = tree.VariableNode emptyNode = tree.NumNode(0) print("node is ", node) if isinstance(node, tree.PlusNode) or isinstance(node, tree.MinusNode): # if plus or minus node if node.canEval() == False: # if can't evaluate children, need to move one # if can't evaluate children, need to move one to the other side newOp = node.getInverse() if isinstance(node.left, nodeType): moveNode = node.left ... ... @@ -38,10 +44,9 @@ class TutorState: elif isinstance(node.right, nodeType): moveNode = node.right node.right = emptyNode moved = False moved = False # trackes if a node has been moved yet while not q.isEmpty() and not moved: currentNode = q.front() print("currentNode is ", currentNode.value) if currentNode.left != None: if isinstance(currentNode.left, nodeType): oldNum = currentNode.left ... ... @@ -59,10 +64,8 @@ class TutorState: moved = True q.enqueue(currentNode.right) if isinstance(currentNode, nodeType) and not moved: # case where there is no operator and want to shift node over oldNum =currentNode print("old node should be 2, is ", oldNum.value) print("moved node should be 7, is ", moveNode.value) print("new op is ", newOp.value) if left: self.tree.root.left = newOp self.tree.root.left.left = oldNum ... ... @@ -73,40 +76,58 @@ class TutorState: self.tree.root.right.right = moveNode moved=True q.dequeue() # will need to change this to just combine variables 4x + 0x if left: self.combine_like_terms(False) else : self.combine_like_terms(True) if left: self.combine_like_terms(False) else: self.combine_like_terms(True) return self.tree.get_expression() def combine_like_terms(self, left): ''' Combines like terms on a designated side of the tree by simplifying like terms. ''' self.tree.get_expression() print("COMBINING LIKE TERMS") if left: print("evaluating left side") self.tree.evaluate(self.tree.root, True) else: print("evaluating right side") self.tree.evaluate(self.tree.root, False) return self.tree.get_expression() def compare_Equations(self, equation1, equation2): ''' Compares two equations to see if both sides are equivalent, regardless of their order Assumes equations have operators that do not require a specific order ''' equation1 = "".join(equation1.split()) equation2 = "".join(equation2.split()) eq1 = equation1.split('=') eq2 = equation2.split('=') eq1list = [] eq2list = [] for side in eq1: eq1list.append(sorted(re.split('[-|+|*|/]',side))) for side in eq2: eq2list.append(sorted(re.split('[-|+|*|/]',side))) #print(eq1list,eq2list) return eq1list==eq2list class UserState(ccm.Model): #ccm.ProductionSystem #moveConstants = "0" # move constants is 0 when need to move them, 1 when move variables, 2 when neither ready = False class UserState(ccm.Model): ''' Class for the user state to track where the user is in their solution ''' def __init__(self, equation): ''' Initializes the model itself, saves the equation, initial sides of the equation and initial count of variable types. ''' ccm.Model.__init__(self) self.equation = equation self.oldEquation = None self.sides = self.getLeftandRightVals() self.constantCount = self.getConstantCount() self.state = None self.end = False def get_input(self): ''' Gets input from the user by showing them the current state and asking for the next one. Takes their input and saves all needed information to process it accordingly. ''' outputString = "Equation is currently: " + str(self.equation) + "\nWhat is your next step? " user_step = input(outputString) #figure out what user step means # call some get_state() function comparing user step to what state should be user_step = input(outputString) self.oldEquation = self.equation self.equation = user_step oldSides = self.sides ... ... @@ -114,14 +135,11 @@ class UserState(ccm.Model): #ccm.ProductionSystem oldConstantCount = self.constantCount self.constantCount = self.getConstantCount() self.state = self.get_state(oldConstantCount) #print("state is ", self.state) #return oldConstantCount def getLeftandRightVals(self): ''' Splits equation to get left and right sides of equation ''' expressions = self.equation.split("=") leftVars = None rightVars = None try: leftVars = re.split("[+-]", expressions) rightVars = re.split("[+-]", expressions) ... ... @@ -132,6 +150,8 @@ class UserState(ccm.Model): #ccm.ProductionSystem return [leftVars, rightVars] def getConstantCount(self): ''' Counts number of variables of each type on each side of the equation ''' constantsOnLeft = 0 variablesOnLeft = 0 constantsOnRight = 0 ... ... @@ -149,63 +169,46 @@ class UserState(ccm.Model): #ccm.ProductionSystem return [variablesOnLeft, constantsOnLeft, variablesOnRight, constantsOnRight] def isConstant(self, value): ''' Given a value, checks if it is a constant. ''' if not value.isdigit(): return False return True def get_state(self, oldConstantCount): # based on number of variables constants on each side of the equation, the agent guesses which state the user is moving to print("old: ", oldConstantCount) print("new: ", self.constantCount) ''' Based on number of variables and constants on each side of the equation the agent guesses which state the user is moving to ''' if oldConstantCount != self.constantCount and oldConstantCount != self.constantCount: # if not same number of variables as before for both sides then moved variables print("variables were moved") self.state = "move_variables 1" if oldConstantCount < self.constantCount: self.state = "move_variables 1" else: self.state = "move_variables 0" elif oldConstantCount != self.constantCount or oldConstantCount != self.constantCount: print("variables were added") if oldConstantCount > self.constantCount: self.state = "add_variables 1" else: self.state = "add_variables 0" elif oldConstantCount != self.constantCount and oldConstantCount != self.constantCount: print("constants were moved") if oldConstantCount < self.constantCount: #moving constants to left self.state = "move_constants 1" else: self.state = "move_constants 0" elif oldConstantCount != self.constantCount or oldConstantCount != self.constantCount: print("constants were added") if oldConstantCount > self.constantCount: self.state = "add_constants 1" else: self.state = "add_constants 0" else: print("nothing triggered") # need to do this for division and simplifying fraction if oldConstantCount > self.constantCount: self.state = "add_constants 1" else: self.state = "add_constants 0" else: print("nothing triggered") return self.state '''def moveConstants(self): print("Constants moved to one side of equation") self.state = "move_constants" def moveVariables(self): print("Variables moved to one side of equation") self.state = "move_variables"''' # dont think i need these functions anymore # look at how to structure UserState () to not run every function class IntelligentTutor(ACTR): ''' RBES for the tutor itself. Tracks states ''' goal = Buffer() user = UserState("4x+7=5x+2") tutor = TutorState("4x + 7 = 5x + 2") #tutor.move_constants_right() #tutor.combine_like_terms(False) #tutor.combine_like_terms(True) def init(): user.get_input() print("USER STATE IS ", user.state) # need to get user input to translate to state goal.set(user.state) #get_state(cc) goal.set(user.state) def moved_constants(goal="move_constants ?left"): #true if moving constants left tutorEq = tutor.move_values(bool(int(left)), True) ... ... @@ -228,7 +231,7 @@ class IntelligentTutor(ACTR): goal.set("check_state " + tutorEq) def check_state(goal = "check_state ?tutorEq"): if tutorEq == user.equation: if tutor.compare_Equations(tutorEq, user.equation): user.get_input() goal.set(user.state) else: ... ... @@ -236,7 +239,6 @@ class IntelligentTutor(ACTR): def incorrect_state(goal = "invalid_state ?tutorEqn"): print("You have entered an invalid state. We anticipated the correct step to be: ", tutorEqn, "\nPlease continue solving the problem with the corrected equation.") # need to print what correct state would have been user.equation = tutorEqn user.get_input() goal.set(user.state) ... ... @@ -248,12 +250,11 @@ class IntelligentTutor(ACTR): class EmptyEnvironment(ccm.Model): pass def main(): env_name = EmptyEnvironment() agent_name = IntelligentTutor() env_name.agent = agent_name ccm.log_everything(env_name) env_name.agent = agent_name #ccm.log_everything(env_name) # log statement, uncomment if you want to log information env_name.run() main() \ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment