Commit 16a63a41 authored by mrk022's avatar mrk022
Browse files

can follow user steps up until fraction reduction

parent c37c1241
# Equation Tree class
# AI Final Project
# Takes an equation of the form x + 3 = 5 + x and makes this into an equation tree
# this means = is in root and each expression is a tree on either side
# currently only works for addition and two variables on each side of equation
class EquationTreeNode:
def __init__(self, value, parent=None):
self.value = value
self.left = None
self.right = None
self.parent = parent
def setLeft(self, newNode):
self.left = newNode
def setRight(self, newNode):
self.right = newNode
def addLeftNode(self, newNode):
self.left = newNode
newNode.parent = self
def addRightNode(self, newNode):
self.right = newNode
newNode.parent = self
def splitExpression(self, expression):
expressions = expression.split("+")
leftNode = EquationTreeNode(expressions[0])
rightNode = EquationTreeNode(expressions[1])
self.addLeftNode(leftNode)
self.addRightNode(rightNode)
'''def main():
equation = "3x+5=2+2x"
expressions = equation.split("=")
rootNode = EquationTreeNode("=", None)
leftNode = EquationTreeNode("+")
rootNode.addLeftNode(leftNode)
splitExpression(expressions[0], leftNode)
rightNode = EquationTreeNode("+")
rootNode.addRightNode(rightNode)
splitExpression(expressions[1], rightNode)
print(rootNode.value)
print(rootNode.left.value, rootNode.right.value)
print(rootNode.left.left.value, rootNode.left.right.value, rootNode.right.left.value, rootNode.right.right.value)
main() '''
\ No newline at end of file
...@@ -28,12 +28,17 @@ class EquationTree: ...@@ -28,12 +28,17 @@ class EquationTree:
self.inorder(node.right) self.inorder(node.right)
def evaluate(self, parent, left): def evaluate(self, parent, left):
# can simplify this to call helper function
if left: if left:
if parent.left.canEval(): if parent.left.canEval():
print("parent.left.left is ", parent.left.left.value)
print("parent.left.right is ", parent.left.right)
if isinstance(parent.left.left, NumNode): if isinstance(parent.left.left, NumNode):
print("num node")
print("evaluating", parent.left.eval()) print("evaluating", parent.left.eval())
newNode = NumNode(parent.left.eval()) newNode = NumNode(parent.left.eval())
else: else:
print("variable node")
print("evaluating", parent.left.eval()) print("evaluating", parent.left.eval())
newNode = VariableNode(str(parent.left.eval()) + "x") newNode = VariableNode(str(parent.left.eval()) + "x")
parent.left = newNode parent.left = newNode
...@@ -113,14 +118,20 @@ class PlusNode: ...@@ -113,14 +118,20 @@ class PlusNode:
self.value = "+" self.value = "+"
def canEval(self): def canEval(self):
if isinstance(self.left, VariableNode) == isinstance(self.right,VariableNode): if isinstance(self.left, VariableNode) and isinstance(self.right,VariableNode):
return True return True
return False elif isinstance(self.left, NumNode) and isinstance(self.right, NumNode):
return True
else:
return False
def getInverse(self): def getInverse(self):
return MinusNode(None,None) return MinusNode(None,None)
def eval(self): 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() return self.left.eval() + self.right.eval()
...@@ -134,9 +145,12 @@ class MinusNode: ...@@ -134,9 +145,12 @@ class MinusNode:
self.value = "-" self.value = "-"
def canEval(self): def canEval(self):
if isinstance(self.left, VariableNode) == isinstance(self.right,VariableNode): if isinstance(self.left, VariableNode) and isinstance(self.right,VariableNode):
return True
elif isinstance(self.left, NumNode) and isinstance(self.right, NumNode):
return True return True
return False else:
return False
def getInverse(self): def getInverse(self):
return PlusNode(None, None) return PlusNode(None, None)
...@@ -353,6 +367,12 @@ def main(): ...@@ -353,6 +367,12 @@ def main():
equationTree.printTree() equationTree.printTree()
equationTree.get_expression() 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__": if __name__ == "__main__":
main() main()
\ No newline at end of file
import ccm import ccm
import re import re
from ccm.lib.actr import * from ccm.lib.actr import *
#from expressionTree import EquationTreeNode
import tree import tree
import queue import queue
...@@ -11,27 +10,40 @@ class TutorState: ...@@ -11,27 +10,40 @@ class TutorState:
self.expressions = equation.split("=") self.expressions = equation.split("=")
self.tree = tree.generate_tree(equation) self.tree = tree.generate_tree(equation)
def move_constants_right(self): def move_values(self, left, constants):
moveNode = None moveNode = None
node = self.tree.root.left newOp = None
q = queue.Queue()
if left: # if moving values from right to left
node = self.tree.root.right
q.enqueue(self.tree.root.left)
else: # if moving values from left to right
node = self.tree.root.left
q.enqueue(self.tree.root.right)
if constants: # if moving constants
nodeType = tree.NumNode
emptyNode = tree.VariableNode("0x")
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 isinstance(node, tree.PlusNode) or isinstance(node, tree.MinusNode):
# if plus or minus node # if plus or minus node
if node.canEval() == False: if node.canEval() == False:
# if can't evaluate children, need to move one # if can't evaluate children, need to move one
newOp = node.getInverse() newOp = node.getInverse()
if isinstance(node.left, tree.NumNode): if isinstance(node.left, nodeType):
moveNode = node.left moveNode = node.left
node.left = tree.VariableNode("0x") node.left = emptyNode
elif isinstance(node.right,tree.NumNode): elif isinstance(node.right, nodeType):
moveNode = node.right moveNode = node.right
node.right = tree.VariableNode("0x") node.right = emptyNode
q = queue.Queue()
q.enqueue(self.tree.root.right)
moved = False moved = False
while not q.isEmpty() and not moved: while not q.isEmpty() and not moved:
currentNode = q.front() currentNode = q.front()
print("currentNode is ", currentNode.value)
if currentNode.left != None: if currentNode.left != None:
if isinstance(currentNode.left, tree.NumNode): if isinstance(currentNode.left, nodeType):
oldNum = currentNode.left oldNum = currentNode.left
currentNode.left = newOp currentNode.left = newOp
currentNode.left.left = oldNum currentNode.left.left = oldNum
...@@ -39,27 +51,43 @@ class TutorState: ...@@ -39,27 +51,43 @@ class TutorState:
moved = True moved = True
q.enqueue(currentNode.left) q.enqueue(currentNode.left)
if currentNode.right != None and not moved: if currentNode.right != None and not moved:
if isinstance(currentNode.right, tree.NumNode): if isinstance(currentNode.right, nodeType):
oldNum = currentNode.right oldNum = currentNode.right
currentNode.right = newOp currentNode.right = newOp
currentNode.right.left = oldNum currentNode.right.left = oldNum
currentNode.right.right = moveNode currentNode.right.right = moveNode
moved = True moved = True
q.enqueue(currentNode.right) q.enqueue(currentNode.right)
if isinstance(currentNode, nodeType) and not moved:
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
self.tree.root.left.right = moveNode
else:
self.tree.root.right = newOp
self.tree.root.right.left = oldNum
self.tree.root.right.right = moveNode
moved=True
q.dequeue() q.dequeue()
self.combine_like_terms(True) # will need to change this to just combine variables 4x + 0x # will need to change this to just combine variables 4x + 0x
if left: self.combine_like_terms(False)
else : self.combine_like_terms(True)
return self.tree.get_expression() return self.tree.get_expression()
#self.tree.printTree()
#self.tree.get_expression()
def combine_like_terms(self, left): def combine_like_terms(self, left):
self.tree.get_expression() self.tree.get_expression()
print("COMBINING LIKE TERMS") print("COMBINING LIKE TERMS")
if left: if left:
print("evaluating left side")
self.tree.evaluate(self.tree.root, True) self.tree.evaluate(self.tree.root, True)
else: else:
print("evaluating right side")
self.tree.evaluate(self.tree.root, False) self.tree.evaluate(self.tree.root, False)
self.tree.get_expression() return self.tree.get_expression()
class UserState(ccm.Model): #ccm.ProductionSystem class UserState(ccm.Model): #ccm.ProductionSystem
...@@ -72,11 +100,6 @@ class UserState(ccm.Model): #ccm.ProductionSystem ...@@ -72,11 +100,6 @@ class UserState(ccm.Model): #ccm.ProductionSystem
self.oldEquation = None self.oldEquation = None
self.sides = self.getLeftandRightVals() self.sides = self.getLeftandRightVals()
self.constantCount = self.getConstantCount() self.constantCount = self.getConstantCount()
#self.generate_tree()
#self.moveconstants = ["4x=5x+2-7","4x+7-2=5x", "7-2=1x", "-1x+7-2=0"]
#self.movevariables = ["7=5x-4x+2", "4x-5x+7=2"]
#self.addconstants = ["4x=5x-5","4x+5=5x"]
#self.addvariables = ["7=1x+2", "-1x+7=2"]
self.state = None self.state = None
self.end = False self.end = False
...@@ -90,13 +113,15 @@ class UserState(ccm.Model): #ccm.ProductionSystem ...@@ -90,13 +113,15 @@ class UserState(ccm.Model): #ccm.ProductionSystem
self.sides = self.getLeftandRightVals() self.sides = self.getLeftandRightVals()
oldConstantCount = self.constantCount oldConstantCount = self.constantCount
self.constantCount = self.getConstantCount() self.constantCount = self.getConstantCount()
#self.state = self.get_state(oldConstantCount) self.state = self.get_state(oldConstantCount)
#print("state is ", self.state) #print("state is ", self.state)
return oldConstantCount #return oldConstantCount
def getLeftandRightVals(self): def getLeftandRightVals(self):
expressions = self.equation.split("=") expressions = self.equation.split("=")
leftVars = None
rightVars = None
try: try:
leftVars = re.split("[+-]", expressions[0]) leftVars = re.split("[+-]", expressions[0])
rightVars = re.split("[+-]", expressions[1]) rightVars = re.split("[+-]", expressions[1])
...@@ -114,53 +139,57 @@ class UserState(ccm.Model): #ccm.ProductionSystem ...@@ -114,53 +139,57 @@ class UserState(ccm.Model): #ccm.ProductionSystem
for value in self.sides[0]: for value in self.sides[0]:
if self.isConstant(value): if self.isConstant(value):
constantsOnLeft += 1 constantsOnLeft += 1
else: elif 'x' in value:
variablesOnLeft += 1 variablesOnLeft += 1
for value in self.sides[1]: for value in self.sides[1]:
if self.isConstant(value): if self.isConstant(value):
constantsOnRight += 1 constantsOnRight += 1
else: elif 'x' in value:
variablesOnRight += 1 variablesOnRight += 1
return [variablesOnLeft, constantsOnLeft, variablesOnRight, constantsOnRight] return [variablesOnLeft, constantsOnLeft, variablesOnRight, constantsOnRight]
print("There are ", variablesOnLeft, " variables on the left and ", constantsOnLeft, " constants on the left")
print("There are ", variablesOnRight, " variables on the right and ", constantsOnRight, " constants on the right")
def isConstant(self, value): def isConstant(self, value):
if 'x' in value: if not value.isdigit():
print(value)
return False return False
return True return True
def get_state(self, oldConstantCount): 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 # based on number of variables constants on each side of the equation, the agent guesses which state the user is moving to
print("old constant count ", oldConstantCount) print("old: ", oldConstantCount)
print("self.constantcount ", self.constantCount) print("new: ", self.constantCount)
if oldConstantCount[0] != self.constantCount[0] and oldConstantCount[2] != self.constantCount[2]: if oldConstantCount[0] != self.constantCount[0] and oldConstantCount[2] != self.constantCount[2]:
# if not same number of variables as before for both sides then moved variables # if not same number of variables as before for both sides then moved variables
print("variables were moved") print("variables were moved")
self.state = "move_variables" self.state = "move_variables 1"
elif oldConstantCount[0] != self.constantCount[0] or oldConstantCount[2] != self.constantCount[2]: elif oldConstantCount[0] != self.constantCount[0] or oldConstantCount[2] != self.constantCount[2]:
print("variables were added") print("variables were added")
self.state = "add_variables" if oldConstantCount[0] > self.constantCount[0]: self.state = "add_variables 1"
else: self.state = "add_variables 0"
elif oldConstantCount[1] != self.constantCount[1] and oldConstantCount[3] != self.constantCount[3]: elif oldConstantCount[1] != self.constantCount[1] and oldConstantCount[3] != self.constantCount[3]:
print("constants were moved") print("constants were moved")
self.state = "move_constants" if oldConstantCount[1] < self.constantCount[1]: #moving constants to left
self.state = "move_constants 1"
else:
self.state = "move_constants 0"
elif oldConstantCount[1] != self.constantCount[1] or oldConstantCount[3] != self.constantCount[3]: elif oldConstantCount[1] != self.constantCount[1] or oldConstantCount[3] != self.constantCount[3]:
print("constants were added") print("constants were added")
self.state = "add_constants" if oldConstantCount[1] > self.constantCount[1]:
self.state = "add_constants 1"
else:
self.state = "add_constants 0"
else: else:
print("nothing triggered") print("nothing triggered")
# need to do this for division and simplifying fraction # need to do this for division and simplifying fraction
return self.state return self.state
def moveConstants(self): '''def moveConstants(self):
print("Constants moved to one side of equation") print("Constants moved to one side of equation")
self.state = "move_constants" self.state = "move_constants"
def moveVariables(self): def moveVariables(self):
print("Variables moved to one side of equation") print("Variables moved to one side of equation")
self.state = "move_variables" self.state = "move_variables"''' # dont think i need these functions anymore
# look at how to structure UserState () to not run every function # look at how to structure UserState () to not run every function
...@@ -174,43 +203,41 @@ class IntelligentTutor(ACTR): ...@@ -174,43 +203,41 @@ class IntelligentTutor(ACTR):
#tutor.combine_like_terms(True) #tutor.combine_like_terms(True)
def init(): def init():
cc = user.get_input() user.get_input()
print("USER STATE IS ", user.state) # need to get user input to translate to state print("USER STATE IS ", user.state) # need to get user input to translate to state
goal.set(user.get_state(cc)) # goal.set(user.state) #get_state(cc)
def moved_constants(goal="move_constants ?left"): #true if moving constants left
tutorEq = tutor.move_values(bool(int(left)), True)
print("user equation ",user.equation)
goal.set("check_state " + tutorEq)
def add_constants(goal= "add_constants ?left"):
tutorEq = tutor.combine_like_terms(bool(int(left)))
print("user equation ",user.equation)
goal.set("check_state " + tutorEq)
def moved_variables(goal="move_variables ?left"):
tutorEq = tutor.move_values(bool(int(left)), False)
print("user equation ",user.equation)
goal.set("check_state " + tutorEq)
def add_variables(goal = "add_variables ?left"):
tutorEq = tutor.combine_like_terms(bool(int(left)))
print("user equation", user.equation)
goal.set("check_state " + tutorEq)
def moved_constants(goal="move_constants"): #user="ready:True" def check_state(goal = "check_state ?tutorEq"):
tutorEq = tutor.move_constants_right()
if tutorEq == user.equation: if tutorEq == user.equation:
user.get_input() user.get_input()
goal.set(user.state) goal.set(user.state)
else: else:
print("INVALID") goal.set("invalid_state " + tutorEq)
goal.set("end_process")
#if it is invalid then move to invalid state, and return correct state we found in that function
#print("constants")
#goal.set("add_constants")
def add_constants(goal= "add_constants"):
# use tree functionality to add constants, pass in expression with two constants to expression tree and solve
# generate new correct equation based on this result
# check if user input is the same as what we caluclated
# if it is correct then
user.get_input()
goal.set(user.state)
# if it is invalid then move to the invalid state
def moved_variables(goal="move_variables"):
#user.moveVariables()
print("variables")
goal.set("add_variables")
def add_variables(goal = "add_variables"): def incorrect_state(goal = "invalid_state ?tutorEqn"):
print("add") print("You have entered an invalid state. We anticipated the correct step to be: ", tutorEqn, "\nPlease continue solving the problem with the corrected equation.")
goal.set("end_process")
def incorrect_state(goal = "invalid state"):
print("You have entered an invalid state. We anticipated the correct step to be: \n Please continue solving the problem with the corrected equation above.")
# need to print what correct state would have been # need to print what correct state would have been
user.equation = tutorEqn
user.get_input() user.get_input()
goal.set(user.state) goal.set(user.state)
...@@ -223,8 +250,6 @@ class EmptyEnvironment(ccm.Model): ...@@ -223,8 +250,6 @@ class EmptyEnvironment(ccm.Model):
def main(): def main():
#eqn = "3x + 4 = 0"
env_name = EmptyEnvironment() env_name = EmptyEnvironment()
agent_name = IntelligentTutor() agent_name = IntelligentTutor()
env_name.agent = agent_name env_name.agent = agent_name
......
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