-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpression_tree_puzzle.py
207 lines (175 loc) · 7.37 KB
/
expression_tree_puzzle.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
"""
CSC148, Winter 2021
Assignment 2: Automatic Puzzle Solver
==============================
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
Authors: Diane Horton, Jonathan Calver, Sophia Huynh,
Maryam Majedi, and Jaisie Sin.
All of the files in this directory are:
Copyright (c) 2021 Diane Horton, Jonathan Calver, Sophia Huynh,
Maryam Majedi, and Jaisie Sin.
=== Module Description ===
This module contains the ExpressionTreePuzzle class.
"""
from __future__ import annotations
from typing import List, Dict
from expression_tree import ExprTree
from puzzle import Puzzle
from adts import Queue
class ExpressionTreePuzzle(Puzzle):
""""
An expression tree puzzle.
=== Public Attributes ===
variables: the dictionary of variable name (str) - value (int) pairs
A variable is considered "unassigned" unless it has a
non-zero value.
target: the target value for the expression tree to evaluate to
=== Private Attributes ===
_tree: the expression tree
=== Representation Invariants ===
- variables contains a key for each variable appearing in _tree
- all values stored in variables are single digit integers (0-9).
"""
_tree: ExprTree
variables: Dict[str, int]
target: int
def __init__(self, tree: ExprTree, target: int) -> None:
"""
Create a new expression tree puzzle given the provided
expression tree and the target value. The variables are initialized
using the tree's populate_lookup method.
>>> puz = ExpressionTreePuzzle(ExprTree('a', []), 4)
>>> puz.variables == {'a': 0}
True
>>> puz.target
4
"""
self.variables = {}
tree.populate_lookup(self.variables)
self._tree = tree
self.target = target
# TODO (Task 5) override is_solved
def is_solved(self) -> bool:
"""
Return True iff ExpressionTreePuzzle self is solved.
The puzzle is solved if all variables have been assigned a non-zero
value and the expression tree evaluates to the target value.
>>> exp_t = ExprTree('+', [ExprTree('a', []), ExprTree('b', [])])
>>> puz = ExpressionTreePuzzle(exp_t, 7)
>>> puz.is_solved()
False
>>> puz.variables['a'] = 7
>>> puz.is_solved()
False
>>> puz.variables['a'] = 5
>>> puz.variables['b'] = 2
>>> puz.is_solved()
True
"""
for key in self.variables:
if self.variables[key] == 0:
return False
if self._tree.eval(self.variables) != self.target:
return False
return True
# TODO (Task 5) override __str__
def __str__(self) -> str:
"""
Return a string representation of this ExpressionTreePuzzle.
The first line should show the dictionary of variables and the
second line should show the string representation of the algebraic
equation represented by the puzzle.
>>> exprt = ExprTree('+', [ExprTree('*', \
[ExprTree('a', []), \
ExprTree('+', [ExprTree('b', []), \
ExprTree(6, []), \
ExprTree(6, []), \
])]), \
ExprTree(5, [])])
>>> puz = ExpressionTreePuzzle(exprt, 61)
>>> print(puz)
{'a': 0, 'b': 0}
((a * (b + 6 + 6)) + 5) = 61
"""
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, '*', '+']
d = {}
for key in self.variables:
if key not in lst and not key.isnumeric():
d[key] = self.variables[key]
return "{}\n{} = {}".format(d, self._tree.__str__(), self.target)
# TODO (Task 5) override extensions
def extensions(self) -> List[ExpressionTreePuzzle]:
"""
Return the list of legal extensions of this ExpressionTreePuzzle.
A legal extension is a new ExpressionTreePuzzle equal to this
ExpressionTreePuzzle, except that it assigns a single currently
unassigned variable a value in the range 1-9.
A variable is "unassigned" if it has a value of 0.
A copy of the expression tree and variables dictionary should be
used in each extension made, so as to avoid unintended aliasing.
>>> exp_t = ExprTree('a', [])
>>> puz = ExpressionTreePuzzle(exp_t, 7)
>>> exts_of_puz = puz.extensions()
>>> len(exts_of_puz) == 9
True
>>> exts_of_an_ext = exts_of_puz[0].extensions()
>>> len(exts_of_an_ext) == 0
True
>>> exp_t = ExprTree('a', [ExprTree('b', [])])
>>> puz = ExpressionTreePuzzle(exp_t, 8)
>>> exts_of_puz = puz.extensions()
>>> len(exts_of_puz) == 18
True
"""
lst = [] # the list of expression tree puzzle
record = [] # record of the variables
for key in self.variables: # the variable in self.variable()
if self.variables[key] == 0:
record.append(key)
for item in record:
for i in range(1, 10):
copy = self._tree.copy()
a = ExpressionTreePuzzle(copy, self.target)
b = self.variables.copy()
b[item] = i
a.variables = b
lst.append(a)
return lst
# TODO (TASK 5): override fail_fast
# The specifics of how you implement this are up to you.
# Hint 1: remember that a puzzle can only be extended by assigning a value
# to an unassigned variable.
# Hint 2: remember that our expression tree only supports addition,
# multiplication, and non-negative integers.
def fail_fast(self) -> bool:
"""
Return True if this ExpressionTreePuzzle can be quickly determined to
have no solution, False otherwise.
"""
min_tree, max_tree = self._tree.copy(), self._tree.copy()
min_vars, max_vars = self.variables.copy(), self.variables.copy()
for key in min_vars:
if min_vars[key] == 0:
min_vars[key] = 1
for key in max_vars:
if key != "*" and key != "+" and max_vars[key] == 0:
max_vars[key] = 9
min_val = min_tree.eval(min_vars)
max_val = max_tree.eval(max_vars)
return not min_val <= self.target <= max_val
if __name__ == "__main__":
import python_ta
python_ta.check_all(config={'pyta-reporter': 'ColorReporter',
'allowed-io': [],
'allowed-import-modules': ['doctest',
'python_ta',
'typing',
'__future__',
'expression_tree'],
'disable': ['E1136'],
'max-attributes': 15}
)