├── Labs ├── Lab 8 │ ├── chart.xls │ ├── handout.pdf │ └── test_sort.py ├── Lab 1 │ ├── handout.pdf │ ├── lab1_tester.py │ ├── sample_solutions.py │ └── lab1.py ├── Lab 2 │ ├── handout.pdf │ ├── test_lab2 │ ├── speclab2.txt │ ├── lab2.py │ ├── NumericGradeEntry.py │ ├── LetterGradeEntry.py │ └── BookRoster.py ├── Lab 3 │ ├── handout.pdf │ ├── stack_client.py │ ├── queue_client.py │ ├── stack.py │ ├── Solution_queue.py │ ├── csc148_queue.py │ ├── teststack.py │ └── testqueue.py ├── Lab 4 │ └── handout.pdf ├── Lab 5 │ ├── handout.pdf │ ├── extra_exercise.py │ ├── ex5.py │ ├── recursion_exercise.py │ ├── test_list_even_ex5.py │ ├── test_list_even_basic.py │ ├── test_count_all_ex5.py │ ├── test_count_all_basic.py │ ├── test_count_above_ex5.py │ ├── test_count_above_basic.py │ ├── test_count_even_ex5.py │ └── test_count_even_basic.py ├── Lab 6 │ ├── handout.pdf │ ├── csc148_queue.py │ ├── test_count_leaves_basic.py │ ├── test_sum_leaves_basic.py │ ├── test_sum_internal_basic.py │ └── test_count_internal_basic.py └── Lab 7 │ ├── handout.pdf │ ├── pylint.txt │ ├── test_count_leaves_basic.py │ ├── test_sum_leaves_basic.py │ ├── test_sum_internal_basic.py │ └── test_concatenate_leaves_basic.py ├── Lecture Slides ├── Week 2 │ └── w2.pdf ├── Week 3 │ └── w3.pdf ├── Week 4 │ └── w4.pdf ├── Week 5 │ └── w5.pdf ├── Week 6 │ └── w6.pdf ├── Week 7 │ └── w7.pdf ├── Week 8 │ └── w8.pdf ├── Week 9 │ └── w9.pdf ├── Week 10 │ └── w10.pdf ├── Week 11 │ └── w11.pdf ├── Week 12 │ └── w12.pdf └── Week 1 │ └── intro.pdf ├── Midterms ├── Term Test 1 │ ├── t1a.pdf │ ├── t1_v1.pdf │ ├── t1_v2.pdf │ ├── t1_v3.pdf │ ├── t12015.pdf │ ├── t12016.pdf │ ├── t12015 with solutions.pdf │ ├── t12016 with solutions.pdf │ ├── balanced_paranthesis.py │ ├── try_exception.py │ ├── stack_api.py │ └── point.py └── Term Test 2 │ ├── t2_2016.pdf │ ├── t2_2017.pdf │ ├── t2_v1_solution.pdf │ ├── t2_v2_solution.pdf │ ├── t2_v3_solution.pdf │ ├── t2_2016_solution.pdf │ ├── t2_2017_solution.pdf │ └── t2_collection_additional_practice_no_sol.py ├── Assignments ├── Assignment 1 │ ├── a1.pdf │ ├── strategy.py │ ├── a1_pyta.txt │ ├── state.py │ ├── subtract_square.py │ ├── chopstick.py │ ├── game_interface.py │ ├── subtract_square_state.py │ └── chopstick_state.py └── Assignment 2 │ ├── a2.pdf │ ├── game.py │ ├── a2_pyta.txt │ ├── game_state.py │ ├── subtract_square_game.py │ ├── subtract_square_state.py │ ├── game_interface.py │ └── strategy.py └── README.md /Labs/Lab 8/chart.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 8/chart.xls -------------------------------------------------------------------------------- /Labs/Lab 1/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 1/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 2/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 2/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 3/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 3/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 4/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 4/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 5/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 5/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 6/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 6/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 7/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 7/handout.pdf -------------------------------------------------------------------------------- /Labs/Lab 8/handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Labs/Lab 8/handout.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 2/w2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 2/w2.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 3/w3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 3/w3.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 4/w4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 4/w4.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 5/w5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 5/w5.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 6/w6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 6/w6.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 7/w7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 7/w7.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 8/w8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 8/w8.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 9/w9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 9/w9.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t1a.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t1a.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 10/w10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 10/w10.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 11/w11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 11/w11.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 12/w12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 12/w12.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t1_v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t1_v1.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t1_v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t1_v2.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t1_v3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t1_v3.pdf -------------------------------------------------------------------------------- /Assignments/Assignment 1/a1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Assignments/Assignment 1/a1.pdf -------------------------------------------------------------------------------- /Assignments/Assignment 2/a2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Assignments/Assignment 2/a2.pdf -------------------------------------------------------------------------------- /Lecture Slides/Week 1/intro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Lecture Slides/Week 1/intro.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t12015.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t12015.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t12016.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t12016.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_2016.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_2016.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_2017.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_v1_solution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_v1_solution.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_v2_solution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_v2_solution.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_v3_solution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_v3_solution.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_2016_solution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_2016_solution.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_2017_solution.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 2/t2_2017_solution.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t12015 with solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t12015 with solutions.pdf -------------------------------------------------------------------------------- /Midterms/Term Test 1/t12016 with solutions.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiCUI6/CSC148-2018-Winter/HEAD/Midterms/Term Test 1/t12016 with solutions.pdf -------------------------------------------------------------------------------- /Labs/Lab 1/lab1_tester.py: -------------------------------------------------------------------------------- 1 | """ 2 | a test for calss RaceRegistry 3 | """ 4 | 5 | if __name__ == "__main__": 6 | from lab1 import RaceRegistry 7 | r1 = RaceRegistry() 8 | r1.add_member('gerhard@mail.utoronto.ca', 'under 40 minutes') 9 | r1.add_member('tom@mail.utoronto.ca', 'under 30 minutes') 10 | r1.add_member('toni@mail.utoronto.ca', 'under 20 minutes') 11 | r1.add_member('margot@mail.utoronto.ca', 'under 30 minutes') 12 | r1.add_member('gerhard@mail.utoronto.ca', 'under 30 minutes') 13 | result = r1.search_members('under 30 minutes') 14 | print(r1) 15 | print(result) 16 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | module strategy for game players 3 | """ 4 | 5 | import random 6 | from typing import Any 7 | 8 | 9 | def interactive_strategy(game: Any) -> Any: 10 | """ 11 | Return a move for game through interactively asking the user for input. 12 | """ 13 | move = input("Enter a move: ") 14 | return game.str_to_move(move) 15 | 16 | 17 | def random_strategy(game: Any) -> Any: 18 | """ 19 | return a move for game randomly 20 | """ 21 | return random.choice(game.current_state.get_possible_moves()) 22 | 23 | 24 | if __name__ == '__main__': 25 | import python_ta 26 | python_ta.check_all(config="a1_pyta.txt") 27 | -------------------------------------------------------------------------------- /Labs/Lab 2/test_lab2: -------------------------------------------------------------------------------- 1 | """ 2 | module test lab2 3 | """ 4 | 5 | 6 | from NumericGradeEntry import NumericGradeEntry 7 | from LetterGradeEntry import LetterGradeEntry 8 | 9 | 10 | if __name__ == '__main__': 11 | grades = [NumericGradeEntry('csc148', 0.5, '87'), 12 | NumericGradeEntry('mat137', 1.0, '76'), 13 | LetterGradeEntry('his450', 0.5, 'B+')] 14 | for g in grades: 15 | print("weight: {}, grade: {}, points: {}".format( 16 | g.course_weight, g.course_grade, g.get_points())) 17 | 18 | total = sum([g.course_weight * g.get_points() for g in grades]) 19 | total_weight = sum([g.course_weight for g in grades]) 20 | print("GPA: {}".format(total / total_weight)) 21 | -------------------------------------------------------------------------------- /Labs/Lab 3/stack_client.py: -------------------------------------------------------------------------------- 1 | """ 2 | module stack client code 3 | """ 4 | 5 | from stack import Stack 6 | from typing import List 7 | 8 | 9 | def list_stack(list: list, stack: Stack) -> None: 10 | """ 11 | some function to use class stack 12 | 13 | >>> a2 = Stack() 14 | >>> list_stack([1, [3, [5, 7], 9], 11], a2) 15 | 11 16 | 9 17 | 7 18 | 5 19 | 3 20 | 1 21 | """ 22 | for item in list: 23 | stack.add(item) 24 | while not stack.is_empty(): 25 | remove = stack.remove() 26 | if type(remove) == type(list): 27 | for thing in remove: 28 | stack.add(thing) 29 | else: 30 | print(remove) 31 | 32 | 33 | if __name__ == '__main__': 34 | a1 = Stack() 35 | while True: 36 | b1 = input('Type a srting:') 37 | a1.add(b1) 38 | if b1 == 'end': 39 | break 40 | while not a1.is_empty(): 41 | print(a1.remove()) 42 | -------------------------------------------------------------------------------- /Labs/Lab 3/queue_client.py: -------------------------------------------------------------------------------- 1 | """ 2 | module queue client code 3 | """ 4 | 5 | from queue import Queue 6 | from csc148_queue import Queue 7 | from typing import List 8 | 9 | 10 | def list_queue(list: List, queue: Queue) -> None: 11 | """ 12 | test class Queue3 13 | 14 | >>> queue = Queue() 15 | >>> list_queue([1, [3, [5, 7], 9], 11], queue) 16 | 1 17 | 11 18 | 3 19 | 9 20 | 5 21 | 7 22 | """ 23 | for item in list: 24 | queue.add(item) 25 | while not queue.is_empty(): 26 | remove = queue.remove() 27 | if type(remove) == type(list): 28 | for thing in remove: 29 | queue.add(thing) 30 | else: 31 | print(remove) 32 | 33 | 34 | if __name__ == '__main__': 35 | q1 = Queue() 36 | a = int(input('Choose an integer:')) 37 | sum = 0 38 | while True: 39 | q1.add(a) 40 | sum += a 41 | a = int(input('Choose an integer:')) 42 | if a == 148: 43 | break 44 | print(sum) 45 | -------------------------------------------------------------------------------- /Midterms/Term Test 1/balanced_paranthesis.py: -------------------------------------------------------------------------------- 1 | """ use a stack to check whether parentheses are balanced 2 | """ 3 | from stack_api import Stack 4 | 5 | 6 | def balanced_delimiters(s: str) -> bool: 7 | """ 8 | Return whether the delimiters in string s 9 | are balanced. 10 | 11 | Assume: Only delimiters are brackets, parentheses, braces 12 | 13 | >>> balanced_delimiters("[({])}") 14 | False 15 | >>> balanced_delimiters("[({})]]") 16 | False 17 | >>> balanced_delimiters("[[]") 18 | False 19 | >>> balanced_delimiters("[(){}]") 20 | True 21 | """ 22 | st = Stack() 23 | left_delim = {")": "(", "]": "[", "}": "{"} 24 | for c in s: 25 | if c not in "()[]{}": 26 | pass 27 | elif c in "([{": 28 | st.add(c) 29 | elif not st.is_empty(): 30 | assert c in ")]}" 31 | if left_delim[c] != st.remove(): 32 | return False 33 | else: 34 | return False 35 | pass 36 | return st.is_empty() 37 | 38 | 39 | if __name__ == '__main__': 40 | import doctest 41 | doctest.testmod() 42 | -------------------------------------------------------------------------------- /Midterms/Term Test 1/try_exception.py: -------------------------------------------------------------------------------- 1 | # Experiment with exceptions changing what is commented out 2 | # in the try block 3 | class SpecialException(Exception): 4 | """class docstring here --- child of Exception""" 5 | pass 6 | class ExtremeException(SpecialException): 7 | """ grandchild of Exception""" 8 | pass 9 | 10 | if __name__ == '__main__': 11 | num =1 12 | denum=0 13 | try: 14 | if(denum==0): 15 | # raise SpecialException('I am a SpecialException') 16 | raise Exception('I am an Exception') 17 | # raise ExtremeException('I am an ExtremeException') 18 | else: 19 | print(num/denum) 20 | # block to run if SpecialException was raised 21 | # use the name se if one is detected 22 | except ExtremeException as se: 23 | print(se) 24 | print('caught as ExtremeException') 25 | except SpecialException as ee: 26 | print(ee) 27 | print('caught as SpecialException') 28 | except Exception as e: 29 | print(e) 30 | print('caught as Exception') 31 | 32 | print('I am outside try') 33 | print('my code did not stop due to exception') 34 | -------------------------------------------------------------------------------- /Labs/Lab 6/csc148_queue.py: -------------------------------------------------------------------------------- 1 | class Queue: 2 | ''' Represent a FIFO queue. 3 | ''' 4 | 5 | def __init__(self): 6 | ''' (Queue) -> NoneType 7 | 8 | Create and initialize new queue self. 9 | ''' 10 | self._data = [] 11 | 12 | def add(self, o): 13 | ''' (Queue, object) -> NoneType 14 | 15 | Add o at the back of this queue. 16 | ''' 17 | self._data.append(o) 18 | 19 | def remove(self): 20 | ''' (Queue) -> object 21 | 22 | Remove and return front object from self. 23 | 24 | >>> q = Queue() 25 | >>> q.add(3) 26 | >>> q.add(5) 27 | >>> q.remove() 28 | 3 29 | ''' 30 | return self._data.pop(0) 31 | 32 | def is_empty(self): 33 | ''' (Queue) -> bool 34 | 35 | Return True queue self is empty, False otherwise. 36 | 37 | >>> q = Queue() 38 | >>> q.add(5) 39 | >>> q.is_empty() 40 | False 41 | >>> q.remove() 42 | 5 43 | >>> q.is_empty() 44 | True 45 | ''' 46 | return self._data == [] 47 | 48 | 49 | if __name__ == '__main__': 50 | import doctest 51 | doctest.testmod() 52 | -------------------------------------------------------------------------------- /Midterms/Term Test 1/stack_api.py: -------------------------------------------------------------------------------- 1 | """ implement stack ADT 2 | """ 3 | 4 | 5 | class Stack: 6 | """ Last-in, first-out (LIFO) stack. 7 | """ 8 | 9 | def __init__(self) -> None: 10 | """ Create a new, empty Stack self. 11 | 12 | >>> s = Stack() 13 | """ 14 | self._contains = [] 15 | 16 | def add(self, obj: object) -> None: 17 | """ Add object obj to top of Stack self. 18 | 19 | >>> s = Stack() 20 | >>> s.add(5) 21 | """ 22 | self._contains.append(obj) 23 | 24 | def remove(self) -> object: 25 | """ 26 | Remove and return top element of Stack self. 27 | 28 | Assume Stack self is not emp. 29 | 30 | >>> s = Stack() 31 | >>> s.add(5) 32 | >>> s.add(7) 33 | >>> s.remove() 34 | 7 35 | """ 36 | return self._contains.pop() 37 | 38 | def is_empty(self) -> bool: 39 | """ 40 | Return whether Stack self is empty. 41 | 42 | >>> s = Stack() 43 | >>> s.is_empty() 44 | True 45 | >>> s.add(5) 46 | >>> s.is_empty() 47 | False 48 | """ 49 | return len(self._contains) == 0 50 | 51 | 52 | if __name__ == "__main__": 53 | import doctest 54 | doctest.testmod() 55 | -------------------------------------------------------------------------------- /Labs/Lab 3/stack.py: -------------------------------------------------------------------------------- 1 | """ 2 | stack class materials 3 | """ 4 | 5 | 6 | class Stack: 7 | """ 8 | Last-in, first-out (LIFO) stack. 9 | """ 10 | 11 | def __init__(self) -> None: 12 | """ 13 | Create a new, empty Stack self. 14 | 15 | >>> s = Stack() 16 | """ 17 | self._contents = [] 18 | 19 | def add(self, obj: object) -> None: 20 | """ 21 | Add object obj to top of Stack self. 22 | 23 | >>> s = Stack() 24 | >>> s.add(7) 25 | """ 26 | self._contents.append(obj) 27 | 28 | def remove(self) -> object: 29 | """ 30 | Remove and return top element of Stack self. 31 | 32 | Assume Stack self is not empty. 33 | 34 | >>> s = Stack() 35 | >>> s.add(5) 36 | >>> s.add(7) 37 | >>> s.remove() 38 | 7 39 | """ 40 | return self._contents.pop() 41 | 42 | def is_empty(self) -> bool: 43 | """ 44 | Return whether Stack self is empty. 45 | 46 | >>> s = Stack() 47 | >>> s.is_empty() 48 | True 49 | >>> s.add(7) 50 | >>> s.is_empty() 51 | False 52 | """ 53 | return len(self._contents) == 0 54 | 55 | 56 | if __name__ == "__main__": 57 | import doctest 58 | doctest.testmod() 59 | -------------------------------------------------------------------------------- /Labs/Lab 3/Solution_queue.py: -------------------------------------------------------------------------------- 1 | """ 2 | queue implementation 3 | """ 4 | 5 | 6 | class Queue: 7 | """ 8 | A first-in, first-out (FIFO) queue. 9 | """ 10 | 11 | def __init__(self) -> None: 12 | """ 13 | Create and initialize new Queue self. 14 | 15 | >>> q = Queue() 16 | """ 17 | self._items = [] 18 | 19 | def add(self, obj: object) -> None: 20 | """ 21 | Add object at the back of Queue self. 22 | 23 | >>> q = Queue() 24 | >>> q.add(7) 25 | """ 26 | self._items.append(obj) 27 | 28 | def remove(self) -> object: 29 | """ 30 | Remove and return front object from Queue self. 31 | 32 | Queue self must not be empty. 33 | 34 | >>> q = Queue() 35 | >>> q.add(3) 36 | >>> q.add(5) 37 | >>> q.remove() 38 | 3 39 | """ 40 | return self._items.pop(0) 41 | 42 | def is_empty(self) -> bool: 43 | """ 44 | Return whether Queue self is empty 45 | 46 | >>> q = Queue() 47 | >>> q.add(5) 48 | >>> q.is_empty() 49 | False 50 | >>> q.remove() 51 | 5 52 | >>> q.is_empty() 53 | True 54 | """ 55 | return len(self._items) == 0 56 | 57 | 58 | if __name__ == '__main__': 59 | import doctest 60 | doctest.testmod() 61 | -------------------------------------------------------------------------------- /Labs/Lab 3/csc148_queue.py: -------------------------------------------------------------------------------- 1 | """ 2 | queue implementation 3 | """ 4 | 5 | 6 | class Queue: 7 | """ 8 | A first-in, first-out (FIFO) queue. 9 | """ 10 | 11 | def __init__(self) -> None: 12 | """ 13 | Create and initialize new Queue self. 14 | 15 | >>> q = Queue() 16 | """ 17 | self._contents = [] 18 | 19 | def add(self, obj: object) -> None: 20 | """ 21 | Add object at the back of Queue self. 22 | 23 | >>> q = Queue() 24 | >>> q.add(7) 25 | """ 26 | self._contents.append(obj) 27 | 28 | def remove(self) -> object: 29 | """ 30 | Remove and return front object from Queue self. 31 | 32 | Queue self must not be empty. 33 | 34 | >>> q = Queue() 35 | >>> q.add(3) 36 | >>> q.add(5) 37 | >>> q.remove() 38 | 3 39 | """ 40 | return self._contents.pop(0) 41 | 42 | def is_empty(self) -> bool: 43 | """ 44 | Return whether Queue self is empty 45 | 46 | >>> q = Queue() 47 | >>> q.add(5) 48 | >>> q.is_empty() 49 | False 50 | >>> q.remove() 51 | 5 52 | >>> q.is_empty() 53 | True 54 | """ 55 | return self._contents == [] 56 | 57 | 58 | if __name__ == '__main__': 59 | import doctest 60 | doctest.testmod() 61 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/game.py: -------------------------------------------------------------------------------- 1 | """ 2 | Superclass Game 3 | """ 4 | from typing import Any 5 | from game_state import GameState 6 | 7 | 8 | class Game: 9 | """ 10 | Abstract class for a game to be played with two players. 11 | """ 12 | 13 | def __init__(self, p1_starts: bool) -> None: 14 | """ 15 | Initialize this Game, using p1_starts to find who the first player is. 16 | """ 17 | raise NotImplementedError 18 | 19 | def get_instructions(self) -> str: 20 | """ 21 | Return the instructions for this Game. 22 | """ 23 | raise NotImplementedError 24 | 25 | def is_over(self, state: GameState) -> bool: 26 | """ 27 | Return whether or not this game is over at state. 28 | """ 29 | raise NotImplementedError 30 | 31 | def is_winner(self, player: str) -> bool: 32 | """ 33 | Return whether player has won the game. 34 | 35 | Precondition: player is 'p1' or 'p2'. 36 | """ 37 | raise NotImplementedError 38 | 39 | def str_to_move(self, string: str) -> Any: 40 | """ 41 | Return the move that string represents. If string is not a move, 42 | return some invalid move. 43 | """ 44 | raise NotImplementedError 45 | 46 | 47 | if __name__ == "__main__": 48 | from python_ta import check_all 49 | check_all(config="a2_pyta.txt") 50 | -------------------------------------------------------------------------------- /Labs/Lab 5/extra_exercise.py: -------------------------------------------------------------------------------- 1 | """ 2 | recursion list_odd and count_odd 3 | """ 4 | from typing import List, Union 5 | 6 | 7 | def list_odd(obj: Union[list, int]) -> List[int]: 8 | """ 9 | Return a list of all odd integers in obj, 10 | or sublists of obj, if obj is a list. If obj is an odd 11 | integer, return a list containing obj. Otherwise return 12 | en empty list. 13 | 14 | >>> list_odd(3) 15 | [3] 16 | >>> list_odd(16) 17 | [] 18 | >>> list_odd([1, 2, 3, 4, 5]) 19 | [1, 3, 5] 20 | >>> list_odd([1, 2, [3, 4], 5]) 21 | [1, 3, 5] 22 | >>> list_odd([1, [2, [3, 4]], 5]) 23 | [1, 3, 5] 24 | """ 25 | if isinstance(obj, int): 26 | if obj % 2 == 1: 27 | return [obj] 28 | else: 29 | return [] 30 | else: 31 | return sum([list_odd(x) for x in obj], []) 32 | 33 | 34 | def count_odd(obj: Union[list, int]) -> int: 35 | """ 36 | Return the number of odd numbers in obj or sublists of obj 37 | if obj is a list. Otherwise, if obj is a number, return 0 38 | if it is an even number and 1 if it is an odd number. 39 | 40 | >>> count_odd(3) 41 | 1 42 | >>> count_odd(16) 43 | 0 44 | >>> count_odd([1, 2, [3, 4], 5]) 45 | 3 46 | """ 47 | if isinstance(obj, int): 48 | if obj % 2 == 1: 49 | return 1 50 | else: 51 | return 0 52 | else: 53 | return sum([count_odd(x) for x in obj]) 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CSC148-2018-Winter Introduction to Computer Science 2 | Course materials of CSC148 in 2018 Winter at the University of Toronto 3 | 4 | ## Contents 5 | - Lecture Slides: Official leture slides for CSC148 in University of Toronto 6 | 7 | - Labs: Labs with my solutions (some including sample solutions) 8 | 9 | - Midterms: Different versions of midterms with corresponding sample solutions 10 | 11 | - Assignments: Two assignments including handouts (starter code) and my solutions 12 | 13 | (Assignment 2 is much more interesting. I basically implemented an AI (actually it is Minimax Algorithm in Game Theory) for the two games, i.e. subtract square and stonehenge. 14 | 15 | See more details in Assignment/Assignment 2/strategy.py) 16 | 17 | ## License 18 | 19 | All materials are under [Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)](https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en). 20 | 21 | According to the license, **you are free to:** 22 | - **Share** - copy and redistribute the material in any medium or format 23 | 24 | - **Adapt** - remix, transform, and build upon the material 25 | 26 | The licensor cannot revoke these freedoms as long as you follow the license terms. 27 | 28 | **Under the following terms:** 29 | - **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 30 | 31 | - **NonCommercial** — You may not use the material for commercial purposes. 32 | 33 | - **ShareAlike** — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 34 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/a1_pyta.txt: -------------------------------------------------------------------------------- 1 | [ELIF] 2 | 3 | # Set maximum allowed if nesting. 4 | max-nested-blocks = 3 5 | 6 | [FORMAT] 7 | 8 | # Set the maximum line length. The maximum line length in pep8 is 80 characters. 9 | max-line-length = 80 10 | 11 | [FORBIDDEN IMPORT] 12 | 13 | # Set the whitelist of modules that are allowed to be imported 14 | allowed-import-modules=doctest, unittest, hypothesis, python_ta 15 | 16 | [FORBIDDEN IO] 17 | 18 | # Comma-separated names of functions that are allowed to contain IO actions 19 | allowed-io = 20 | 21 | [MESSAGES CONTROL] 22 | 23 | # Disable the message, report, category or checker with the given id(s). 24 | disable=R0401, R0901, R0903, R0904, R0911, R0916, W0402, W0403, W0410, 25 | W1501, W1502, W1505, E1300, E1301, E1302, E1304, W1300, W1301, W1302, W1304, 26 | E1124, E1125, E1129, E1132, W1402, W0105, E1303, W1306, W1307, C0123, 27 | E0116, E0114, E0112, E0115, E0106, E0113, E0111, E0105, E0100, E0117, 28 | W0150, W0120, W0124, W0108, W0123, W0122, W0110, C0122, C0200, W0141, 29 | W0640, W0623, W0614, W0604, W0603, W0602, W0601, E0604, E0603, E1200, 30 | E1201, E1202, W1201, E1205, E1206, similarities, newstyle, python3, 31 | W0512, C0403, C0401, C0402, E1701, E1700, W0332, C0327, C0328, E0202, 32 | E0241, E0704, W0211, W0232, W0511, R0204, C0303, W0231, E9998, R0201, E9999 33 | 34 | # Enable single-letter identifiers 35 | function-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 36 | variable-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 37 | attr-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 38 | argument-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 39 | method-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 40 | class-attribute-rgx = ([A-Za-z_][A-Za-z0-9_]{0,30}|(__.*__))$ -------------------------------------------------------------------------------- /Assignments/Assignment 2/a2_pyta.txt: -------------------------------------------------------------------------------- 1 | [ELIF] 2 | 3 | # Set maximum allowed if nesting. 4 | max-nested-blocks = 3 5 | 6 | [FORMAT] 7 | 8 | # Set the maximum line length. The maximum line length in pep8 is 80 characters. 9 | max-line-length = 80 10 | 11 | [FORBIDDEN IMPORT] 12 | 13 | # Set the whitelist of modules that are allowed to be imported 14 | allowed-import-modules=doctest, unittest, hypothesis, python_ta 15 | 16 | [FORBIDDEN IO] 17 | 18 | # Comma-separated names of functions that are allowed to contain IO actions 19 | allowed-io = 20 | 21 | [MESSAGES CONTROL] 22 | 23 | # Disable the message, report, category or checker with the given id(s). 24 | disable=R0401, R0901, R0903, R0904, R0911, R0916, W0402, W0403, W0410, 25 | W1501, W1502, W1505, E1300, E1301, E1302, E1304, W1300, W1301, W1302, W1304, 26 | E1124, E1125, E1129, E1132, W1402, W0105, E1303, W1306, W1307, C0123, 27 | E0116, E0114, E0112, E0115, E0106, E0113, E0111, E0105, E0100, E0117, 28 | W0150, W0120, W0124, W0108, W0123, W0122, W0110, C0122, C0200, W0141, 29 | W0640, W0623, W0614, W0604, W0603, W0602, W0601, E0604, E0603, E1200, 30 | E1201, E1202, W1201, E1205, E1206, similarities, newstyle, python3, 31 | W0512, C0403, C0401, C0402, E1701, E1700, W0332, C0327, C0328, E0202, 32 | E0241, E0704, W0211, W0232, W0511, R0204, C0303, W0231, E9998, R0201, E9999 33 | 34 | # Enable single-letter identifiers 35 | function-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 36 | variable-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 37 | attr-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 38 | argument-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 39 | method-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 40 | class-attribute-rgx = ([A-Za-z_][A-Za-z0-9_]{0,30}|(__.*__))$ -------------------------------------------------------------------------------- /Labs/Lab 7/pylint.txt: -------------------------------------------------------------------------------- 1 | [ELIF] 2 | 3 | # Set maximum allowed if nesting. 4 | max-nested-blocks = 3 5 | 6 | [FORMAT] 7 | 8 | # Set the maximum line length. The maximum line length in pep8 is 80 characters. 9 | max-line-length = 80 10 | 11 | [FORBIDDEN IMPORT] 12 | 13 | # Set the whitelist of modules that are allowed to be imported 14 | allowed-import-modules=doctest, unittest, hypothesis, python_ta 15 | 16 | [FORBIDDEN IO] 17 | 18 | # Comma-separated names of functions that are allowed to contain IO actions 19 | allowed-io = 20 | 21 | [MESSAGES CONTROL] 22 | 23 | # Disable the message, report, category or checker with the given id(s). 24 | disable=R0401, R0901, R0903, R0904, R0911, R0916, W0402, W0403, W0410, 25 | W1501, W1502, W1505, E1300, E1301, E1302, E1304, W1300, W1301, W1302, W1304, 26 | E1124, E1125, E1129, E1132, W1402, W0105, E1303, W1306, W1307, C0123, 27 | E0116, E0114, E0112, E0115, E0106, E0113, E0111, E0105, E0100, E0117, W0622, 28 | W0150, W0120, W0124, W0108, W0123, W0122, W0110, C0122, C0200, W0141, 29 | W0640, W0623, W0614, W0604, W0603, W0602, W0601, E0604, E0603, E1200, 30 | E1201, E1202, W1201, E1205, E1206, similarities, newstyle, python3, 31 | W0512, C0403, C0401, C0402, E1701, E1700, W0332, C0327, C0328, E0202, 32 | E0241, E0704, W0211, W0232, W0511, R0204, C0303, W0231, W0611, C0330, 33 | C0123 34 | 35 | # Enable single-letter identifiers 36 | function-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 37 | variable-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 38 | attr-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 39 | argument-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 40 | method-rgx = (([a-z][a-z0-9_]{0,30})|(_[a-z0-9_]*))$ 41 | class-attribute-rgx = ([A-Za-z_][A-Za-z0-9_]{0,30}|(__.*__))$ -------------------------------------------------------------------------------- /Labs/Lab 2/speclab2.txt: -------------------------------------------------------------------------------- 1 | == GradeEntry == 2 | 3 | Context: a student record system at U of T 4 | 5 | A grade entry must keep track of three things: 6 | -- a course identifier, such as "CSC148". This is the course 7 | in which the grade was earned. 8 | -- a course weight: 1.0 credits for a half-course, 2.0 credits 9 | for a full course 10 | -- a course grade, which has no meaningful value unless we know 11 | whether letter grades or numeric grades are used 12 | A grade entry must also be able to generate how many points it is worth, based 13 | on its grade. The details of how points are generated are left 14 | out unless we know whether letter or numeric grades are used. 15 | 16 | Design and implement class GradeEntry 17 | 18 | == LetterGradeEntry == 19 | 20 | Context: a course grade entry with letter grades 21 | 22 | A letter grade entry is a grade entry for which the grade is a character. 23 | The value of the grade is one of {A, B, C, D, F}, with a possible suffix from {+, -}. A 24 | LetterGradeEntry generates points, based on its grade, according to the 25 | following table: 26 | 27 | value grade-point 28 | ------------------- 29 | A+ 4.0 30 | A 4.0 31 | A- 3.7 32 | B+ 3.3 33 | B 3.0 34 | B- 2.7 35 | C+ 2.3 36 | C 2.0 37 | C- 1.7 38 | D+ 1.3 39 | D 1.0 40 | D- 0.7 41 | F 0.0 42 | 43 | Design and implement class LetterGradeEntry 44 | 45 | == NumericGradeEntry == 46 | 47 | Context: a course grade with an integer value 48 | 49 | A numeric grade entry is a grade entry for which the grade is an integer between 0 50 | and 100 (inclusive). A numeric grade entry generates grade points based on its 51 | grade, according to the following table: 52 | 53 | value points 54 | -------------------- 55 | 90-100 4.0 56 | 85-89 4.0 57 | 80-84 3.7 58 | 77-79 3.3 59 | 73-76 3.0 60 | 70-72 2.7 61 | 67-69 2.3 62 | 63-66 2.0 63 | 60-62 1.7 64 | 57-59 1.3 65 | 53-56 1.0 66 | 50-52 0.7 67 | 0-49 0.0 68 | 69 | Design and implement class NumericGradeEntry. -------------------------------------------------------------------------------- /Labs/Lab 1/sample_solutions.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List 2 | 3 | 4 | class Registry: 5 | """A registry of runners in a 5K race. Each runner is identified by 6 | their email address and is registered in a speed category. 7 | 8 | === Attributes === 9 | groups - runners grouped by category 10 | """ 11 | groups: Dict[str, list] 12 | runners: Dict[str, str] 13 | 14 | # The names of the speed CATEGORIES for a race. 15 | CATEGORIES = ['<20', '<30', '<40', '>=40'] 16 | 17 | def __init__(self) -> None: 18 | """ Initialize a new race registry with no runners entered. 19 | """ 20 | self.groups = {} 21 | self.runners = {} 22 | for c in Registry.CATEGORIES: 23 | self.groups[c] = [] 24 | 25 | def __eq__(self, other: Any) -> bool: 26 | """ 27 | Return whether Registry self has same value as other. 28 | """ 29 | if type(self) != type(other): 30 | return False 31 | for c in Registry.CATEGORIES: 32 | if self.groups[c] != other.groups[c]: 33 | return False 34 | # note that runners contains the same information 35 | # as groups, so we don't have to explicitly compare. 36 | return True 37 | 38 | def register(self, email: str, category: str) -> None: 39 | """ Register runner with email andd category. 40 | """ 41 | # remove the runner from all categories they are 42 | # currently in. 43 | for c in Registry.CATEGORIES: 44 | if email in self.groups[c]: 45 | self.groups[c].remove(email) 46 | self.groups[category].append(email) 47 | self.groups[category].sort() 48 | self.runners[email] = category 49 | 50 | def get_runner_category(self, email: str) -> str: 51 | """ Return what speed category a given runner is in. 52 | """ 53 | return self.runners[email] 54 | 55 | def get_runners_in_category(self, category: str) -> List[str]: 56 | return self.groups[category] 57 | -------------------------------------------------------------------------------- /Labs/Lab 1/lab1.py: -------------------------------------------------------------------------------- 1 | # == Race Registry == 2 | # 3 | # Context: a system for organizing a 5K running race. 4 | # 5 | # When runners register, they provide their email address 6 | # and their speed category. A speed category indicates how quickly they 7 | # estimate that they can finish the race. This allows organizers to start 8 | # the runners in groups of roughly equivalent running speed so that 9 | # faster runners aren't stuck behind slower runners. The possible speed 10 | # categories are: under 20 minutes, under 30 minutes, under 40 minutes, 11 | # and 40 minutes or over. We need to be able get a list of runners' emails in 12 | # a given speed category. We also need to be able to look up a runner by email 13 | # to find their speed category. 14 | # 15 | # Design and implement a class for a race registry. 16 | 17 | from typing import Any 18 | 19 | 20 | class RaceRegistry: 21 | """ 22 | a system for organizing a 5K running race 23 | """ 24 | content: dict 25 | 26 | def __init__(self) -> None: 27 | self.content = {} 28 | 29 | def __eq__(self, other: Any) -> bool: 30 | return type(self) == type(other) and self.content == other.content 31 | 32 | def __str__(self) -> str: 33 | result = '' 34 | for key in self.content: 35 | result = result + key + ':' 36 | for member in self.content[key]: 37 | result = result + member + ' ' 38 | 39 | return result 40 | 41 | def add_member(self, name: str, speed: str) -> None: 42 | """ 43 | when a person registries for the race, we add him into the system 44 | """ 45 | if speed not in self.content: 46 | self.content[speed] = [] 47 | self.content[speed].append(name) 48 | else: 49 | self.content[speed].append(name) 50 | 51 | def search_members(self, speed: str) -> list: 52 | """ 53 | we want to get a list of runner's eamil address in a given speed 54 | category 55 | """ 56 | if speed in self.content: 57 | return self.content[speed] 58 | else: 59 | return [] 60 | -------------------------------------------------------------------------------- /Labs/Lab 2/lab2.py: -------------------------------------------------------------------------------- 1 | """ 2 | module GradeEntry 3 | """ 4 | 5 | 6 | from typing import Any 7 | 8 | 9 | class GradeEntry: 10 | """ 11 | a grade system for students 12 | 13 | course_identifier - which course 14 | course_weight - credit 15 | course_grade - grade for this course 16 | """ 17 | course_identifier: str 18 | course_weight: float 19 | course_grade: str 20 | 21 | def __init__(self, course_identifier: str, course_weight: float, 22 | course_grade: str) -> None: 23 | """ 24 | initialize a new gradeentry 25 | 26 | 27 | >>> a1 = GradeEntry('csc148', 0.5, '87') 28 | >>> a1.course_identifier 29 | 'csc148' 30 | >>> a1.course_grade 31 | '87' 32 | >>> a1.course_weight 33 | 0.5 34 | """ 35 | self.course_identifier = course_identifier 36 | self.course_grade = course_grade 37 | self.course_weight = course_weight 38 | 39 | def __str__(self) -> str: 40 | """ 41 | Return a str representation of GradeEntry 42 | 43 | >>> a2 = GradeEntry('mat137', 1.0, '76') 44 | >>> print(a2) 45 | mat137 76 1.0 46 | >>> a3 = GradeEntry('his450', 0.5, 'B+') 47 | >>> print(a3) 48 | his450 B+ 0.5 49 | """ 50 | return "{} {} {}".format(self.course_identifier, self.course_grade, 51 | self.course_weight) 52 | 53 | def __eq__(self, other: Any) -> bool: 54 | """ 55 | return whether other equals to self 56 | 57 | >>> a4 = GradeEntry('mat137', 1.0, '76') 58 | >>> a5 = GradeEntry('his450', 0.5, 'B+') 59 | >>> a6 = GradeEntry('mat137', 1.0, '76') 60 | >>> a4 == a5 61 | False 62 | >>> a4 == a6 63 | True 64 | """ 65 | return (type(self) == type(other) 66 | and self.course_weight == other.course_weight 67 | and self.course_grade == other.course_grade 68 | and self.course_identifier == other.course_identifier) 69 | 70 | def get_points(self) -> float: 71 | """ 72 | get points based on its course grade 73 | """ 74 | raise NotImplementedError('subclass needed') 75 | -------------------------------------------------------------------------------- /Midterms/Term Test 1/point.py: -------------------------------------------------------------------------------- 1 | """ 2 | point module 3 | """ 4 | from typing import Any 5 | 6 | 7 | class Point: 8 | """ Represent a two-dimensional point 9 | 10 | x - horizontal position 11 | y - vertical position 12 | """ 13 | x: float 14 | y: float 15 | 16 | def __init__(self, x: float, y: float) -> None: 17 | """ Initialize a new point 18 | """ 19 | self.x, self.y = float(x), float(y) 20 | 21 | def __eq__(self, other: Any) -> bool: 22 | """ Return whether self is equivalent to other. 23 | 24 | >>> Point(3, 5) == Point(3.0, 5.0) 25 | True 26 | >>> Point(3, 5) == Point(5, 3) 27 | False 28 | >>> Point(3, 5) == 7 29 | False 30 | """ 31 | return (type(self) == type(other) 32 | and self.x == other.x 33 | and self.y == other.y) 34 | 35 | def __str__(self) -> str: 36 | """ Return a string representation of self 37 | 38 | >>> print(Point(3, 5)) 39 | (3.0, 5.0) 40 | """ 41 | return "({}, {})".format(self.x, self.y) 42 | 43 | def __repr__(self) -> str: 44 | """ 45 | Return a string that would evaluate to a Point equivalent to self. 46 | 47 | >>> Point(3, 4).__repr__() 48 | 'Point(3.0, 4.0)' 49 | """ 50 | return "Point({}, {})".format(self.x, self.y) 51 | 52 | def distance_to(self, other: 'Point') -> float: 53 | """ 54 | Return distance from self to other. 55 | 56 | >>> Point(1, 2).distance_to(Point(4, 6)) 57 | 5.0 58 | """ 59 | return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5 60 | 61 | def distance_from_origin(self) -> float: 62 | """ Return the distance from the origin of this point 63 | 64 | >>> Point(3, 4).distance_from_origin() 65 | 5.0 66 | """ 67 | return self.distance_to(Point(0, 0)) 68 | 69 | def __add__(self, other: 'Point') -> 'Point': 70 | """ Produce sum of self + other. 71 | 72 | >>> Point(1, 2) + Point(3, 4) == Point(4, 6) 73 | True 74 | >>> Point(1, 2) + Point(0, 0) == Point(1, 2) 75 | True 76 | """ 77 | return Point(self.x + other.x, self.y + other.y) 78 | 79 | 80 | if __name__ == "__main__": 81 | from doctest import testmod 82 | testmod() 83 | -------------------------------------------------------------------------------- /Labs/Lab 2/NumericGradeEntry.py: -------------------------------------------------------------------------------- 1 | """ 2 | module numericgradeentry 3 | """ 4 | 5 | 6 | from lab2 import GradeEntry 7 | 8 | 9 | class NumericGradeEntry(GradeEntry): 10 | """ 11 | class numericgradeentry 12 | """ 13 | def __init__(self, course_identifier: str, course_weight: float, 14 | course_grade: str) -> None: 15 | """ 16 | initialize a new numericgradeentry 17 | 18 | >>> b1 = NumericGradeEntry('mat137', 1.0, '76') 19 | >>> b2 = NumericGradeEntry('csc148', 0.5, '87') 20 | >>> print(b1) 21 | mat137 76 1.0 22 | >>> b2.course_weight 23 | 0.5 24 | >>> b2.course_grade 25 | '87' 26 | >>> b2.course_identifier 27 | 'csc148' 28 | """ 29 | GradeEntry.__init__(self, course_identifier, course_weight, 30 | course_grade) 31 | 32 | def get_points(self) -> float: 33 | """ 34 | return the point based on its grade 35 | 36 | >>> b4 = NumericGradeEntry('mat137', 1.0, '76') 37 | >>> b5 = NumericGradeEntry('csc148', 0.5, '87') 38 | >>> b4.get_points() 39 | 3.0 40 | >>> b5.get_points() 41 | 4.0 42 | """ 43 | if int(self.course_grade) >= 90: 44 | return 4.0 45 | elif int(self.course_grade) >= 85: 46 | return 4.0 47 | elif int(self.course_grade) >= 80: 48 | return 3.7 49 | elif int(self.course_grade) >= 77: 50 | return 3.3 51 | elif int(self.course_grade) >= 73: 52 | return 3.0 53 | elif int(self.course_grade) >= 70: 54 | return 2.7 55 | elif int(self.course_grade) >= 67: 56 | return 2.3 57 | elif int(self.course_grade) >= 63: 58 | return 2.0 59 | elif int(self.course_grade) >= 60: 60 | return 1.7 61 | elif int(self.course_grade) >= 57: 62 | return 1.3 63 | elif int(self.course_grade) >= 53: 64 | return 1.0 65 | elif int(self.course_grade) >= 50: 66 | return 0.7 67 | elif int(self.course_grade) >= 0: 68 | return 0.0 69 | 70 | 71 | if __name__ == '__main__': 72 | import doctest 73 | doctest.testmod() 74 | a1 = NumericGradeEntry('mat137', 1.0, '76') 75 | a2 = NumericGradeEntry('csc148', 0.5, '87') 76 | print(a1) 77 | print(a2) 78 | print(a1.get_points()) 79 | print(a2.get_points()) 80 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/game_state.py: -------------------------------------------------------------------------------- 1 | """ 2 | The GameState superclass. 3 | 4 | NOTE: You do not have to run python-ta on this file. 5 | """ 6 | from typing import Any 7 | 8 | 9 | class GameState: 10 | """ 11 | The state of a game at a certain point in time. 12 | 13 | WIN - score if player is in a winning position 14 | LOSE - score if player is in a losing position 15 | DRAW - score if player is in a tied position 16 | p1_turn - whether it is p1's turn or not 17 | """ 18 | WIN: int = 1 19 | LOSE: int = -1 20 | DRAW: int = 0 21 | p1_turn: bool 22 | 23 | def __init__(self, is_p1_turn: bool) -> None: 24 | """ 25 | Initialize this game state and set the current player based on 26 | is_p1_turn. 27 | 28 | """ 29 | self.p1_turn = is_p1_turn 30 | 31 | def __str__(self) -> str: 32 | """ 33 | Return a string representation of the current state of the game. 34 | """ 35 | raise NotImplementedError 36 | 37 | def get_possible_moves(self) -> list: 38 | """ 39 | Return all possible moves that can be applied to this state. 40 | """ 41 | raise NotImplementedError 42 | 43 | def get_current_player_name(self) -> str: 44 | """ 45 | Return 'p1' if the current player is Player 1, and 'p2' if the current 46 | player is Player 2. 47 | """ 48 | if self.p1_turn: 49 | return 'p1' 50 | return 'p2' 51 | 52 | def make_move(self, move: Any) -> 'GameState': 53 | """ 54 | Return the GameState that results from applying move to this GameState. 55 | """ 56 | raise NotImplementedError 57 | 58 | def is_valid_move(self, move: Any) -> bool: 59 | """ 60 | Return whether move is a valid move for this GameState. 61 | """ 62 | return move in self.get_possible_moves() 63 | 64 | def __repr__(self) -> Any: 65 | """ 66 | Return a representation of this state (which can be used for 67 | equality testing). 68 | """ 69 | raise NotImplementedError 70 | 71 | def rough_outcome(self) -> float: 72 | """ 73 | Return an estimate in interval [LOSE, WIN] of best outcome the current 74 | player can guarantee from state self. 75 | """ 76 | raise NotImplementedError 77 | 78 | 79 | if __name__ == "__main__": 80 | from python_ta import check_all 81 | check_all(config="a2_pyta.txt") 82 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/state.py: -------------------------------------------------------------------------------- 1 | """ 2 | super class state 3 | """ 4 | from typing import Any 5 | from typing import List 6 | 7 | 8 | class State: 9 | """ 10 | class State 11 | """ 12 | is_p1_turn: bool 13 | is_game_over: bool 14 | 15 | def __init__(self, is_p1_turn: bool) -> None: 16 | """ 17 | initialzie a superclass state 18 | 19 | >>> state1 = State(True) 20 | >>> state2 = State(False) 21 | """ 22 | self.is_p1_turn = is_p1_turn 23 | self.is_game_over = False 24 | 25 | def __eq__(self, other: Any) -> bool: 26 | """ 27 | return whether self is equal to other 28 | 29 | >>> a1 = State(True) 30 | >>> a2 = State(False) 31 | >>> a1 == a2 32 | False 33 | >>> a3 = 3 34 | >>> a1 == a3 35 | False 36 | >>> a4 = State(True) 37 | >>> a1 == a4 38 | True 39 | """ 40 | return (type(self) == type(other) 41 | and self.is_p1_turn == other.is_p1_turn 42 | and self.is_game_over == other.is_game_over) 43 | 44 | def __str__(self) -> str: 45 | """ 46 | return a str representation of class State 47 | """ 48 | raise NotImplementedError("subclass needed") 49 | 50 | def get_possible_moves(self) -> List: 51 | """ 52 | get possible moves of the current game state 53 | """ 54 | raise NotImplementedError("subclass needed") 55 | 56 | def is_valid_move(self, move_to_take: Any) -> bool: 57 | """ 58 | whether a move is a valid move based on the rules of the game 59 | """ 60 | raise NotImplementedError("subclass needed") 61 | 62 | def get_current_player_name(self) -> str: 63 | """ 64 | get the current player name 65 | 66 | >>> is_p1_turn = True 67 | >>> state1 = State(is_p1_turn) 68 | >>> state1.get_current_player_name() 69 | 'p1' 70 | >>> is_p1_turn = False 71 | >>> state2 = State(is_p1_turn) 72 | >>> state2.get_current_player_name() 73 | 'p2' 74 | """ 75 | if self.is_p1_turn: 76 | return 'p1' 77 | return 'p2' 78 | 79 | def make_move(self, move_to_make: Any): 80 | """ 81 | make a move to play the game 82 | """ 83 | raise NotImplementedError("subclass needed") 84 | 85 | 86 | if __name__ == '__main__': 87 | import python_ta 88 | python_ta.check_all(config="a1_pyta.txt") 89 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/subtract_square_game.py: -------------------------------------------------------------------------------- 1 | """ 2 | An implementation of Subtract Square. 3 | 4 | NOTE: You do not have to run python-ta on this file. 5 | """ 6 | from game import Game 7 | from subtract_square_state import SubtractSquareState 8 | 9 | 10 | class SubtractSquareGame(Game): 11 | """ 12 | Abstract class for a game to be played with two players. 13 | """ 14 | 15 | def __init__(self, p1_starts): 16 | """ 17 | Initialize this Game, using p1_starts to find who the first player is. 18 | 19 | :param p1_starts: A boolean representing whether Player 1 is the first 20 | to make a move. 21 | :type p1_starts: bool 22 | """ 23 | count = int(input("Enter the number to subtract from: ")) 24 | self.current_state = SubtractSquareState(p1_starts, count) 25 | 26 | def get_instructions(self): 27 | """ 28 | Return the instructions for this Game. 29 | 30 | :return: The instructions for this Game. 31 | :rtype: str 32 | """ 33 | instructions = "Players take turns subtracting square numbers from" + \ 34 | " the starting number. The winner is the person who subtracts to 0." 35 | return instructions 36 | 37 | def is_over(self, state): 38 | """ 39 | Return whether or not this game is over. 40 | 41 | :return: True if the game is over, False otherwise. 42 | :rtype: bool 43 | """ 44 | return state.current_total == 0 45 | 46 | def is_winner(self, player): 47 | """ 48 | Return whether player has won the game. 49 | 50 | Precondition: player is 'p1' or 'p2'. 51 | 52 | :param player: The player to check. 53 | :type player: str 54 | :return: Whether player has won or not. 55 | :rtype: bool 56 | """ 57 | return (self.current_state.get_current_player_name() != player 58 | and self.is_over(self.current_state)) 59 | 60 | def str_to_move(self, string): 61 | """ 62 | Return the move that string represents. If string is not a move, 63 | return an invalid move. 64 | 65 | :param string: 66 | :type string: 67 | :return: 68 | :rtype: 69 | """ 70 | if not string.strip().isdigit(): 71 | return -1 72 | 73 | return int(string.strip()) 74 | 75 | 76 | if __name__ == "__main__": 77 | from python_ta import check_all 78 | check_all(config="a2_pyta.txt") 79 | -------------------------------------------------------------------------------- /Labs/Lab 2/LetterGradeEntry.py: -------------------------------------------------------------------------------- 1 | """ 2 | module Letter Grade Entry 3 | """ 4 | 5 | 6 | from lab2 import GradeEntry 7 | 8 | 9 | class LetterGradeEntry(GradeEntry): 10 | """ 11 | class letter grade entry 12 | """ 13 | def __init__(self, course_identifier: str, course_weight: float, 14 | course_grade: str) -> None: 15 | """ 16 | initialize a new LetterGradeEntry 17 | 18 | >>> c1 = LetterGradeEntry('his450', 0.5, 'B+') 19 | >>> c2 = LetterGradeEntry('lin101', 0.5, 'C') 20 | >>> c1.course_identifier 21 | 'his450' 22 | >>> c1.course_weight 23 | 0.5 24 | >>> c1.course_grade 25 | 'B+' 26 | >>> print(c2) 27 | lin101 C 0.5 28 | """ 29 | GradeEntry.__init__(self, course_identifier, course_weight, 30 | course_grade) 31 | 32 | def get_points(self) -> float: 33 | """ 34 | return the point of this course based on its letter grade 35 | 36 | >>> c3 = LetterGradeEntry('his450', 0.5, 'B+') 37 | >>> c4 = LetterGradeEntry('lin101', 0.5, 'C') 38 | >>> c3.get_points() 39 | 3.3 40 | >>> c4.get_points() 41 | 2.0 42 | """ 43 | if self.course_grade == 'A+': 44 | return 4.0 45 | elif self.course_grade == 'A': 46 | return 4.0 47 | elif self.course_grade == 'A-': 48 | return 3.7 49 | elif self.course_grade == 'B+': 50 | return 3.3 51 | elif self.course_grade == 'B': 52 | return 3.0 53 | elif self.course_grade == 'B-': 54 | return 2.7 55 | elif self.course_grade == 'C+': 56 | return 2.3 57 | elif self.course_grade == 'C': 58 | return 2.0 59 | elif self.course_grade == 'C-': 60 | return 1.7 61 | elif self.course_grade == 'D+': 62 | return 1.3 63 | elif self.course_grade == 'D': 64 | return 1.0 65 | elif self.course_grade == 'D-': 66 | return 0.7 67 | elif self.course_grade == 'F': 68 | return 0.0 69 | 70 | 71 | if __name__ == '__main__': 72 | import doctest 73 | doctest.testmod() 74 | a1 = LetterGradeEntry('lin101', 0.5, 'C') 75 | a2 = LetterGradeEntry('mat137', 1.0, 'B') 76 | a3 = LetterGradeEntry('his450', 0.5, 'B+') 77 | print(a1.get_points()) 78 | print(a2) 79 | print(a3.course_grade) 80 | print(a3.course_weight) 81 | print(a3.course_identifier) 82 | -------------------------------------------------------------------------------- /Labs/Lab 2/BookRoster.py: -------------------------------------------------------------------------------- 1 | """ 2 | Read the name of subclass BookRoster below, and then add a str 3 | method, including a docstring, to subclass BookRoster. You do not need 4 | examples in this docstring. Your str method should be used to display a list of 5 | all items. 6 | 7 | Assume BookRoster.add() takes a list in the form [book number, name, 8 | genre] where book number is an int. 9 | 10 | Context: an book-tracking system. 11 | A library tracks books that are registered in it, each one having a name. 12 | Books are identified by their book number, and they also have a name, such as 13 | 'CLRS', and a genre such as 'Educational'. We must be able to display a list of 14 | books where each line of the list has the following format: 15 | Book Number: , Name: , Genre: 16 | """ 17 | 18 | class Roster: 19 | """ 20 | Represents a roster of members. 21 | @param dict members: represents this roster’s members 22 | """ 23 | def __init__(self) -> None: 24 | """ 25 | Initialize new roster self. 26 | @param Roster self: this Roster 27 | @rtype: None 28 | """ 29 | self.members = {} 30 | 31 | def add(self, member: tuple) -> None: 32 | """ 33 | Add member to roster self. 34 | @param Roster self: this Roster 35 | @param tuple member: member record to add 36 | @rtype: None 37 | Assume: 38 | -- member is a tuple with member[0] not in self.members, 39 | -- len(member) > 1 40 | """ 41 | self.members[member[0]] = member[1:] 42 | 43 | def remove(self, member: tuple) -> None: 44 | """ 45 | Remove member from roster self. 46 | @param Roster self: this Roster 47 | @param tuple member: member record to be removed 48 | @rtype: None 49 | Assume: 50 | --member is a tuple with member[0] in self.members 51 | --len(member) > 1 52 | """ 53 | del(self.members[member[0]]) 54 | 55 | def __str__(self) -> str: 56 | """ 57 | Return a string representation of the members of roster self. 58 | @param Roster self: this Roster 59 | @rtype: str 60 | """ 61 | raise NotImplementedError 62 | 63 | class BookRoster(Roster): 64 | """ 65 | Represents a roster of books. 66 | """ 67 | 68 | def __str__(self) -> str: 69 | """ 70 | Return a string representation of the members of BookRoster self. 71 | 72 | @param BookRoster self: this BookRoster 73 | @rtype str 74 | """ 75 | ret_str = "" 76 | for number in self.members: 77 | (name, genre) = self.members[number] 78 | ret_str += ("Book Number: {}, Name: {}, " + 79 | "Genre: {}\n").format(str(number), name, genre) 80 | 81 | return ret_str[:-1] # Remove the last newline 82 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/subtract_square_state.py: -------------------------------------------------------------------------------- 1 | """ 2 | An implementation of a state for SubtractSquare. 3 | 4 | NOTE: You do not have to run python-ta on this file. 5 | """ 6 | from typing import Any 7 | from game_state import GameState 8 | 9 | 10 | class SubtractSquareState(GameState): 11 | """ 12 | The state of a game at a certain point in time. 13 | """ 14 | 15 | def __init__(self, is_p1_turn: bool, current_total: int) -> None: 16 | """ 17 | Initialize this game state and set the current player based on 18 | is_p1_turn. 19 | """ 20 | super().__init__(is_p1_turn) 21 | self.current_total = current_total 22 | 23 | def __str__(self) -> str: 24 | """ 25 | Return a string representation of the current state of the game. 26 | """ 27 | return "Current total: {}".format(self.current_total) 28 | 29 | def get_possible_moves(self) -> list: 30 | """ 31 | Return all possible moves that can be applied to this state. 32 | """ 33 | moves = [] 34 | for i in range(1, self.current_total + 1): 35 | if i ** 2 <= self.current_total: 36 | moves.append(i ** 2) 37 | 38 | return moves 39 | 40 | def make_move(self, move: Any) -> "SubtractSquareState": 41 | """ 42 | Return the GameState that results from applying move to this GameState. 43 | """ 44 | if type(move) == str: 45 | move = int(move) 46 | 47 | new_state = SubtractSquareState(not self.p1_turn, 48 | self.current_total - move) 49 | return new_state 50 | 51 | def __repr__(self) -> str: 52 | """ 53 | Return a representation of this state (which can be used for 54 | equality testing). 55 | """ 56 | return "P1's Turn: {} - Total: {}".format(self.p1_turn, 57 | self.current_total) 58 | 59 | def rough_outcome(self) -> float: 60 | """ 61 | Return an estimate in interval [LOSE, WIN] of best outcome the current 62 | player can guarantee from state self. 63 | """ 64 | if is_pos_square(self.current_total): 65 | return self.WIN 66 | elif all([is_pos_square(self.current_total - n ** 2) 67 | for n in range(1, self.current_total + 1) 68 | if n ** 2 < self.current_total]): 69 | return self.LOSE 70 | 71 | return self.DRAW 72 | 73 | 74 | def is_pos_square(n: int) -> bool: 75 | """ 76 | Return whether n is a positive perfect square 77 | 78 | >>> is_pos_square(5) 79 | False 80 | >>> is_pos_square(9) 81 | True 82 | """ 83 | return 0 < n and (round(n ** 0.5) ** 2 == n) 84 | 85 | 86 | if __name__ == "__main__": 87 | from python_ta import check_all 88 | check_all(config="a2_pyta.txt") 89 | -------------------------------------------------------------------------------- /Labs/Lab 3/teststack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test module Stack. 3 | """ 4 | import unittest 5 | from stack import Stack 6 | 7 | 8 | class EmptyTestCase(unittest.TestCase): 9 | """Test behaviour of an empty Stack. 10 | """ 11 | 12 | def setUp(self): 13 | """Set up an empty Stack. 14 | """ 15 | 16 | self.stack = Stack() 17 | 18 | def tearDown(self): 19 | """Clean up. 20 | """ 21 | 22 | self.stack = None 23 | 24 | def testIsEmpty(self): 25 | """Test is_empty() on empty Stack. 26 | """ 27 | self.assertTrue( 28 | self.stack.is_empty(), 29 | 'is_empty returned False on an empty Stack!') 30 | 31 | 32 | class SingletonTestCase(unittest.TestCase): 33 | 34 | """Check whether adding a single item makes it appear at the front. 35 | """ 36 | 37 | def setUp(self): 38 | """Set up a queue with a single element. 39 | """ 40 | 41 | self.stack = Stack() 42 | self.stack.add('a') 43 | 44 | def tearDown(self): 45 | """Clean up. 46 | """ 47 | 48 | self.stack = None 49 | 50 | def testIsEmpty(self): 51 | """Test is_empty() on non-empty Stack. 52 | """ 53 | 54 | self.assertFalse( 55 | self.stack.is_empty(), 56 | 'is_empty returned True on non-empty Stack!') 57 | 58 | def testRemove(self): 59 | """Test remove() on a non-empty Stack. 60 | """ 61 | 62 | front = self.stack.remove() 63 | self.assertEqual( 64 | front, 'a', 65 | 'The item at the front should have been "a" but was ' + 66 | front + '.') 67 | self.assertTrue( 68 | self.stack.is_empty(), 69 | 'Queue with one element not empty after remove().') 70 | 71 | 72 | class TypicalTestCase(unittest.TestCase): 73 | 74 | """A comprehensive tester of typical behaviour of Stack. 75 | """ 76 | 77 | def setUp(self): 78 | """Set up an empty stack. 79 | """ 80 | 81 | self.stack = Stack() 82 | 83 | def tearDown(self): 84 | """Clean up. 85 | """ 86 | 87 | self.stack = None 88 | 89 | def testAll(self): 90 | """Check adding and removing several items. 91 | """ 92 | 93 | for item in range(20): 94 | self.stack.add(item) 95 | self.assertFalse( 96 | self.stack.is_empty(), 97 | 'Stack should not be empty after adding item ' + 98 | str(item)) 99 | item = 19 100 | while not self.stack.is_empty(): 101 | front = self.stack.remove() 102 | self.assertEqual( 103 | front, item, 104 | 'Wrong item at the front of the Stack. Found ' + 105 | str(front) + ' but expected ' + str(item)) 106 | item -= 1 107 | 108 | 109 | if __name__ == '__main__': 110 | unittest.main(exit=False) 111 | -------------------------------------------------------------------------------- /Labs/Lab 3/testqueue.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test module Queue. 3 | """ 4 | import unittest 5 | from csc148_queue import Queue 6 | 7 | 8 | class EmptyTestCase(unittest.TestCase): 9 | """Test behaviour of an empty Queue. 10 | """ 11 | 12 | def setUp(self): 13 | """Set up an empty queue. 14 | """ 15 | 16 | self.queue = Queue() 17 | 18 | def tearDown(self): 19 | """Clean up. 20 | """ 21 | 22 | self.queue = None 23 | 24 | def testIsEmpty(self): 25 | """Test is_empty() on empty Queue. 26 | """ 27 | self.assertTrue( 28 | self.queue.is_empty(), 29 | 'is_empty returned False on an empty Queue!') 30 | 31 | 32 | class SingletonTestCase(unittest.TestCase): 33 | 34 | """Check whether adding a single item makes it appear at the front. 35 | """ 36 | 37 | def setUp(self): 38 | """Set up a queue with a single element. 39 | """ 40 | 41 | self.queue = Queue() 42 | self.queue.add('a') 43 | 44 | def tearDown(self): 45 | """Clean up. 46 | """ 47 | 48 | self.queue = None 49 | 50 | def testIsEmpty(self): 51 | """Test is_empty() on non-empty Queue. 52 | """ 53 | 54 | self.assertFalse( 55 | self.queue.is_empty(), 56 | 'is_empty returned True on non-empty Queue!') 57 | 58 | def testRemove(self): 59 | """Test remove() on a non-empty Queue. 60 | """ 61 | 62 | front = self.queue.remove() 63 | self.assertEqual( 64 | front, 'a', 65 | 'The item at the front should have been "a" but was ' + 66 | front + '.') 67 | self.assertTrue( 68 | self.queue.is_empty(), 69 | 'Queue with one element not empty after remove().') 70 | 71 | 72 | class TypicalTestCase(unittest.TestCase): 73 | 74 | """A comprehensive tester of typical behaviour of Queue. 75 | """ 76 | 77 | def setUp(self): 78 | """Set up an empty queue. 79 | """ 80 | 81 | self.queue = Queue() 82 | 83 | def tearDown(self): 84 | """Clean up. 85 | """ 86 | 87 | self.queue = None 88 | 89 | def testAll(self): 90 | """Check adding and removing several items. 91 | """ 92 | 93 | for item in range(20): 94 | self.queue.add(item) 95 | self.assertFalse( 96 | self.queue.is_empty(), 97 | 'Queue should not be empty after adding item ' + 98 | str(item)) 99 | item = 0 100 | while not self.queue.is_empty(): 101 | front = self.queue.remove() 102 | self.assertEqual( 103 | front, item, 104 | 'Wrong item at the front of the Queue. Found ' + 105 | str(front) + ' but expected ' + str(item)) 106 | item += 1 107 | 108 | 109 | if __name__ == '__main__': 110 | unittest.main(exit=False) 111 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/subtract_square.py: -------------------------------------------------------------------------------- 1 | """ 2 | module game Subtract_Square 3 | """ 4 | from typing import Any 5 | from subtract_square_state import SubtractSquareState 6 | 7 | 8 | class SubtractSquare: 9 | """ 10 | class game SubtractSquare 11 | """ 12 | current_state: SubtractSquareState 13 | 14 | def __init__(self, is_p1_turn: bool) -> None: 15 | """ 16 | initialize a new subtractsquare game 17 | 18 | #A docstring example is not needed for any functions or methods that 19 | use input() or random. 20 | """ 21 | self.current_state = SubtractSquareState(is_p1_turn) 22 | 23 | def __eq__(self, other: Any) -> bool: 24 | """ 25 | return whether self is equivalent to other 26 | 27 | # A docstring example is not needed for any functions or methods that 28 | use input() or random. 29 | """ 30 | return (type(self) == type(other) 31 | and self.current_state.is_game_over == 32 | other.current_state.is_game_over 33 | and self.current_state.starting_number == 34 | other.current_state.starting_number 35 | and self.current_state.is_p1_turn == 36 | other.current_state.is_p1_turn) 37 | 38 | def __str__(self) -> str: 39 | """ 40 | return a str representation of self 41 | 42 | # A docstring example is not needed for any functions or methods that 43 | use input() or random. 44 | """ 45 | return "The current player is: {}, and the current value is: " \ 46 | "{}".format(self.current_state.get_current_player_name(), 47 | self.current_state.starting_number) 48 | 49 | def get_instructions(self) -> str: 50 | """ 51 | reutrn instruction of game for players 52 | 53 | # A docstring example is not needed for any functions or methods that 54 | use input() or random. 55 | """ 56 | instruction = 'Players take turns subtracting square numbers ' \ 57 | 'from the starting number. The winner is the person ' \ 58 | 'who subtracts to 0' 59 | return instruction 60 | 61 | def is_over(self, current_state: SubtractSquareState) -> bool: 62 | """ 63 | return whether this game is over 64 | 65 | # A docstring example is not needed for any functions or methods that 66 | use input() or random. 67 | """ 68 | return current_state.is_game_over 69 | 70 | def str_to_move(self, move: str) -> int: 71 | """ 72 | a method whcih converts a string into a move 73 | 74 | # A docstring example is not needed for any functions or methods that 75 | use input() or random. 76 | """ 77 | return int(move) 78 | 79 | def is_winner(self, player: str) -> bool: 80 | """ 81 | return which player is the winner 82 | 83 | # A docstring example is not needed for any functions or methods that 84 | use input() or random. 85 | """ 86 | if not self.current_state.is_game_over: 87 | return False 88 | else: 89 | if self.current_state.is_p1_turn: 90 | if player == 'p1': 91 | return True 92 | return False 93 | else: 94 | if player == 'p2': 95 | return True 96 | return False 97 | 98 | 99 | if __name__ == '__main__': 100 | import python_ta 101 | python_ta.check_all(config="a1_pyta.txt") 102 | -------------------------------------------------------------------------------- /Labs/Lab 8/test_sort.py: -------------------------------------------------------------------------------- 1 | """ 2 | run some timing tests on sort algorithms 3 | """ 4 | from sort import * 5 | import random 6 | import timeit 7 | import cProfile 8 | from typing import Callable, Any, List 9 | 10 | 11 | def is_sorted(list_: list) -> bool: 12 | """ 13 | Return True iff list_ is in non-decreasing order. 14 | 15 | >>> is_sorted([1, 3, 5]) 16 | True 17 | >>> is_sorted([3, 1, 5]) 18 | False 19 | """ 20 | for j in range(1, len(list_)): 21 | if list_[j - 1] > list_[j]: 22 | return False 23 | return True 24 | 25 | 26 | def time_sort(list_: list, sorted_list: list, which_sort: Callable[[list], Any]) -> None: 27 | """ 28 | Sort list_ using function which_sort, time it and print the results, 29 | and ensure that the elements are the same as list sorted_list, 30 | which is a sorted version of L obtained by 31 | using the built-in sort. 32 | 33 | """ 34 | sorter_name = which_sort.__name__ # the function's name as a string 35 | 36 | # Verify that the sorting algorithm works correctly! 37 | new_list = list_[:] 38 | which_sort(new_list) 39 | error_string = sorter_name + "did not sort" 40 | assert is_sorted(new_list) and new_list == sorted_list, error_string 41 | 42 | # The timeit module provides accurate timing of code in seconds, by 43 | # running the code a number of times and adding up the total time. 44 | t = timeit.timeit('{}({})'.format(sorter_name, list_), 45 | 'from sort import ' + sorter_name, 46 | number=4) / 4 47 | 48 | # Print information about the results so far, before all of the output 49 | # generated by the cProfile module. 50 | print("{} {} items in {:.6f}\n".format(sorter_name, len(list_), t)) 51 | 52 | 53 | def generate_data(n: int, sorted_: bool=False, reversed_: bool=False) -> List[int]: 54 | """ 55 | Return a list of n ints. If sorted_, the list should be nearly sorted: 56 | only a few elements are out of order. If sorted_ and reversed_, the list 57 | should be nearly sorted in reverse. The list should otherwise be 58 | shuffled (in random order). 59 | """ 60 | list_ = [2 * j for j in range(n)] 61 | if sorted_: 62 | j = random.randrange(5, 11) 63 | while j < n // 2: 64 | list_[j], list_[-j] = list_[-j], list_[j] 65 | j += random.randrange(5, 11) 66 | if reversed_: 67 | list_.reverse() 68 | else: 69 | random.shuffle(list_) 70 | return list_ 71 | 72 | 73 | def profile_comparisons(n: int): 74 | """ 75 | Run cProfile to identify bottlenecks in algorithms. 76 | 77 | @param int n: size of list to run algorithms on. 78 | @rtype: None 79 | """ 80 | for algo in [selection_sort, insertion_sort_1, bubblesort_1, 81 | mergesort_1, quicksort_1]: 82 | list_ = generate_data(n) 83 | name = algo.__name__ 84 | print("=== profiling {} ===".format(name)) 85 | cProfile.run("{}({})".format(algo.__name__, list_), sort='calls') 86 | 87 | 88 | if __name__ == "__main__": 89 | import doctest 90 | doctest.testmod() 91 | 92 | for algo_ in [selection_sort, insertion_sort_1, bubblesort_1, 93 | mergesort_1, quicksort_1]: 94 | for i in range(1, 7): 95 | L = generate_data(i * 100) 96 | time_sort(L, sorted(L), algo_) 97 | L = generate_data(i * 100) 98 | time = timeit.timeit('{}.sort()'.format(L), number=100) / 100 99 | print("built-in sort {} items in {:.6f}\n".format(len(L), time)) 100 | 101 | # uncomment this call to profile-comparisons, and edit the list of 102 | # algorithms to see call-by-call comparison 103 | profile_comparisons(1000) 104 | -------------------------------------------------------------------------------- /Midterms/Term Test 2/t2_collection_additional_practice_no_sol.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Union, List, Optional 2 | 3 | ## 一勾CS大课堂, CSC148 Winter 2018 额外编程练习题 4 | ## 请确保你把上课给的题都搞懂,再做这里的问题 5 | 6 | # General Tree (Tree) 7 | class Tree: 8 | value: Any 9 | children: List[Any] 10 | 11 | def __init__(self, value, children=None): 12 | self.value = value 13 | self.children = children.copy() if children else [] 14 | 15 | ## helper function to compare two Tree, do not modify 16 | def __eq__(self, other): 17 | if not isinstance(other, type(self)): 18 | return False 19 | return self.value == other.value and \ 20 | self.children == other.children 21 | 22 | 23 | ## 简单问题 24 | 25 | def sum_pos(self): 26 | """ Return the sum of all positive integers in this tree. 27 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 28 | >>> t.sum_pos() 29 | 65 30 | >>> t = Tree(17, [Tree(3)]) 31 | >>> t.sum_pos() 32 | 20 33 | """ 34 | if not self.children: 35 | if self.value > 0: 36 | return self.value 37 | else: 38 | return 0 39 | else: 40 | if self.value > 0: 41 | return self.value + sum([c.sum_pos() for c in self.children]) 42 | else: 43 | return sum([c.sum_pos() for c in self.children]) 44 | 45 | ## 跟Path有关的额外练习 46 | 47 | def longest_path2(self): 48 | """ Returns a integer indicating the longest path this tree has 49 | 50 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 51 | >>> t.longest_path2() 52 | 4 53 | >>> t = Tree(17, [Tree(3)]) 54 | >>> t.longest_path2() 55 | 2 56 | """ 57 | pass 58 | 59 | 60 | ## 跟Depth有关的额外练习 61 | 62 | def count_at_depth(self, depth): 63 | """ Returns number of values at given depth in tree 64 | 65 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 66 | >>> t.count_at_depth(0) 67 | 1 68 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 69 | >>> t.count_at_depth(1) 70 | 3 71 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 72 | >>> t.count_at_depth(2) 73 | 4 74 | """ 75 | if depth < 0: 76 | return 0 77 | if depth == 0: 78 | return 1 79 | else: 80 | return sum([c.count_at_depth(depth - 1) for c in self.children]) 81 | 82 | def sum_values_until_depth(self, depth): 83 | """ Returns the sum of all the values in this tree until given depth is reached 84 | if given depth 0 means only value of the root 85 | if given depth 1 means root plus all the values in depth 1 86 | etc 87 | 88 | >>> t = Tree(17, [Tree(-2, [Tree(5), Tree(6, [Tree(-8), Tree(13)])]), Tree(3, [Tree(-7), Tree(8, [Tree(9)])]), Tree(4)]) 89 | >>> t.sum_values_until_depth(0) 90 | 17 91 | >>> t.sum_values_until_depth(1) 92 | 22 93 | >>> t.sum_values_until_depth(2) 94 | 34 95 | >>> t.sum_values_until_depth(3) 96 | 48 97 | >>> t.sum_values_until_depth(4) 98 | 48 99 | """ 100 | if depth < 0: 101 | return 0 102 | if depth == 0: 103 | return self.value 104 | else: 105 | return self.value + sum([c.sum_values_until_depth(depth - 1) for c in self.children]) 106 | 107 | 108 | if __name__ == '__main__': 109 | import doctest 110 | doctest.testmod() 111 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/chopstick.py: -------------------------------------------------------------------------------- 1 | """ 2 | module game Chopstick 3 | """ 4 | from typing import Any 5 | from chopstick_state import ChopstickState 6 | 7 | 8 | class Chopstick: 9 | """ 10 | class Chopstick 11 | """ 12 | current_state: ChopstickState 13 | 14 | def __init__(self, is_p1_turn: bool) -> None: 15 | """ 16 | initialize a new Chopstick game 17 | 18 | >>> is_p1_turn = True 19 | >>> c1 = Chopstick(is_p1_turn) 20 | >>> c1.current_state.is_p1_turn 21 | True 22 | >>> c1.current_state.is_game_over 23 | False 24 | >>> c1.current_state.current_list 25 | [1, 1, 1, 1] 26 | """ 27 | self.current_state = ChopstickState(is_p1_turn) 28 | 29 | def __eq__(self, other: Any) -> bool: 30 | """ 31 | return whether self is equal to other 32 | 33 | >>> is_p1_turn = True 34 | >>> c1 = Chopstick(is_p1_turn) 35 | >>> c2 = 3 36 | >>> c1 == c2 37 | False 38 | >>> c3 = 'Any' 39 | >>> c1 == c3 40 | False 41 | >>> c4 = Chopstick(False) 42 | >>> c1 == c4 43 | False 44 | >>> c5 = Chopstick(True) 45 | >>> c5 == c1 46 | True 47 | >>> c5.current_state.current_list = [1 ,0 ,1, 1] 48 | >>> c5 == c1 49 | False 50 | """ 51 | return (type(self) == type(other) 52 | and self.current_state == other.current_state) 53 | 54 | def __str__(self) -> str: 55 | """ 56 | return a str representation of game Chopstick 57 | 58 | >>> is_p1_turn = True 59 | >>> c1 = Chopstick(is_p1_turn) 60 | >>> print(c1) 61 | Player 1: 1 - 1; Player 2: 1 - 1 62 | """ 63 | return self.current_state.__str__() 64 | 65 | def get_instructions(self) -> str: 66 | """ 67 | return the instruction for the game chopstick 68 | 69 | >>> INSTRUCTION = "Players take turns adding the values of one" 70 | >>> is_p1_turn = True 71 | >>> c1 = Chopstick(is_p1_turn) 72 | >>> c1.get_instructions()[:43] == INSTRUCTION 73 | True 74 | """ 75 | instruction = "Players take turns adding the values of one of their" \ 76 | "hands to one of their opponents(modulo 5). A hand" \ 77 | "with a total of 5(or 0; 5 modulo 5) is considered" \ 78 | "'dead'. The first player to have 2 dead hands is" \ 79 | "the loser." 80 | return instruction 81 | 82 | def is_over(self, current_state: ChopstickState) -> bool: 83 | """ 84 | return whether game is over based on current state 85 | 86 | >>> is_p1_turn = True 87 | >>> c1 = Chopstick(is_p1_turn) 88 | >>> c2 = ChopstickState(True) 89 | >>> c1.is_over(c2) 90 | False 91 | >>> c2.is_game_over = True 92 | >>> c1.is_over(c2) 93 | True 94 | """ 95 | return current_state.is_game_over 96 | 97 | def str_to_move(self, move_to_take: str) -> str: 98 | """ 99 | converts a move_to_take into a move 100 | 101 | >>> is_p1_turn = True 102 | >>> c1 = Chopstick(is_p1_turn) 103 | >>> c1.str_to_move('ll') 104 | 'll' 105 | >>> c1.str_to_move('lr') 106 | 'lr' 107 | """ 108 | return move_to_take 109 | 110 | def is_winner(self, player: str) -> bool: 111 | """ 112 | return whether player is winner 113 | 114 | >>> is_p1_turn = True 115 | >>> c1 = Chopstick(is_p1_turn) 116 | >>> c1.is_winner('p1') 117 | False 118 | >>> c1.current_state.is_game_over = True 119 | >>> c1.is_winner('p1') 120 | True 121 | >>> c1.current_state.is_p1_turn = False 122 | >>> c1.is_winner('p1') 123 | False 124 | """ 125 | if not self.current_state.is_game_over: 126 | return False 127 | else: 128 | if self.current_state.is_p1_turn: 129 | if player == 'p1': 130 | return True 131 | return False 132 | else: 133 | if player == 'p2': 134 | return True 135 | return False 136 | 137 | 138 | if __name__ == '__main__': 139 | import python_ta 140 | python_ta.check_all(config="a1_pyta.txt") 141 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/game_interface.py: -------------------------------------------------------------------------------- 1 | 2 | from strategy import interactive_strategy, random_strategy 3 | from typing import Any, Callable 4 | from chopstick import Chopstick 5 | from subtract_square import SubtractSquare 6 | 7 | 8 | # 's' should map to your implementation of Subtract Square, and 'c' should map 9 | # to Chopsticks. 10 | playable_games = {'s': SubtractSquare, 11 | 'c': Chopstick} 12 | 13 | # The strategies you are to implement. See strategy.py, and then decide 14 | # how to modify this. 15 | usable_strategies = {'r': random_strategy, 16 | 'i': interactive_strategy} 17 | 18 | 19 | class GameInterface: 20 | """ 21 | A game interface for a two-player, sequential move, zero-sum, 22 | perfect-information game. 23 | 24 | game - the game to be played 25 | p1_strategy - strategy for player 1 26 | p2_strategy - strategy for player 2 27 | """ 28 | game: Any 29 | p1_strategy: Callable[[Any], Any] 30 | p2_strategy: Callable[[Any], Any] 31 | 32 | def __init__(self, game: Any, p1_strategy: Callable, 33 | p2_strategy: Callable[[Any], Any]) -> None: 34 | """ 35 | Initialize this GameInterface, setting its active game to game, and 36 | using the strategies p1_strategy for Player 1 and p2_strategy for 37 | Player 2. 38 | """ 39 | first_player = input("Type y if player 1 is to make the first move: ") 40 | is_p1_turn = False 41 | if first_player.lower() == 'y': 42 | is_p1_turn = True 43 | 44 | self.game = game(is_p1_turn) 45 | self.p1_strategy = p1_strategy 46 | self.p2_strategy = p2_strategy 47 | 48 | def play(self) -> None: 49 | """ 50 | Play the game. 51 | """ 52 | current_state = self.game.current_state 53 | 54 | print(self.game.get_instructions()) 55 | print(current_state) 56 | 57 | # Pick moves until the game is over 58 | while not self.game.is_over(current_state): 59 | move_to_make = None 60 | 61 | # Print out all of the valid moves 62 | possible_moves = current_state.get_possible_moves() 63 | print("The current available moves are:") 64 | for move in possible_moves: 65 | print(move) 66 | 67 | # Pick a (legal) move. 68 | while not current_state.is_valid_move(move_to_make): 69 | current_strategy = self.p2_strategy 70 | if current_state.get_current_player_name() == 'p1': 71 | current_strategy = self.p1_strategy 72 | move_to_make = current_strategy(self.game) 73 | 74 | # Apply the move 75 | current_player_name = current_state.get_current_player_name() 76 | new_game_state = current_state.make_move(move_to_make) 77 | self.game.current_state = new_game_state 78 | current_state = self.game.current_state 79 | 80 | print("{} made the move {}. The game's state is now:".format( 81 | current_player_name, move_to_make)) 82 | print(current_state) 83 | 84 | # Print out the winner of the game 85 | if self.game.is_winner("p1"): 86 | print("Player 1 is the winner!") 87 | elif self.game.is_winner("p2"): 88 | print("Player 2 is the winner!") 89 | else: 90 | print("It's a tie!") 91 | 92 | 93 | if __name__ == '__main__': 94 | games = ", ".join(["'{}': {}".format(key, playable_games[key].__name__) if 95 | playable_games[key] is not None else 96 | "'{}': None".format(key) for key in playable_games]) 97 | 98 | strategies = ", ".join(["'{}': {}".format(key, 99 | usable_strategies[key].__name__) 100 | if usable_strategies[key] is not None else 101 | "'{}': None".format(key) 102 | for key in usable_strategies]) 103 | 104 | chosen_game = '' 105 | while chosen_game not in playable_games.keys(): 106 | chosen_game = input( 107 | "Select the game you want to play ({}): ".format(games)) 108 | 109 | p1 = '' 110 | p2 = '' 111 | 112 | while p1 not in usable_strategies.keys(): 113 | p1 = input("Select the strategy for Player 1 ({}): ".format(strategies)) 114 | 115 | while p2 not in usable_strategies.keys(): 116 | p2 = input("Select the strategy for Player 2 ({}): ".format(strategies)) 117 | 118 | GameInterface(playable_games[chosen_game], usable_strategies[p1], 119 | usable_strategies[p2]).play() 120 | -------------------------------------------------------------------------------- /Labs/Lab 5/ex5.py: -------------------------------------------------------------------------------- 1 | """ recursion exercises with nested lists 2 | """ 3 | from typing import List, Union 4 | 5 | 6 | def gather_lists(list_: List[List[object]]) -> List[object]: 7 | """ 8 | Return the concatenation of the sublists of list_. 9 | 10 | >>> list_ = [[1, 2], [3, 4]] 11 | >>> gather_lists(list_) 12 | [1, 2, 3, 4] 13 | """ 14 | # special form of sum for "adding" lists 15 | return sum(list_, []) 16 | 17 | 18 | def list_all(obj: Union[list, object]) -> list: 19 | """ 20 | Return a list of all non-list elements in obj or obj's sublists, if obj 21 | is a list. Otherwise, return a list containing obj. 22 | 23 | >>> obj = 17 24 | >>> list_all(obj) 25 | [17] 26 | >>> obj = [1, 2, 3, 4] 27 | >>> list_all(obj) 28 | [1, 2, 3, 4] 29 | >>> obj = [[1, 2, [3, 4], 5], 6] 30 | >>> all([x in list_all(obj) for x in [1, 2, 3, 4, 5, 6]]) 31 | True 32 | >>> all ([x in [1, 2, 3, 4, 5, 6] for x in list_all(obj)]) 33 | True 34 | """ 35 | if not isinstance(obj, list): 36 | return [obj] 37 | else: 38 | return sum([list_all(x) for x in obj], []) 39 | 40 | 41 | def max_length(obj: Union[list, object]) -> int: 42 | """ 43 | Return the maximum length of obj or any of its sublists, if obj is a list. 44 | otherwise return 0. 45 | 46 | >>> max_length(17) 47 | 0 48 | >>> max_length([1, 2, 3, 17]) 49 | 4 50 | >>> max_length([[1, 2, 3, 3], 4, [4, 5]]) 51 | 4 52 | """ 53 | if isinstance(obj, int): 54 | return 0 55 | elif not any([isinstance(x, list) for x in obj]): 56 | return len(obj) 57 | else: 58 | a = max([max(max_length(x), len(x)) 59 | if isinstance(x, list) else 0 for x in obj]) 60 | return max(a, len(obj)) 61 | 62 | 63 | def list_over(obj: Union[list, str], n: int) -> List[str]: 64 | """ 65 | Return a list of strings of length greater than n in obj, 66 | or sublists of obj, if obj is a list. 67 | If obj is a string of length greater than n, return a list 68 | containing obj. Otherwise return an empty list. 69 | 70 | >>> list_over("five", 3) 71 | ['five'] 72 | >>> list_over("five", 4) 73 | [] 74 | >>> list_over(["one", "two", "three", "four"], 3) 75 | ['three', 'four'] 76 | """ 77 | if isinstance(obj, str): 78 | if len(obj) > n: 79 | return [obj] 80 | else: 81 | return [] 82 | else: 83 | return sum([list_over(x, n) for x in obj], []) 84 | 85 | 86 | def list_even(obj: Union[list, int]) -> List[int]: 87 | """ 88 | Return a list of all even integers in obj, 89 | or sublists of obj, if obj is a list. If obj is an even 90 | integer, return a list containing obj. Otherwise return 91 | en empty list. 92 | 93 | >>> list_even(3) 94 | [] 95 | >>> list_even(16) 96 | [16] 97 | >>> list_even([1, 2, 3, 4, 5]) 98 | [2, 4] 99 | >>> list_even([1, 2, [3, 4], 5]) 100 | [2, 4] 101 | >>> list_even([1, [2, [3, 4]], 5]) 102 | [2, 4] 103 | """ 104 | if isinstance(obj, int): 105 | if obj % 2 == 0: 106 | return [obj] 107 | else: 108 | return [] 109 | else: 110 | return sum([list_even(x) for x in obj], []) 111 | 112 | 113 | def count_even(obj: Union[list, int]) -> int: 114 | """ 115 | Return the number of even numbers in obj or sublists of obj 116 | if obj is a list. Otherwise, if obj is a number, return 1 117 | if it is an even number and 0 if it is an odd number. 118 | 119 | >>> count_even(3) 120 | 0 121 | >>> count_even(16) 122 | 1 123 | >>> count_even([1, 2, [3, 4], 5]) 124 | 2 125 | """ 126 | if isinstance(obj, int): 127 | if obj % 2 == 1: 128 | return 0 129 | else: 130 | return 1 131 | else: 132 | return sum([count_even(x) for x in obj]) 133 | 134 | 135 | def count_all(obj: Union[list, object]) -> int: 136 | """ 137 | Return the number of elements in obj or sublists of obj if obj is a list. 138 | Otherwise, if obj is a non-list return 1. 139 | 140 | >>> count_all(17) 141 | 1 142 | >>> count_all([17, 17, 5]) 143 | 3 144 | >>> count_all([17, [17, 5], 3]) 145 | 4 146 | """ 147 | if not isinstance(obj, list): 148 | return 1 149 | else: 150 | return sum([count_all(x) for x in obj]) 151 | 152 | 153 | def count_above(obj: Union[list, int], n: int) -> int: 154 | """ 155 | Return tally of numbers in obj, and sublists of obj, that are over n, if 156 | obj is a list. Otherwise, if obj is a number over n, return 1. Otherwise 157 | return 0. 158 | 159 | >>> count_above(17, 19) 160 | 0 161 | >>> count_above(19, 17) 162 | 1 163 | >>> count_above([17, 18, 19, 20], 18) 164 | 2 165 | >>> count_above([17, 18, [19, 20]], 18) 166 | 2 167 | """ 168 | if isinstance(obj, int): 169 | if obj > n: 170 | return 1 171 | else: 172 | return 0 173 | else: 174 | return sum([count_above(x, n) for x in obj]) 175 | -------------------------------------------------------------------------------- /Labs/Lab 7/test_count_leaves_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from extra_practice import count_leaves 4 | from hypothesis import given 5 | from hypothesis.strategies import recursive 6 | from hypothesis.strategies import booleans 7 | from hypothesis.strategies import tuples 8 | from hypothesis.strategies import none 9 | 10 | class BTNode: 11 | """ 12 | A Binary Tree, i.e. arity 2. 13 | === Attributes === 14 | @param object data: data in this node of tree 15 | @param BTNode|None left: left child 16 | @param BTNode|None right: right child 17 | @rtype: None 18 | """ 19 | 20 | 21 | def __init__(self, data, left=None, right=None): 22 | """ 23 | Create BTNode self with data and children left and right. 24 | @param BTNode self: this binary tree 25 | @param object data: data of this node 26 | @param BTNode|None left: left child 27 | @param BTNode|None right: right child 28 | @rtype: None 29 | """ 30 | self.data, self.left, self.right = data, left, right 31 | 32 | def tuples_to_tree(t): 33 | """ 34 | Return a BTNode generated from t and the number of leaves. 35 | 36 | Precondition: t is in the form (data, left child, right child) where 37 | left child and right child are either None, a data, or 38 | another tuple. 39 | 40 | @param tuple(bool, tuple|None|bool, tuple|None|bool) t: The tuple to turn 41 | into a BTNode 42 | @rtype: (BTNode, int) 43 | """ 44 | if t is None: 45 | return (None, 0) 46 | 47 | if type(t) == bool: 48 | return (BTNode(t), 1) 49 | 50 | (left, l_count) = tuples_to_tree(t[1]) 51 | (right, r_count) = tuples_to_tree(t[2]) 52 | num_leaves = l_count + r_count 53 | 54 | if num_leaves == 0: 55 | num_leaves = 1 56 | 57 | return (BTNode(t[0], left, right), num_leaves) 58 | 59 | class CountLeavesTests(unittest.TestCase): 60 | def test_returns_int(self): 61 | """ 62 | Test count_leaves to make sure it returns an int. 63 | """ 64 | return_type = type(count_leaves(BTNode(1))) 65 | 66 | self.assertEqual(return_type, int, "count_leaves should return type " + 67 | "int, but instead returned type {}.".format( 68 | return_type)) 69 | 70 | def test_none(self): 71 | """ 72 | Test count_leaves on None. 73 | """ 74 | self.assertEqual(count_leaves(None), 0, "count_leaves on None should " + 75 | "return 0.") 76 | 77 | def test_leaf(self): 78 | """ 79 | Test count_leaves on a leaf. 80 | """ 81 | self.assertEqual(count_leaves(BTNode(1)), 1, "count_leaves should" + 82 | " return 1 when used on a leaf.") 83 | 84 | def test_one_left_child(self): 85 | """ 86 | Test count_leaves on a BTNode with one left child. 87 | """ 88 | t = BTNode(1, BTNode(2)) 89 | self.assertNotEqual(count_leaves(t), 2, "count_leaves should not " + 90 | "count None or any BTNodes with children as" + 91 | " leaf nodes.") 92 | self.assertEqual(count_leaves(t), 1, "count_leaves should return 1 " + 93 | "when used on a BTNode with only one child, " + 94 | "where the child is a leaf.") 95 | 96 | def test_one_right_child(self): 97 | """ 98 | Test count_leaves on a BTNode with one right child 99 | """ 100 | t = BTNode(1, None, BTNode(2)) 101 | self.assertNotEqual(count_leaves(t), 2, "count_leaves should not " + 102 | "count None or any BTNodes with children as" + 103 | " leaf nodes.") 104 | self.assertEqual(count_leaves(t), 1, "count_leaves should return 1 " + 105 | "when used on a BTNode with only one child, " + 106 | "where the child is a leaf.") 107 | 108 | def test_two_leaf_children(self): 109 | """ 110 | Test count_leaves on a BTNode with two leaf children. 111 | """ 112 | t = BTNode(1, BTNode(2), BTNode(3)) 113 | self.assertEqual(count_leaves(t), 2, "count_leaves should count all " + 114 | "of the leaves in the entire BTNode.") 115 | 116 | @given(recursive(none() | booleans(), lambda children: tuples(booleans(), 117 | children, 118 | children))) 119 | def test_count_leaves(self, tuple_tree): 120 | """ 121 | Test count_leaves on a randomly generated BTNode. 122 | """ 123 | (t, expected) = tuples_to_tree(tuple_tree) 124 | actual = count_leaves(t) 125 | self.assertEqual(actual, expected, 126 | ("test_count_leaves on BTNode\n{}\nReturned {}" + 127 | " instead of {}.").format(tuple_tree, actual, 128 | expected)) 129 | 130 | if __name__ == '__main__': 131 | unittest.main() 132 | -------------------------------------------------------------------------------- /Labs/Lab 5/recursion_exercise.py: -------------------------------------------------------------------------------- 1 | """ recursion exercises with nested lists 2 | """ 3 | from typing import List, Union 4 | 5 | 6 | def gather_lists(list_: List[List[object]]) -> List[object]: 7 | """ 8 | Return the concatenation of the sublists of list_. 9 | 10 | >>> list_ = [[1, 2], [3, 4]] 11 | >>> gather_lists(list_) 12 | [1, 2, 3, 4] 13 | """ 14 | # special form of sum for "adding" lists 15 | return sum(list_, []) 16 | 17 | 18 | def list_all(obj: Union[list, object]) -> list: 19 | """ 20 | Return a list of all non-list elements in obj or obj's sublists, if obj 21 | is a list. Otherwise, return a list containing obj. 22 | 23 | >>> obj = 17 24 | >>> list_all(obj) 25 | [17] 26 | >>> obj = [1, 2, 3, 4] 27 | >>> list_all(obj) 28 | [1, 2, 3, 4] 29 | >>> obj = [[1, 2, [3, 4], 5], 6] 30 | >>> all([x in list_all(obj) for x in [1, 2, 3, 4, 5, 6]]) 31 | True 32 | >>> all ([x in [1, 2, 3, 4, 5, 6] for x in list_all(obj)]) 33 | True 34 | """ 35 | if isinstance(obj, list): 36 | return gather_lists([list_all(x) for x in obj]) 37 | else: 38 | return [obj] 39 | 40 | 41 | def max_length(obj: Union[list, object]) -> int: 42 | """ 43 | Return the maximum length of obj or any of its sublists, if obj is a list. 44 | otherwise return 0. 45 | 46 | >>> max_length(17) 47 | 0 48 | >>> max_length([1, 2, 3, 17]) 49 | 4 50 | >>> max_length([[1, 2, 3, 3], 4, [4, 5]]) 51 | 4 52 | >>> max_length([[1, 2, [3, 4]], 4, [5, 6]]) 53 | 3 54 | >>> max_length([[1, 2, [1, 2, 3, 4, 5]], 4, 5, [5, 6]]) 55 | 5 56 | """ 57 | if isinstance(obj, int): 58 | return 0 59 | elif not any([isinstance(x, list) for x in obj]): 60 | return len(obj) 61 | else: 62 | a = max([max(max_length(x), len(x)) if isinstance(x, list) 63 | else 0 for x in obj]) 64 | return max(a, len(obj)) 65 | 66 | 67 | def list_over(obj: Union[list, str], n: int) -> List[str]: 68 | """ 69 | Return a list of strings of length greater than n in obj, 70 | or sublists of obj, if obj is a list. 71 | If obj is a string of length greater than n, return a list 72 | containing obj. Otherwise return an empty list. 73 | 74 | >>> list_over("five", 3) 75 | ['five'] 76 | >>> list_over("five", 4) 77 | [] 78 | >>> list_over(["one", "two", "three", "four"], 3) 79 | ['three', 'four'] 80 | """ 81 | if isinstance(obj, str): 82 | if len(obj) > n: 83 | return [obj] 84 | else: 85 | return [] 86 | else: 87 | return sum([list_over(x, n) for x in obj], []) 88 | 89 | 90 | def list_even(obj: Union[list, int]) -> List[int]: 91 | """ 92 | Return a list of all even integers in obj, 93 | or sublists of obj, if obj is a list. If obj is an even 94 | integer, return a list containing obj. Otherwise return 95 | en empty list. 96 | 97 | >>> list_even(3) 98 | [] 99 | >>> list_even(16) 100 | [16] 101 | >>> list_even([1, 2, 3, 4, 5]) 102 | [2, 4] 103 | >>> list_even([1, 2, [3, 4], 5]) 104 | [2, 4] 105 | >>> list_even([1, [2, [3, 4]], 5]) 106 | [2, 4] 107 | """ 108 | if isinstance(obj, int): 109 | if obj % 2 == 0: 110 | return [obj] 111 | else: 112 | return [] 113 | else: 114 | return sum([list_even(x) for x in obj], []) 115 | 116 | 117 | def count_even(obj: Union[list, int]) -> int: 118 | """ 119 | Return the number of even numbers in obj or sublists of obj 120 | if obj is a list. Otherwise, if obj is a number, return 1 121 | if it is an even number and 0 if it is an odd number. 122 | 123 | >>> count_even(3) 124 | 0 125 | >>> count_even(16) 126 | 1 127 | >>> count_even([1, 2, [3, 4], 5]) 128 | 2 129 | """ 130 | if isinstance(obj, int): 131 | if obj % 2 == 0: 132 | return 1 133 | else: 134 | return 0 135 | else: 136 | return sum([count_even(x) for x in obj]) 137 | 138 | 139 | def count_all(obj: Union[list, object]) -> int: 140 | """ 141 | Return the number of elements in obj or sublists of obj if obj is a list. 142 | Otherwise, if obj is a non-list return 1. 143 | 144 | >>> count_all(17) 145 | 1 146 | >>> count_all([17, 17, 5]) 147 | 3 148 | >>> count_all([17, [17, 5], 3]) 149 | 4 150 | """ 151 | if not isinstance(obj, list): 152 | return 1 153 | else: 154 | return sum([count_all(x) for x in obj]) 155 | 156 | 157 | def count_above(obj: Union[list, int], n: int) -> int: 158 | """ 159 | Return tally of numbers in obj, and sublists of obj, that are over n, if 160 | obj is a list. Otherwise, if obj is a number over n, return 1. Otherwise 161 | return 0. 162 | 163 | >>> count_above(17, 19) 164 | 0 165 | >>> count_above(19, 17) 166 | 1 167 | >>> count_above([17, 18, 19, 20], 18) 168 | 2 169 | >>> count_above([17, 18, [19, 20]], 18) 170 | 2 171 | >>> count_above([2, 3, [1, 3, 5, [3, 5, [5 ,7]]], 6], 2) 172 | 8 173 | """ 174 | if isinstance(obj, list): 175 | return sum([count_above(x, n) for x in obj]) 176 | else: 177 | if obj > n: 178 | return 1 179 | else: 180 | return 0 181 | -------------------------------------------------------------------------------- /Labs/Lab 6/test_count_leaves_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from hypothesis import given 4 | from hypothesis import note 5 | from hypothesis.strategies import integers 6 | from hypothesis.strategies import lists 7 | from hypothesis.strategies import recursive 8 | from ex6 import count_leaves 9 | 10 | 11 | def make_children_list(children): 12 | """ 13 | Return a list of child Trees generated by children. 14 | 15 | @param list[object]|object children: The children values and trees 16 | @rtype: (list[Tree], int) 17 | """ 18 | num_leaves = 0 19 | if type(children) != list: 20 | return ([Tree(children)], 1) 21 | 22 | ret_children = [] 23 | for child in children: 24 | rec_call = make_children_list(child) 25 | 26 | if type(child) == list: 27 | ret_children.append(Tree(random.randint(0, 100), rec_call[0])) 28 | if not rec_call[0]: 29 | num_leaves += 1 30 | else: 31 | ret_children += rec_call[0] 32 | 33 | num_leaves += rec_call[1] 34 | 35 | # Pick a random value for the Tree's value 36 | return (ret_children, num_leaves) 37 | 38 | class Tree: 39 | """ 40 | A bare-bones Tree ADT that identifies the root with the entire tree. 41 | """ 42 | def __init__(self, value=None, children=None): 43 | """ 44 | Create Tree self with content value and 0 or more children 45 | 46 | @param Tree self: this tree 47 | @param object value: value contained in this tree 48 | @param list[object|None] children: possibly-empty list of children 49 | @rtype: None 50 | """ 51 | self.value = value 52 | # copy children if not None 53 | self.children = children.copy() if children else [] 54 | 55 | def __repr__(self): 56 | """ 57 | Return representation of Tree (self) as string that 58 | can be evaluated into an equivalent Tree. 59 | 60 | @param Tree self: this tree 61 | @rtype: str 62 | 63 | >>> t1 = Tree(5) 64 | >>> t1 65 | Tree(5) 66 | >>> t2 = Tree(7, [t1]) 67 | >>> t2 68 | Tree(7, [Tree(5)]) 69 | """ 70 | # Our __repr__ is recursive, because it can also be called 71 | # via repr...! 72 | return ('Tree({}, {})'.format(repr(self.value), repr(self.children)) 73 | if self.children 74 | else 'Tree({})'.format(repr(self.value))) 75 | 76 | class CountInternalTests(unittest.TestCase): 77 | def test_returns_int(self): 78 | """ 79 | Test count_leaves to make sure it returns an int. 80 | """ 81 | return_type = type(count_leaves(Tree(0, [Tree(1, [Tree(2)])]))) 82 | self.assertEqual(return_type, int, "count_leaves should return type" + 83 | "int, but instead returned type {}.".format(return_type 84 | )) 85 | 86 | def test_leaf_node(self): 87 | """ 88 | Test count_leaves on a leaf node. 89 | """ 90 | self.assertEqual(count_leaves(Tree(0)), 1, "Leaf nodes should " + 91 | "have 1 leaf node.") 92 | 93 | def test_one_leaf_child(self): 94 | """ 95 | Test count_leaves on a tree containing only a root and its leaf child. 96 | """ 97 | t = Tree(0, [Tree(1)]) 98 | 99 | self.assertEqual(count_leaves(t), 1, "Only leaf nodes should be " + 100 | "included in the count and not nodes with children.") 101 | 102 | def test_multiple_leaf_children(self): 103 | """ 104 | Test count_leaves on a tree containing only a root and its children 105 | which are all leaves. 106 | """ 107 | t = Tree(0, [Tree(1), Tree(2)]) 108 | 109 | self.assertEqual(count_leaves(t), 2, "Leaf nodes should be " + 110 | "included in the count, while root nodes (with " + 111 | "children) should not.") 112 | 113 | def test_multiple_non_leaf_children(self): 114 | """ 115 | Test count_leaves on a tree containing only a root and its children 116 | which are all subtrees with children. 117 | """ 118 | t = Tree(0, [Tree(1, [Tree(3), Tree(5)]), Tree(2, [Tree(4), Tree(6)])]) 119 | 120 | self.assertEqual(count_leaves(t), 4, "All nodes with no children " + 121 | "should be counted as leaf nodes.") 122 | 123 | @given(integers(min_value = -99, max_value = 99), 124 | recursive(integers(min_value = -99, max_value = 99), lists, 125 | max_leaves = 20)) 126 | def test_count_internal(self, value, children): 127 | """ 128 | Test the correctness of count_leaves against the solution. 129 | """ 130 | (children_list, num_leaves) = make_children_list(children) 131 | t = Tree(value, children_list) 132 | 133 | if not children_list: 134 | num_leaves += 1 135 | 136 | actual = count_leaves(t) 137 | self.assertEqual(actual, num_leaves, 138 | ("count_leaves on the Tree\n{}\nReturned {}" + 139 | " instead of {}.").format(t.__repr__(), actual, 140 | num_leaves)) 141 | 142 | if __name__ == "__main__": 143 | unittest.main() 144 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/game_interface.py: -------------------------------------------------------------------------------- 1 | """ 2 | The module used to play our games. 3 | Please fill in the TODO's (i.e. importing games and strategies as needed) 4 | 5 | Note: You do not have to run python_ta on this file. 6 | You may import your games from A1 (i.e. Chopsticks). However, the minimax 7 | strategy cannot be used on Chopsticks unless you account for infinite loops. 8 | (You do not have to worry about this for the assignment: only do it for 9 | your own curiousity!) 10 | """ 11 | # TODO: import the modules needed to make game_interface run. 12 | from strategy import interactive_strategy, recursive_strategy, \ 13 | rough_outcome_strategy, iterative_strategy 14 | from typing import Any, Callable 15 | from subtract_square_game import SubtractSquareGame 16 | from stonehenge import StoneHenge 17 | 18 | # TODO: Replace None with the corresponding class name for your games. 19 | # 'h' should map to Stonehenge. 20 | playable_games = {'s': SubtractSquareGame, 21 | 'h': StoneHenge} 22 | 23 | # TODO: Replace None with the corresponding function names for your strategies. 24 | # 'mr' should map to your recursive implementation of minimax while 25 | # 'mi' should map to your iterative implementation of minimax 26 | usable_strategies = {'i': interactive_strategy, 27 | 'ro': rough_outcome_strategy, 28 | 'mr': recursive_strategy, 29 | 'mi': iterative_strategy} 30 | 31 | 32 | class GameInterface: 33 | """ 34 | A game interface for a two-player, sequential move, zero-sum, 35 | perfect-information game. 36 | """ 37 | 38 | def __init__(self, game: Any, p1_strategy: Callable, 39 | p2_strategy: Callable[[Any], Any]) -> None: 40 | """ 41 | Initialize this GameInterface, setting its active game to game, and 42 | using the strategies p1_strategy for Player 1 and p2_strategy for 43 | Player 2. 44 | 45 | :param game: The game to be played. 46 | :type game: 47 | :param p1_strategy: The strategy for Player 1. 48 | :type p1_strategy: 49 | :param p2_strategy: The strategy for Play 2. 50 | :type p2_strategy: 51 | """ 52 | first_player = input("Type y if player 1 is to make the first move: ") 53 | is_p1_turn = False 54 | if first_player.lower() == 'y': 55 | is_p1_turn = True 56 | 57 | self.game = game(is_p1_turn) 58 | self.p1_strategy = p1_strategy 59 | self.p2_strategy = p2_strategy 60 | 61 | def play(self) -> None: 62 | """ 63 | Play the game. 64 | """ 65 | current_state = self.game.current_state 66 | 67 | print(self.game.get_instructions()) 68 | print(current_state) 69 | 70 | # Pick moves until the game is over 71 | while not self.game.is_over(current_state): 72 | move_to_make = None 73 | 74 | # Print out all of the valid moves 75 | possible_moves = current_state.get_possible_moves() 76 | print("The current available moves are:") 77 | for move in possible_moves: 78 | print(move) 79 | 80 | # Pick a (legal) move. 81 | while not current_state.is_valid_move(move_to_make): 82 | current_strategy = self.p2_strategy 83 | if current_state.get_current_player_name() == 'p1': 84 | current_strategy = self.p1_strategy 85 | move_to_make = current_strategy(self.game) 86 | 87 | # Apply the move 88 | current_player_name = current_state.get_current_player_name() 89 | new_game_state = current_state.make_move(move_to_make) 90 | self.game.current_state = new_game_state 91 | current_state = self.game.current_state 92 | 93 | print("{} made the move {}. The game's state is now:".format( 94 | current_player_name, move_to_make)) 95 | print(current_state) 96 | 97 | # Print out the winner of the game 98 | if self.game.is_winner("p1"): 99 | print("Player 1 is the winner!") 100 | elif self.game.is_winner("p2"): 101 | print("Player 2 is the winner!") 102 | else: 103 | print("It's a tie!") 104 | 105 | 106 | if __name__ == '__main__': 107 | games = ", ".join(["'{}': {}".format(key, playable_games[key].__name__) if 108 | playable_games[key] is not None else 109 | "'{}': None".format(key) for key in playable_games]) 110 | 111 | strategies = ", ".join(["'{}': {}".format(key, 112 | usable_strategies[key].__name__) 113 | if usable_strategies[key] is not None else 114 | "'{}': None".format(key) 115 | for key in usable_strategies]) 116 | 117 | chosen_game = '' 118 | while chosen_game not in playable_games.keys(): 119 | chosen_game = input( 120 | "Select the game you want to play ({}): ".format(games)) 121 | 122 | p1 = '' 123 | p2 = '' 124 | 125 | while p1 not in usable_strategies.keys(): 126 | p1 = input("Select the strategy for Player 1 ({}): ".format(strategies)) 127 | 128 | while p2 not in usable_strategies.keys(): 129 | p2 = input("Select the strategy for Player 2 ({}): ".format(strategies)) 130 | 131 | GameInterface(playable_games[chosen_game], usable_strategies[p1], 132 | usable_strategies[p2]).play() 133 | -------------------------------------------------------------------------------- /Labs/Lab 6/test_sum_leaves_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from hypothesis import given 4 | from hypothesis import note 5 | from hypothesis.strategies import integers 6 | from hypothesis.strategies import lists 7 | from hypothesis.strategies import recursive 8 | from ex6 import sum_leaves 9 | 10 | 11 | def make_children_list(children): 12 | """ 13 | Return a list of child Trees generated by children. 14 | 15 | @param list[object]|object children: The children values and trees 16 | @rtype: (list[Tree], int) 17 | """ 18 | leaves_sum = 0 19 | if type(children) != list: 20 | return [[Tree(children)], children] 21 | 22 | ret_children = [] 23 | for child in children: 24 | if type(child) == list: 25 | rec_call = make_children_list(child) 26 | value = random.randint(0, 100) 27 | ret_children.append(Tree(value, rec_call[0])) 28 | 29 | if not rec_call[0]: 30 | leaves_sum += value 31 | 32 | leaves_sum += rec_call[1] 33 | else: 34 | rec_call = make_children_list(child) 35 | ret_children += rec_call[0] 36 | leaves_sum += rec_call[1] 37 | 38 | # Pick a random value for the Tree's value 39 | return (ret_children, leaves_sum) 40 | 41 | class Tree: 42 | """ 43 | A bare-bones Tree ADT that identifies the root with the entire tree. 44 | """ 45 | def __init__(self, value=None, children=None): 46 | """ 47 | Create Tree self with content value and 0 or more children 48 | 49 | @param Tree self: this tree 50 | @param object value: value contained in this tree 51 | @param list[object|None] children: possibly-empty list of children 52 | @rtype: None 53 | """ 54 | self.value = value 55 | # copy children if not None 56 | self.children = children.copy() if children else [] 57 | 58 | def __repr__(self): 59 | """ 60 | Return representation of Tree (self) as string that 61 | can be evaluated into an equivalent Tree. 62 | 63 | @param Tree self: this tree 64 | @rtype: str 65 | 66 | >>> t1 = Tree(5) 67 | >>> t1 68 | Tree(5) 69 | >>> t2 = Tree(7, [t1]) 70 | >>> t2 71 | Tree(7, [Tree(5)]) 72 | """ 73 | # Our __repr__ is recursive, because it can also be called 74 | # via repr...! 75 | return ('Tree({}, {})'.format(repr(self.value), repr(self.children)) 76 | if self.children 77 | else 'Tree({})'.format(repr(self.value))) 78 | 79 | class CountInternalTests(unittest.TestCase): 80 | def test_returns_int(self): 81 | """ 82 | Test sum_leaves to make sure it returns an int. 83 | """ 84 | return_type = type(sum_leaves(Tree(0, [Tree(1, [Tree(2)])]))) 85 | self.assertEqual(return_type, int, "sum_leaves should return type" + 86 | "int, but instead returned type {}.".format(return_type 87 | )) 88 | 89 | def test_leaf_node(self): 90 | """ 91 | Test sum_leaves on a leaf node. 92 | """ 93 | self.assertEqual(sum_leaves(Tree(1)), 1, "Leaf nodes should " + 94 | "return their value.") 95 | 96 | def test_one_leaf_child(self): 97 | """ 98 | Test sum_leaves on a tree containing only a root and its leaf child. 99 | """ 100 | t = Tree(1, [Tree(2)]) 101 | 102 | self.assertEqual(sum_leaves(t), 2, "Internal nodes should not be " + 103 | "included in the sum, while leaf nodes (with no " + 104 | "children) should.") 105 | 106 | def test_multiple_leaf_children(self): 107 | """ 108 | Test sum_leaves on a tree containing only a root and its children 109 | which are all leaves. 110 | """ 111 | t = Tree(1, [Tree(2), Tree(3)]) 112 | 113 | self.assertEqual(sum_leaves(t), 5, "Internal nodes should not be " + 114 | "included in the sum, while leaf nodes (with no " + 115 | "children) should.") 116 | 117 | def test_multiple_non_leaf_children(self): 118 | """ 119 | Test sum_leaves on a tree containing only a root and its children 120 | which are all subtrees with children. 121 | """ 122 | t = Tree(1, [Tree(2, [Tree(4), Tree(6)]), Tree(3, [Tree(5), Tree(7)])]) 123 | 124 | self.assertEqual(sum_leaves(t), 22, "All leaf nodes should be " + 125 | "summed together.") 126 | 127 | @given(integers(min_value = -99, max_value = 99), 128 | recursive(integers(min_value = -99, max_value = 99), lists, 129 | max_leaves = 20)) 130 | def test_sum_leaves(self, value, children): 131 | """ 132 | Test the correctness of sum_leaves against the solution. 133 | """ 134 | (children_list, leaves_sum) = make_children_list(children) 135 | t = Tree(value, children_list) 136 | 137 | if not children_list: 138 | leaves_sum += value 139 | 140 | actual = sum_leaves(t) 141 | self.assertEqual(actual, leaves_sum, 142 | ("sum_leaves on the Tree\n{}\nReturned {}" + 143 | " instead of {}.").format(t.__repr__(), actual, 144 | leaves_sum)) 145 | 146 | if __name__ == "__main__": 147 | unittest.main() 148 | -------------------------------------------------------------------------------- /Labs/Lab 6/test_sum_internal_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from hypothesis import given 4 | from hypothesis import note 5 | from hypothesis.strategies import integers 6 | from hypothesis.strategies import lists 7 | from hypothesis.strategies import recursive 8 | from ex6 import sum_internal 9 | 10 | 11 | def make_children_list(children): 12 | """ 13 | Return a list of child Trees generated by children. 14 | 15 | @param list[object]|object children: The children values and trees 16 | @rtype: (list[Tree], int) 17 | """ 18 | internal_sum = 0 19 | if type(children) != list: 20 | return [[Tree(children)], 0] 21 | 22 | ret_children = [] 23 | for child in children: 24 | if type(child) == list: 25 | rec_call = make_children_list(child) 26 | value = random.randint(0, 100) 27 | ret_children.append(Tree(value, rec_call[0])) 28 | 29 | if rec_call[0]: 30 | internal_sum += value 31 | 32 | internal_sum += rec_call[1] 33 | else: 34 | rec_call = make_children_list(child) 35 | ret_children += rec_call[0] 36 | internal_sum += rec_call[1] 37 | 38 | # Pick a random value for the Tree's value 39 | return (ret_children, internal_sum) 40 | 41 | 42 | class Tree: 43 | """ 44 | A bare-bones Tree ADT that identifies the root with the entire tree. 45 | """ 46 | def __init__(self, value=None, children=None): 47 | """ 48 | Create Tree self with content value and 0 or more children 49 | 50 | @param Tree self: this tree 51 | @param object value: value contained in this tree 52 | @param list[object|None] children: possibly-empty list of children 53 | @rtype: None 54 | """ 55 | self.value = value 56 | # copy children if not None 57 | self.children = children.copy() if children else [] 58 | 59 | def __repr__(self): 60 | """ 61 | Return representation of Tree (self) as string that 62 | can be evaluated into an equivalent Tree. 63 | 64 | @param Tree self: this tree 65 | @rtype: str 66 | 67 | >>> t1 = Tree(5) 68 | >>> t1 69 | Tree(5) 70 | >>> t2 = Tree(7, [t1]) 71 | >>> t2 72 | Tree(7, [Tree(5)]) 73 | """ 74 | # Our __repr__ is recursive, because it can also be called 75 | # via repr...! 76 | return ('Tree({}, {})'.format(repr(self.value), repr(self.children)) 77 | if self.children 78 | else 'Tree({})'.format(repr(self.value))) 79 | 80 | class CountInternalTests(unittest.TestCase): 81 | def test_returns_int(self): 82 | """ 83 | Test sum_internal to make sure it returns an int. 84 | """ 85 | return_type = type(sum_internal(Tree(0, [Tree(1, [Tree(2)])]))) 86 | self.assertEqual(return_type, int, "sum_internal should return type" + 87 | "int, but instead returned type {}.".format(return_type 88 | )) 89 | 90 | def test_leaf_node(self): 91 | """ 92 | Test sum_internal on a leaf node. 93 | """ 94 | self.assertEqual(sum_internal(Tree(1)), 0, "Leaf nodes should " + 95 | "have 0 internal nodes to sum.") 96 | 97 | def test_one_leaf_child(self): 98 | """ 99 | Test sum_internal on a tree containing only a root and its leaf child. 100 | """ 101 | t = Tree(1, [Tree(2)]) 102 | 103 | self.assertEqual(sum_internal(t), 1, "Leaf nodes should not be " + 104 | "included in the sum, while root nodes (with " + 105 | "children) should.") 106 | 107 | def test_multiple_leaf_children(self): 108 | """ 109 | Test sum_internal on a tree containing only a root and its children 110 | which are all leaves. 111 | """ 112 | t = Tree(1, [Tree(2), Tree(3)]) 113 | 114 | self.assertEqual(sum_internal(t), 1, "Leaf nodes should not be " + 115 | "included in the sum, while root nodes (with " + 116 | "children) should.") 117 | 118 | def test_multiple_non_leaf_children(self): 119 | """ 120 | Test sum_internal on a tree containing only a root and its children 121 | which are all subtrees with children. 122 | """ 123 | t = Tree(1, [Tree(2, [Tree(4), Tree(6)]), Tree(3, [Tree(5), Tree(7)])]) 124 | 125 | self.assertEqual(sum_internal(t), 6, "All non-leaf nodes should be " + 126 | "summed together.") 127 | 128 | @given(integers(min_value = -99, max_value = 99), 129 | recursive(integers(min_value = -99, max_value = 99), lists, 130 | max_leaves = 20)) 131 | def test_sum_internal(self, value, children): 132 | """ 133 | Test the correctness of sum_internal against the solution. 134 | """ 135 | (children_list, internal_sum) = make_children_list(children) 136 | t = Tree(value, children_list) 137 | 138 | if children_list: 139 | internal_sum += value 140 | actual = sum_internal(t) 141 | self.assertEqual(actual, internal_sum, 142 | ("sum_internal on the Tree\n{}\nReturned {}" + 143 | " instead of {}.").format(t.__repr__(), actual, 144 | internal_sum)) 145 | 146 | if __name__ == "__main__": 147 | unittest.main() 148 | -------------------------------------------------------------------------------- /Labs/Lab 6/test_count_internal_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import random 3 | from hypothesis import given 4 | from hypothesis import note 5 | from hypothesis.strategies import integers 6 | from hypothesis.strategies import lists 7 | from hypothesis.strategies import recursive 8 | from ex6 import count_internal 9 | 10 | 11 | def make_children_list(children): 12 | """ 13 | Return a list of child Trees generated by children. 14 | 15 | @param list[object]|object children: The children values and trees 16 | @rtype: (list[Tree], int) 17 | """ 18 | num_internal = 0 19 | if type(children) != list: 20 | return [[Tree(children)], 0] 21 | 22 | ret_children = [] 23 | for child in children: 24 | if type(child) == list: 25 | rec_call = make_children_list(child) 26 | ret_children.append(Tree(random.randint(0, 100), rec_call[0])) 27 | 28 | if rec_call[0]: 29 | num_internal += 1 30 | 31 | num_internal += rec_call[1] 32 | else: 33 | rec_call = make_children_list(child) 34 | ret_children += rec_call[0] 35 | num_internal += rec_call[1] 36 | 37 | # Pick a random value for the Tree's value 38 | return (ret_children, num_internal) 39 | 40 | 41 | class Tree: 42 | """ 43 | A bare-bones Tree ADT that identifies the root with the entire tree. 44 | """ 45 | def __init__(self, value=None, children=None): 46 | """ 47 | Create Tree self with content value and 0 or more children 48 | 49 | @param Tree self: this tree 50 | @param object value: value contained in this tree 51 | @param list[object|None] children: possibly-empty list of children 52 | @rtype: None 53 | """ 54 | self.value = value 55 | # copy children if not None 56 | self.children = children.copy() if children else [] 57 | 58 | def __repr__(self): 59 | """ 60 | Return representation of Tree (self) as string that 61 | can be evaluated into an equivalent Tree. 62 | 63 | @param Tree self: this tree 64 | @rtype: str 65 | 66 | >>> t1 = Tree(5) 67 | >>> t1 68 | Tree(5) 69 | >>> t2 = Tree(7, [t1]) 70 | >>> t2 71 | Tree(7, [Tree(5)]) 72 | """ 73 | # Our __repr__ is recursive, because it can also be called 74 | # via repr...! 75 | return ('Tree({}, {})'.format(repr(self.value), repr(self.children)) 76 | if self.children 77 | else 'Tree({})'.format(repr(self.value))) 78 | 79 | 80 | class CountInternalTests(unittest.TestCase): 81 | def test_returns_int(self): 82 | """ 83 | Test count_internal to make sure it returns an int. 84 | """ 85 | return_type = type(count_internal(Tree(0, [Tree(1, [Tree(2)])]))) 86 | self.assertEqual(return_type, int, "count_internal should return type" + 87 | "int, but instead returned type {}.".format(return_type 88 | )) 89 | 90 | def test_leaf_node(self): 91 | """ 92 | Test count_internal on a leaf node. 93 | """ 94 | self.assertEqual(count_internal(Tree(0)), 0, "Leaf nodes should " + 95 | "have 0 internal nodes.") 96 | 97 | def test_one_leaf_child(self): 98 | """ 99 | Test count_internal on a tree containing only a root and its leaf child. 100 | """ 101 | t = Tree(0, [Tree(1)]) 102 | 103 | self.assertEqual(count_internal(t), 1, "Leaf nodes should not be " + 104 | "included in the count, while root nodes (with " + 105 | "children) should.") 106 | 107 | def test_multiple_leaf_children(self): 108 | """ 109 | Test count_internal on a tree containing only a root and its children 110 | which are all leaves. 111 | """ 112 | t = Tree(0, [Tree(1), Tree(2)]) 113 | 114 | self.assertEqual(count_internal(t), 1, "Leaf nodes should not be " + 115 | "included in the count, while root nodes (with " + 116 | "children) should.") 117 | 118 | def test_multiple_non_leaf_children(self): 119 | """ 120 | Test count_internal on a tree containing only a root and its children 121 | which are all subtrees with children. 122 | """ 123 | t = Tree(0, [Tree(1, [Tree(3), Tree(5)]), Tree(2, [Tree(4), Tree(6)])]) 124 | 125 | self.assertEqual(count_internal(t), 3, "All non-leaf nodes should be " + 126 | "counted as an internal node.") 127 | 128 | @given(integers(min_value = -99, max_value = 99), 129 | recursive(integers(min_value = -99, max_value = 99), lists, 130 | max_leaves = 20)) 131 | def test_count_internal(self, value, children): 132 | """ 133 | Test the correctness of count_internal against the solution. 134 | """ 135 | (children_list, num_internal) = make_children_list(children) 136 | t = Tree(value, children_list) 137 | 138 | if children_list: 139 | num_internal += 1 140 | actual = count_internal(t) 141 | self.assertEqual(actual, num_internal, 142 | ("count_internal on the Tree\n{}\nReturned {}" + 143 | " instead of {}.").format(t.__repr__(), actual, 144 | num_internal)) 145 | 146 | 147 | if __name__ == "__main__": 148 | unittest.main() 149 | -------------------------------------------------------------------------------- /Labs/Lab 7/test_sum_leaves_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from extra_practice import sum_leaves 4 | from hypothesis import given 5 | from hypothesis.strategies import recursive 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import tuples 8 | from hypothesis.strategies import none 9 | 10 | class BTNode: 11 | """ 12 | A Binary Tree, i.e. arity 2. 13 | === Attributes === 14 | @param object data: data in this node of tree 15 | @param BTNode|None left: left child 16 | @param BTNode|None right: right child 17 | @rtype: None 18 | """ 19 | 20 | 21 | def __init__(self, data, left=None, right=None): 22 | """ 23 | Create BTNode self with data and children left and right. 24 | @param BTNode self: this binary tree 25 | @param object data: data of this node 26 | @param BTNode|None left: left child 27 | @param BTNode|None right: right child 28 | @rtype: None 29 | """ 30 | self.data, self.left, self.right = data, left, right 31 | 32 | def tuples_to_tree(t): 33 | """ 34 | Return a BTNode generated from t and the number of leaves. 35 | 36 | Precondition: t is in the form (data, left child, right child) where 37 | left child and right child are either None, a data, or 38 | another tuple. 39 | 40 | @param tuple(bool, tuple|None|int, tuple|None|int) t: The tuple to turn 41 | into a BTNode 42 | @rtype: (BTNode, int) 43 | """ 44 | if t is None: 45 | return (None, 0) 46 | 47 | if type(t) == int: 48 | return (BTNode(t), t) 49 | 50 | (left, l_count) = tuples_to_tree(t[1]) 51 | (right, r_count) = tuples_to_tree(t[2]) 52 | sum_leaves = l_count + r_count 53 | 54 | if not left and not right: 55 | sum_leaves = t[0] 56 | 57 | return (BTNode(t[0], left, right), sum_leaves) 58 | 59 | class SumLeavesTests(unittest.TestCase): 60 | def test_returns_int(self): 61 | """ 62 | Test sum_leaves to make sure it returns an int. 63 | """ 64 | return_type = type(sum_leaves(BTNode(1))) 65 | 66 | self.assertEqual(return_type, int, "sum_leaves should return type " + 67 | "int, but instead returned type {}.".format( 68 | return_type)) 69 | 70 | def test_none(self): 71 | """ 72 | Test sum_leaves on None. 73 | """ 74 | self.assertEqual(sum_leaves(None), 0, "sum_leaves on None should " + 75 | "return 0.") 76 | 77 | def test_leaf(self): 78 | """ 79 | Test sum_leaves on a leaf. 80 | """ 81 | self.assertEqual(sum_leaves(BTNode(2)), 2, "sum_leaves should" + 82 | " return the leaf's data when used on a leaf.") 83 | 84 | def test_one_left_child(self): 85 | """ 86 | Test sum_leaves on a BTNode with one left child. 87 | """ 88 | t = BTNode(1, BTNode(5)) 89 | self.assertNotEqual(sum_leaves(t), 1, "sum_leaves should not " + 90 | "count None or any BTNodes with children as" + 91 | " leaf nodes.") 92 | self.assertNotEqual(sum_leaves(t), 6, "sum_leaves should not " + 93 | "count None or any BTNodes with children as" + 94 | " leaf nodes.") 95 | self.assertEqual(sum_leaves(t), 5, "sum_leaves should return the " + 96 | "data of the leaf child when used on a BTNode " + 97 | "with a single leaf child.") 98 | 99 | def test_one_right_child(self): 100 | """ 101 | Test sum_leaves on a BTNode with one right child 102 | """ 103 | t = BTNode(1, None, BTNode(5)) 104 | self.assertNotEqual(sum_leaves(t), 1, "sum_leaves should not " + 105 | "count None or any BTNodes with children as" + 106 | " leaf nodes.") 107 | self.assertNotEqual(sum_leaves(t), 6, "sum_leaves should not " + 108 | "count None or any BTNodes with children as" + 109 | " leaf nodes.") 110 | self.assertEqual(sum_leaves(t), 5, "sum_leaves should return the " + 111 | "data of the leaf child when used on a BTNode " + 112 | "with a single leaf child.") 113 | 114 | def test_two_leaf_children(self): 115 | """ 116 | Test sum_leaves on a BTNode with two leaf children. 117 | """ 118 | t = BTNode(5, BTNode(4), BTNode(3)) 119 | self.assertEqual(sum_leaves(t), 7, "sum_leaves should sum all " + 120 | "of the leaves in the entire BTNode.") 121 | 122 | @given(recursive(none() | integers(min_value=0, max_value=100), 123 | lambda children: tuples(integers(min_value = 0, 124 | max_value = 100), 125 | children, 126 | children)) 127 | ) 128 | def test_sum_leaves(self, tuple_tree): 129 | """ 130 | Test sum_leaves on a randomly generated BTNode. 131 | """ 132 | (t, expected) = tuples_to_tree(tuple_tree) 133 | actual = sum_leaves(t) 134 | self.assertEqual(actual, expected, 135 | ("test_sum_leaves on BTNode\n{}\nReturned {}" + 136 | " instead of {}.").format(tuple_tree, actual, 137 | expected)) 138 | 139 | if __name__ == '__main__': 140 | unittest.main() 141 | -------------------------------------------------------------------------------- /Labs/Lab 7/test_sum_internal_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from extra_practice import sum_internal 4 | from hypothesis import given 5 | from hypothesis.strategies import recursive 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import tuples 8 | from hypothesis.strategies import none 9 | 10 | 11 | class BTNode: 12 | """ 13 | A Binary Tree, i.e. arity 2. 14 | === Attributes === 15 | @param object data: data in this node of tree 16 | @param BTNode|None left: left child 17 | @param BTNode|None right: right child 18 | @rtype: None 19 | """ 20 | 21 | def __init__(self, data, left=None, right=None): 22 | """ 23 | Create BTNode self with data and children left and right. 24 | @param BTNode self: this binary tree 25 | @param object data: data of this node 26 | @param BTNode|None left: left child 27 | @param BTNode|None right: right child 28 | @rtype: None 29 | """ 30 | self.data, self.left, self.right = data, left, right 31 | 32 | 33 | def tuples_to_tree(t): 34 | """ 35 | Return a BTNode generated from t and the number of internal. 36 | 37 | Precondition: t is in the form (data, left child, right child) where 38 | left child and right child are either None, a data, or 39 | another tuple. 40 | 41 | @param tuple(bool, tuple|None|int, tuple|None|int) t: The tuple to turn 42 | into a BTNode 43 | @rtype: (BTNode, int) 44 | """ 45 | if t is None: 46 | return (None, 0) 47 | 48 | if type(t) == int: 49 | return (BTNode(t), 0) 50 | 51 | (left, l_count) = tuples_to_tree(t[1]) 52 | (right, r_count) = tuples_to_tree(t[2]) 53 | sum_internal = l_count + r_count 54 | 55 | if left or right: 56 | sum_internal += t[0] 57 | 58 | return (BTNode(t[0], left, right), sum_internal) 59 | 60 | 61 | class SumInternalTests(unittest.TestCase): 62 | def test_returns_int(self): 63 | """ 64 | Test sum_internal to make sure it returns an int. 65 | """ 66 | return_type = type(sum_internal(BTNode(1))) 67 | 68 | self.assertEqual(return_type, int, "sum_internal should return type " + 69 | "int, but instead returned type {}.".format( 70 | return_type)) 71 | 72 | def test_none(self): 73 | """ 74 | Test sum_internal on None. 75 | """ 76 | self.assertEqual(sum_internal(None), 0, "sum_internal on None should " + 77 | "return 0.") 78 | 79 | def test_leaf(self): 80 | """ 81 | Test sum_internal on a leaf. 82 | """ 83 | self.assertEqual(sum_internal(BTNode(2)), 0, "sum_internal should" + 84 | " return 0 when used on a leaf.") 85 | 86 | def test_one_left_child(self): 87 | """ 88 | Test sum_internal on a BTNode with one left child. 89 | """ 90 | t = BTNode(1, BTNode(5)) 91 | self.assertNotEqual(sum_internal(t), 5, "sum_internal should not " + 92 | "count None or any BTNodes without children as" + 93 | " internal nodes.") 94 | self.assertNotEqual(sum_internal(t), 6, "sum_internal should not " + 95 | "count None or any BTNodes without children as" + 96 | " internal nodes.") 97 | self.assertEqual(sum_internal(t), 1, "sum_internal should return the " + 98 | "data of the root node when used on a BTNode " + 99 | "with a single leaf child.") 100 | 101 | def test_one_right_child(self): 102 | """ 103 | Test sum_internal on a BTNode with one right child 104 | """ 105 | t = BTNode(1, None, BTNode(5)) 106 | self.assertNotEqual(sum_internal(t), 5, "sum_internal should not " + 107 | "count None or any BTNodes without children as" + 108 | " internal nodes.") 109 | self.assertNotEqual(sum_internal(t), 6, "sum_internal should not " + 110 | "count None or any BTNodes without children as" + 111 | " internal nodes.") 112 | self.assertEqual(sum_internal(t), 1, "sum_internal should return the " + 113 | "data of the root node when used on a BTNode " + 114 | "with a single leaf child.") 115 | 116 | def test_two_leaf_children(self): 117 | """ 118 | Test sum_internal on a BTNode with two leaf children. 119 | """ 120 | t = BTNode(5, BTNode(4), BTNode(3)) 121 | self.assertEqual(sum_internal(t), 5, "sum_internal should sum all " + 122 | "of the internal nodes in the entire BTNode.") 123 | 124 | @given(recursive(none() | integers(min_value=0, max_value=100), 125 | lambda children: tuples(integers(min_value = 0, 126 | max_value = 100), 127 | children, 128 | children)) 129 | ) 130 | def test_sum_internal(self, tuple_tree): 131 | """ 132 | Test sum_internal on a randomly generated BTNode. 133 | """ 134 | (t, expected) = tuples_to_tree(tuple_tree) 135 | actual = sum_internal(t) 136 | self.assertEqual(actual, expected, 137 | ("test_sum_internal on BTNode\n{}\nReturned {}" + 138 | " instead of {}.").format(tuple_tree, actual, 139 | expected)) 140 | 141 | 142 | if __name__ == '__main__': 143 | unittest.main() 144 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/subtract_square_state.py: -------------------------------------------------------------------------------- 1 | """ 2 | subclass of State: Subtract_Square_State 3 | """ 4 | from typing import Any, List 5 | from state import State 6 | 7 | 8 | class SubtractSquareState(State): 9 | """ 10 | subclass of State, game SubtractSquare 11 | """ 12 | starting_number: int 13 | 14 | def __init__(self, p1: bool, starting_number=-1) -> None: 15 | """ 16 | initialize a new game state for SubtractSquare game. 17 | 18 | >>> is_p1_turn = True 19 | >>> s1 = SubtractSquareState(is_p1_turn, 20) 20 | >>> is_p1_turn = False 21 | >>> s2 = SubtractSquareState(is_p1_turn, 30) 22 | """ 23 | State.__init__(self, p1) 24 | if starting_number == -1: 25 | self.starting_number = int(input("Choose a non-negtive whole number" 26 | ":")) 27 | else: 28 | self.starting_number = starting_number 29 | if self.starting_number == 0: 30 | self.is_game_over = True 31 | if self.is_p1_turn: 32 | self.is_p1_turn = False 33 | else: 34 | self.is_p1_turn = True 35 | 36 | def __eq__(self, other: Any) -> bool: 37 | """ 38 | return whether self is equal to other. 39 | 40 | >>> is_p1_turn = True 41 | >>> s1 = SubtractSquareState(is_p1_turn, 20) 42 | >>> s2 = SubtractSquareState(is_p1_turn, 30) 43 | >>> s1 == s2 44 | False 45 | >>> a1 = 7 46 | >>> a2 = 'few' 47 | >>> a1 == s1 48 | False 49 | >>> a2 == s2 50 | False 51 | >>> s3 = SubtractSquareState(is_p1_turn, 20) 52 | >>> s1 == s3 53 | True 54 | """ 55 | return (State.__eq__(self, other) 56 | and self.starting_number == other.starting_number) 57 | 58 | def __str__(self) -> str: 59 | """ 60 | return a str representation of game SubtractSquare state. 61 | 62 | >>> is_p1_turn = True 63 | >>> s2 = SubtractSquareState(is_p1_turn, 20) 64 | >>> print(s2) 65 | The current player is: p1, and the current value is: 20 66 | """ 67 | return "The current player is: {}, and the current value is: " \ 68 | "{}".format(self.get_current_player_name(), self.starting_number) 69 | 70 | def get_possible_moves(self) -> List: 71 | """ 72 | get possible moves based on current value 73 | 74 | >>> is_p1_turn = True 75 | >>> s1 = SubtractSquareState(is_p1_turn, 20) 76 | >>> s1.get_possible_moves() 77 | [1, 4, 9, 16] 78 | >>> s2 = SubtractSquareState(is_p1_turn, 30) 79 | >>> s2.get_possible_moves() 80 | [1, 4, 9, 16, 25] 81 | >>> s3 = SubtractSquareState(is_p1_turn, 25) 82 | >>> s3.get_possible_moves() 83 | [1, 4, 9, 16, 25] 84 | """ 85 | if self.starting_number == 1: 86 | possible_moves = [1] 87 | elif self.starting_number > 1: 88 | possible_moves = [i ** 2 for i in range(1, self.starting_number) 89 | if i ** 2 <= self.starting_number] 90 | else: 91 | return [] 92 | return possible_moves 93 | 94 | def is_valid_move(self, move_to_take: Any) -> bool: 95 | """ 96 | return whether a move_to_make is a valid move for player based on 97 | the rules of game 98 | 99 | >>> is_p1_turn = True 100 | >>> s1 = SubtractSquareState(is_p1_turn, 30) 101 | >>> s1.is_valid_move('25') 102 | False 103 | >>> s1.is_valid_move(25) 104 | True 105 | >>> s1.is_valid_move(12.3435) 106 | False 107 | >>> s1.is_valid_move(None) 108 | False 109 | """ 110 | return move_to_take in self.get_possible_moves() 111 | 112 | def get_current_player_name(self) -> str: 113 | """ 114 | get current player name 115 | 116 | >>> is_p1_turn = True 117 | >>> s1 = SubtractSquareState(is_p1_turn, 20) 118 | >>> s1.get_current_player_name() 119 | 'p1' 120 | >>> is_p1_turn = False 121 | >>> s2 = SubtractSquareState(is_p1_turn, 30) 122 | >>> s2.get_current_player_name() 123 | 'p2' 124 | """ 125 | return State.get_current_player_name(self) 126 | 127 | def make_move(self, move_to_make: int) -> 'SubtractSquareState': 128 | """ 129 | make move for the game 130 | 131 | >>> is_p1_turn = True 132 | >>> s1 = SubtractSquareState(is_p1_turn, 30) 133 | >>> s1.make_move(16).is_p1_turn 134 | False 135 | >>> s1.make_move(16).starting_number 136 | 14 137 | >>> s1.make_move(16).is_game_over 138 | False 139 | >>> s1.make_move(16).get_possible_moves() 140 | [1, 4, 9] 141 | >>> s1.make_move(16).get_current_player_name() 142 | 'p2' 143 | >>> s2 = SubtractSquareState(is_p1_turn, 1) 144 | >>> s2.make_move(1).get_current_player_name() 145 | 'p1' 146 | """ 147 | current_number = self.starting_number - move_to_make 148 | current_player = self.is_p1_turn 149 | is_game_current_over = self.is_game_over 150 | if current_number <= 0: 151 | is_game_current_over = True 152 | else: 153 | if current_player: 154 | current_player = False 155 | else: 156 | current_player = True 157 | new_state = SubtractSquareState(current_player, current_number) 158 | new_state.is_p1_turn = current_player 159 | new_state.is_game_over = is_game_current_over 160 | return new_state 161 | 162 | 163 | if __name__ == '__main__': 164 | import python_ta 165 | python_ta.check_all(config="a1_pyta.txt") 166 | -------------------------------------------------------------------------------- /Labs/Lab 7/test_concatenate_leaves_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from extra_practice import concatenate_leaves 4 | from hypothesis import given 5 | from hypothesis.strategies import recursive 6 | from hypothesis.strategies import text 7 | from hypothesis.strategies import tuples 8 | from hypothesis.strategies import none 9 | 10 | class BTNode: 11 | """ 12 | A Binary Tree, i.e. arity 2. 13 | === Attributes === 14 | @param object data: data in this node of tree 15 | @param BTNode|None left: left child 16 | @param BTNode|None right: right child 17 | @rtype: None 18 | """ 19 | 20 | 21 | def __init__(self, data, left=None, right=None): 22 | """ 23 | Create BTNode self with data and children left and right. 24 | @param BTNode self: this binary tree 25 | @param object data: data of this node 26 | @param BTNode|None left: left child 27 | @param BTNode|None right: right child 28 | @rtype: None 29 | """ 30 | self.data, self.left, self.right = data, left, right 31 | 32 | def tuples_to_tree(t): 33 | """ 34 | Return a BTNode generated from t and the number of leaves. 35 | 36 | Precondition: t is in the form (data, left child, right child) where 37 | left child and right child are either None, a data, or 38 | another tuple. 39 | 40 | @param tuple(bool, tuple|None|int, tuple|None|int) t: The tuple to turn 41 | into a BTNode 42 | @rtype: (BTNode, int) 43 | """ 44 | if t is None: 45 | return (None, '') 46 | 47 | if type(t) == str: 48 | return (BTNode(t), t) 49 | 50 | (left, l_count) = tuples_to_tree(t[1]) 51 | (right, r_count) = tuples_to_tree(t[2]) 52 | concatenate_leaves = l_count + r_count 53 | 54 | if not left and not right: 55 | concatenate_leaves = t[0] 56 | 57 | return (BTNode(t[0], left, right), concatenate_leaves) 58 | 59 | 60 | class ConcatenateLeavesTests(unittest.TestCase): 61 | def test_returns_int(self): 62 | """ 63 | Test concatenate_leaves to make sure it returns an int. 64 | """ 65 | return_type = type(concatenate_leaves(BTNode("a"))) 66 | 67 | self.assertEqual(return_type, str, 68 | "concatenate_leaves should return type " + 69 | "int, but instead returned type {}.".format( 70 | return_type)) 71 | 72 | def test_none(self): 73 | """ 74 | Test concatenate_leaves on None. 75 | """ 76 | self.assertEqual(concatenate_leaves(None), "", 77 | "concatenate_leaves on None should " + 78 | "return ''.") 79 | 80 | def test_leaf(self): 81 | """ 82 | Test concatenate_leaves on a leaf. 83 | """ 84 | self.assertEqual(concatenate_leaves(BTNode("a")), "a", 85 | "concatenate_leaves should" + 86 | " return the leaf's data when used on a leaf.") 87 | 88 | def test_one_left_child(self): 89 | """ 90 | Test concatenate_leaves on a BTNode with one left child. 91 | """ 92 | t = BTNode("a", BTNode("b")) 93 | self.assertNotEqual(concatenate_leaves(t), "ab", 94 | "concatenate_leaves should not " + 95 | "count None or any BTNodes with children as" + 96 | " leaf nodes.") 97 | self.assertNotEqual(concatenate_leaves(t), "a", 98 | "concatenate_leaves should not " + 99 | "count None or any BTNodes with children as" + 100 | " leaf nodes.") 101 | self.assertEqual(concatenate_leaves(t), "b", 102 | "concatenate_leaves should return the " + 103 | "data of the leaf child when used on a BTNode " + 104 | "with a single leaf child.") 105 | 106 | def test_one_right_child(self): 107 | """ 108 | Test concatenate_leaves on a BTNode with one right child 109 | """ 110 | t = BTNode("a", None, BTNode("b")) 111 | self.assertNotEqual(concatenate_leaves(t), "ab", 112 | "concatenate_leaves should not " + 113 | "count None or any BTNodes with children as" + 114 | " leaf nodes.") 115 | self.assertNotEqual(concatenate_leaves(t), "a", 116 | "concatenate_leaves should not " + 117 | "count None or any BTNodes with children as" + 118 | " leaf nodes.") 119 | self.assertEqual(concatenate_leaves(t), "b", 120 | "concatenate_leaves should return the " + 121 | "data of the leaf child when used on a BTNode " + 122 | "with a single leaf child.") 123 | 124 | def test_two_leaf_children(self): 125 | """ 126 | Test concatenate_leaves on a BTNode with two leaf children. 127 | """ 128 | t = BTNode("a", BTNode("b"), BTNode("c")) 129 | self.assertEqual(concatenate_leaves(t), "bc", 130 | "concatenate_leaves should sum all " + 131 | "of the leaves in the entire BTNode.") 132 | 133 | @given(recursive(none() | text(max_size=3), 134 | lambda children: tuples(text(max_size = 3), 135 | children, 136 | children)) 137 | ) 138 | def test_concatenate_leaves(self, tuple_tree): 139 | """ 140 | Test concatenate_leaves on a randomly generated BTNode. 141 | """ 142 | (t, expected) = tuples_to_tree(tuple_tree) 143 | actual = concatenate_leaves(t) 144 | self.assertEqual(actual, expected, 145 | ("test_concatenate_leaves on BTNode\n{}" + 146 | "\nReturned {}" + 147 | " instead of {}.").format(tuple_tree, actual, 148 | expected)) 149 | 150 | 151 | if __name__ == '__main__': 152 | unittest.main() 153 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_list_even_ex5.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for list_even 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from ex5 import list_even 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | """ 28 | 29 | nested_list_values = [] 30 | 31 | list_to_add_to = nested_list_values 32 | list_to_use = list_values 33 | 34 | sublist = [] 35 | finished_forming_sublist = True 36 | 37 | return_list = [] 38 | 39 | for n in range(len(nested_index_sets)): 40 | nested_indices = nested_index_sets[n] 41 | 42 | if n == len(nested_index_sets) - 1: 43 | list_to_add_to = return_list 44 | 45 | for i in range(len(list_to_use)): 46 | if nested_indices: 47 | if i == nested_indices[0]: 48 | nested_indices.pop(0) 49 | finished_forming_sublist = not finished_forming_sublist 50 | 51 | sublist.append(list_to_use[i]) 52 | 53 | # Add the formed sublist into nested_list_values 54 | if finished_forming_sublist: 55 | list_to_add_to.append(sublist) 56 | sublist = [] 57 | 58 | if nested_indices and nested_indices[0] == i: 59 | finished_forming_sublist = True 60 | list_to_add_to.append(sublist) 61 | sublist = [] 62 | while nested_indices and nested_indices[0] == i: 63 | nested_indices.pop(0) 64 | else: 65 | if not finished_forming_sublist: 66 | sublist.append(list_to_use[i]) 67 | else: 68 | # We're not forming a sublist at the moment, so 69 | # append to nested_list_values. 70 | list_to_add_to.append(list_to_use[i]) 71 | else: 72 | if not finished_forming_sublist: 73 | list_to_add_to.append(sublist) 74 | sublist = [] 75 | finished_forming_sublist = True 76 | 77 | list_to_add_to.append(list_to_use[i]) 78 | 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_use = list_to_add_to 85 | list_to_add_to = [] 86 | 87 | return return_list 88 | 89 | 90 | class ListEvenTests(unittest.TestCase): 91 | def test_returns_list(self): 92 | """ 93 | Test list_even to make sure it returns a list. 94 | """ 95 | return_type = type(list_even(1)) 96 | self.assertEqual(return_type, list, "list_even should return type " + 97 | "list, but instead returned type {}.".format( 98 | return_type)) 99 | 100 | def test_odd_integer(self): 101 | """ 102 | Test list_even on an odd integer. 103 | """ 104 | self.assertEqual(list_even(1), [], "list_even should return an empty " + 105 | "list when passed an odd integer.") 106 | 107 | def test_even_integer(self): 108 | """ 109 | Test list_even on an even integer. 110 | """ 111 | self.assertEqual(list_even(2), [2], "list_even should return a " + 112 | "list containing the even integer passed in when " + 113 | "given an even integer.") 114 | 115 | 116 | def test_one_nested_sublist(self): 117 | """ 118 | Test list_even on a list with only one sublist in it. 119 | """ 120 | self.assertEqual(list_even([[2]]), [2], "list_even should return " + 121 | "the even integers in nested sublists.") 122 | 123 | 124 | def test_one_nested_sublist_and_integers(self): 125 | """ 126 | Test list_even on a list with at most one level of nested sublists in 127 | it mixed with integers. 128 | """ 129 | self.assertEqual(list_even([[2], 3, [4]]), [2, 4], 130 | "list_even should return the even integers in nested" + 131 | " sublists and in the list passed in.") 132 | 133 | 134 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 135 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 136 | max_size = 20)) 137 | def test_list_even(self, list_values, list_indices): 138 | """ 139 | Test the submitted list_even against a randomly generated list. 140 | """ 141 | 142 | # Gather all of the even values 143 | expected = [] 144 | for n in list_values: 145 | if n % 2 == 0: 146 | expected.append(n) 147 | expected.sort() 148 | 149 | # Create up to 2 levels of nesting for the values in list_values, where 150 | # the indices we turn into sublists are contained in 151 | # nesting_indices_1 and nesting_indices_2 152 | nesting_indices_1 = list_indices[:len(list_indices)//2] 153 | nesting_indices_2 = list_indices[len(list_indices)//2:] 154 | nesting_indices_1.sort() 155 | nesting_indices_2.sort() 156 | 157 | obj = create_nested_list(list_values, [nesting_indices_1, 158 | nesting_indices_2]) 159 | 160 | # Ignoring the order of the values, in case students have an 161 | # out-of-order version for some reason. 162 | actual = list_even(obj) 163 | actual.sort() 164 | 165 | self.assertEqual(actual, expected, 166 | ("Using list_even on {} returned" + 167 | " {} instead of {}.").format(obj, actual, expected)) 168 | 169 | if __name__ == "__main__": 170 | unittest.main() 171 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_list_even_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for list_even 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from recursion_exercise import list_even 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | """ 28 | 29 | nested_list_values = [] 30 | 31 | list_to_add_to = nested_list_values 32 | list_to_use = list_values 33 | 34 | sublist = [] 35 | finished_forming_sublist = True 36 | 37 | return_list = [] 38 | 39 | for n in range(len(nested_index_sets)): 40 | nested_indices = nested_index_sets[n] 41 | 42 | if n == len(nested_index_sets) - 1: 43 | list_to_add_to = return_list 44 | 45 | for i in range(len(list_to_use)): 46 | if nested_indices: 47 | if i == nested_indices[0]: 48 | nested_indices.pop(0) 49 | finished_forming_sublist = not finished_forming_sublist 50 | 51 | sublist.append(list_to_use[i]) 52 | 53 | # Add the formed sublist into nested_list_values 54 | if finished_forming_sublist: 55 | list_to_add_to.append(sublist) 56 | sublist = [] 57 | 58 | if nested_indices and nested_indices[0] == i: 59 | finished_forming_sublist = True 60 | list_to_add_to.append(sublist) 61 | sublist = [] 62 | while nested_indices and nested_indices[0] == i: 63 | nested_indices.pop(0) 64 | else: 65 | if not finished_forming_sublist: 66 | sublist.append(list_to_use[i]) 67 | else: 68 | # We're not forming a sublist at the moment, so 69 | # append to nested_list_values. 70 | list_to_add_to.append(list_to_use[i]) 71 | else: 72 | if not finished_forming_sublist: 73 | list_to_add_to.append(sublist) 74 | sublist = [] 75 | finished_forming_sublist = True 76 | 77 | list_to_add_to.append(list_to_use[i]) 78 | 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_use = list_to_add_to 85 | list_to_add_to = [] 86 | 87 | return return_list 88 | 89 | 90 | class ListEvenTests(unittest.TestCase): 91 | def test_returns_list(self): 92 | """ 93 | Test list_even to make sure it returns a list. 94 | """ 95 | return_type = type(list_even(1)) 96 | self.assertEqual(return_type, list, "list_even should return type " + 97 | "list, but instead returned type {}.".format( 98 | return_type)) 99 | 100 | def test_odd_integer(self): 101 | """ 102 | Test list_even on an odd integer. 103 | """ 104 | self.assertEqual(list_even(1), [], "list_even should return an empty " + 105 | "list when passed an odd integer.") 106 | 107 | def test_even_integer(self): 108 | """ 109 | Test list_even on an even integer. 110 | """ 111 | self.assertEqual(list_even(2), [2], "list_even should return a " + 112 | "list containing the even integer passed in when " + 113 | "given an even integer.") 114 | 115 | 116 | def test_one_nested_sublist(self): 117 | """ 118 | Test list_even on a list with only one sublist in it. 119 | """ 120 | self.assertEqual(list_even([[2]]), [2], "list_even should return " + 121 | "the even integers in nested sublists.") 122 | 123 | 124 | def test_one_nested_sublist_and_integers(self): 125 | """ 126 | Test list_even on a list with at most one level of nested sublists in 127 | it mixed with integers. 128 | """ 129 | self.assertEqual(list_even([[2], 3, [4]]), [2, 4], 130 | "list_even should return the even integers in nested" + 131 | " sublists and in the list passed in.") 132 | 133 | 134 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 135 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 136 | max_size = 20)) 137 | def test_list_even(self, list_values, list_indices): 138 | """ 139 | Test the submitted list_even against a randomly generated list. 140 | """ 141 | 142 | # Gather all of the even values 143 | expected = [] 144 | for n in list_values: 145 | if n % 2 == 0: 146 | expected.append(n) 147 | expected.sort() 148 | 149 | # Create up to 2 levels of nesting for the values in list_values, where 150 | # the indices we turn into sublists are contained in 151 | # nesting_indices_1 and nesting_indices_2 152 | nesting_indices_1 = list_indices[:len(list_indices)//2] 153 | nesting_indices_2 = list_indices[len(list_indices)//2:] 154 | nesting_indices_1.sort() 155 | nesting_indices_2.sort() 156 | 157 | obj = create_nested_list(list_values, [nesting_indices_1, 158 | nesting_indices_2]) 159 | 160 | # Ignoring the order of the values, in case students have an 161 | # out-of-order version for some reason. 162 | actual = list_even(obj) 163 | actual.sort() 164 | 165 | self.assertEqual(actual, expected, 166 | ("Using list_even on {} returned" + 167 | " {} instead of {}.").format(obj, actual, expected)) 168 | 169 | if __name__ == "__main__": 170 | unittest.main() 171 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_all_ex5.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for count_all 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from ex5 import count_all 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 29 | [[0, 1], 2, [3], 4] 30 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 31 | [[[0, 1], 2], 3, 4] 32 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 33 | [[[0, 1], 2, [3]], 4] 34 | """ 35 | 36 | nested_list_values = [] 37 | 38 | list_to_add_to = nested_list_values 39 | list_to_use = list_values 40 | 41 | sublist = [] 42 | finished_forming_sublist = True 43 | 44 | return_list = [] 45 | 46 | for n in range(len(nested_index_sets)): 47 | nested_indices = nested_index_sets[n] 48 | 49 | if n == len(nested_index_sets) - 1: 50 | list_to_add_to = return_list 51 | 52 | for i in range(len(list_to_use)): 53 | if nested_indices: 54 | if i == nested_indices[0]: 55 | nested_indices.pop(0) 56 | finished_forming_sublist = not finished_forming_sublist 57 | 58 | sublist.append(list_to_use[i]) 59 | 60 | # Add the formed sublist into nested_list_values 61 | if finished_forming_sublist: 62 | list_to_add_to.append(sublist) 63 | sublist = [] 64 | 65 | if nested_indices and nested_indices[0] == i: 66 | finished_forming_sublist = True 67 | list_to_add_to.append(sublist) 68 | sublist = [] 69 | while nested_indices and nested_indices[0] == i: 70 | nested_indices.pop(0) 71 | else: 72 | if not finished_forming_sublist: 73 | sublist.append(list_to_use[i]) 74 | else: 75 | # We're not forming a sublist at the moment, so 76 | # append to nested_list_values. 77 | list_to_add_to.append(list_to_use[i]) 78 | else: 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_add_to.append(list_to_use[i]) 85 | 86 | if not finished_forming_sublist: 87 | list_to_add_to.append(sublist) 88 | sublist = [] 89 | finished_forming_sublist = True 90 | 91 | list_to_use = list_to_add_to 92 | list_to_add_to = [] 93 | 94 | return return_list 95 | 96 | 97 | class CountAllTests(unittest.TestCase): 98 | def test_returns_int(self): 99 | """ 100 | Test list_even to make sure it returns an int. 101 | """ 102 | return_type = type(count_all(1)) 103 | self.assertEqual(return_type, int, "count_even should return type " + 104 | "int, but instead returned type {}.".format( 105 | return_type)) 106 | 107 | return_type = type(count_all([1])) 108 | self.assertEqual(return_type, int, "count_even should return type " + 109 | "int, but instead returned type {}.".format( 110 | return_type)) 111 | 112 | def test_integer(self): 113 | """ 114 | Test list_even on an integer. 115 | """ 116 | self.assertEqual(count_all(1), 1, "count_all should return 1 " + 117 | "when passed a single integer.") 118 | 119 | def test_one_nested_sublist(self): 120 | """ 121 | Test list_even on a list with only one sublist in it. 122 | """ 123 | self.assertEqual(count_all([[2]]), 1, "count_all should return " + 124 | "the number of integers in nested sublists.") 125 | 126 | 127 | def test_one_nested_sublist_and_integers(self): 128 | """ 129 | Test list_even on a list with at most one level of nested sublists in 130 | it mixed with integers. 131 | """ 132 | self.assertEqual(count_all([[2], 3, [4]]), 3, 133 | "count_even should return the number of " + 134 | "integers in nested sublists and in the list passed " + 135 | "in.") 136 | 137 | 138 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 139 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 140 | max_size = 20)) 141 | def test_count_all(self, list_values, list_indices): 142 | """ 143 | Test the submitted count_even against a randomly generated list. 144 | """ 145 | 146 | # Gather all of the even values 147 | expected = len(list_values) 148 | 149 | # Create up to 2 levels of nesting for the values in list_values, where 150 | # the indices we turn into sublists are contained in 151 | # nesting_indices_1 and nesting_indices_2 152 | nesting_indices_1 = list_indices[:len(list_indices)//2] 153 | nesting_indices_2 = list_indices[len(list_indices)//2:] 154 | nesting_indices_1.sort() 155 | nesting_indices_2.sort() 156 | 157 | obj = create_nested_list(list_values, [nesting_indices_1, 158 | nesting_indices_2]) 159 | 160 | # Ignoring the order of the values, in case students have an 161 | # out-of-order version for some reason. 162 | actual = count_all(obj) 163 | 164 | self.assertEqual(actual, expected, 165 | ("Using count_even on {} returned" + 166 | " {} instead of {}.").format(obj, actual, expected)) 167 | 168 | if __name__ == "__main__": 169 | unittest.main() 170 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_all_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for count_all 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from recursion_exercise import count_all 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 29 | [[0, 1], 2, [3], 4] 30 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 31 | [[[0, 1], 2], 3, 4] 32 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 33 | [[[0, 1], 2, [3]], 4] 34 | """ 35 | 36 | nested_list_values = [] 37 | 38 | list_to_add_to = nested_list_values 39 | list_to_use = list_values 40 | 41 | sublist = [] 42 | finished_forming_sublist = True 43 | 44 | return_list = [] 45 | 46 | for n in range(len(nested_index_sets)): 47 | nested_indices = nested_index_sets[n] 48 | 49 | if n == len(nested_index_sets) - 1: 50 | list_to_add_to = return_list 51 | 52 | for i in range(len(list_to_use)): 53 | if nested_indices: 54 | if i == nested_indices[0]: 55 | nested_indices.pop(0) 56 | finished_forming_sublist = not finished_forming_sublist 57 | 58 | sublist.append(list_to_use[i]) 59 | 60 | # Add the formed sublist into nested_list_values 61 | if finished_forming_sublist: 62 | list_to_add_to.append(sublist) 63 | sublist = [] 64 | 65 | if nested_indices and nested_indices[0] == i: 66 | finished_forming_sublist = True 67 | list_to_add_to.append(sublist) 68 | sublist = [] 69 | while nested_indices and nested_indices[0] == i: 70 | nested_indices.pop(0) 71 | else: 72 | if not finished_forming_sublist: 73 | sublist.append(list_to_use[i]) 74 | else: 75 | # We're not forming a sublist at the moment, so 76 | # append to nested_list_values. 77 | list_to_add_to.append(list_to_use[i]) 78 | else: 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_add_to.append(list_to_use[i]) 85 | 86 | if not finished_forming_sublist: 87 | list_to_add_to.append(sublist) 88 | sublist = [] 89 | finished_forming_sublist = True 90 | 91 | list_to_use = list_to_add_to 92 | list_to_add_to = [] 93 | 94 | return return_list 95 | 96 | 97 | class CountAllTests(unittest.TestCase): 98 | def test_returns_int(self): 99 | """ 100 | Test list_even to make sure it returns an int. 101 | """ 102 | return_type = type(count_all(1)) 103 | self.assertEqual(return_type, int, "count_even should return type " + 104 | "int, but instead returned type {}.".format( 105 | return_type)) 106 | 107 | return_type = type(count_all([1])) 108 | self.assertEqual(return_type, int, "count_even should return type " + 109 | "int, but instead returned type {}.".format( 110 | return_type)) 111 | 112 | def test_integer(self): 113 | """ 114 | Test list_even on an integer. 115 | """ 116 | self.assertEqual(count_all(1), 1, "count_all should return 1 " + 117 | "when passed a single integer.") 118 | 119 | def test_one_nested_sublist(self): 120 | """ 121 | Test list_even on a list with only one sublist in it. 122 | """ 123 | self.assertEqual(count_all([[2]]), 1, "count_all should return " + 124 | "the number of integers in nested sublists.") 125 | 126 | 127 | def test_one_nested_sublist_and_integers(self): 128 | """ 129 | Test list_even on a list with at most one level of nested sublists in 130 | it mixed with integers. 131 | """ 132 | self.assertEqual(count_all([[2], 3, [4]]), 3, 133 | "count_even should return the number of " + 134 | "integers in nested sublists and in the list passed " + 135 | "in.") 136 | 137 | 138 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 139 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 140 | max_size = 20)) 141 | def test_count_all(self, list_values, list_indices): 142 | """ 143 | Test the submitted count_even against a randomly generated list. 144 | """ 145 | 146 | # Gather all of the even values 147 | expected = len(list_values) 148 | 149 | # Create up to 2 levels of nesting for the values in list_values, where 150 | # the indices we turn into sublists are contained in 151 | # nesting_indices_1 and nesting_indices_2 152 | nesting_indices_1 = list_indices[:len(list_indices)//2] 153 | nesting_indices_2 = list_indices[len(list_indices)//2:] 154 | nesting_indices_1.sort() 155 | nesting_indices_2.sort() 156 | 157 | obj = create_nested_list(list_values, [nesting_indices_1, 158 | nesting_indices_2]) 159 | 160 | # Ignoring the order of the values, in case students have an 161 | # out-of-order version for some reason. 162 | actual = count_all(obj) 163 | 164 | self.assertEqual(actual, expected, 165 | ("Using count_even on {} returned" + 166 | " {} instead of {}.").format(obj, actual, expected)) 167 | 168 | if __name__ == "__main__": 169 | unittest.main() 170 | -------------------------------------------------------------------------------- /Assignments/Assignment 2/strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | A module for strategies. 3 | 4 | NOTE: Make sure this file adheres to python-ta. 5 | Adjust the type annotations as needed, and implement both a recursive 6 | and an iterative version of minimax. 7 | """ 8 | from typing import Any 9 | 10 | 11 | # TODO: Adjust the type annotation as needed. 12 | def interactive_strategy(game: Any) -> Any: 13 | """ 14 | Return a move for game through interactively asking the user for input. 15 | """ 16 | move = input("Enter a move: ") 17 | return game.str_to_move(move) 18 | 19 | 20 | def rough_outcome_strategy(game: Any) -> Any: 21 | """ 22 | Return a move for game by picking a move which results in a state with 23 | the lowest rough_outcome() for the opponent. 24 | 25 | NOTE: game.rough_outcome() should do the following: 26 | - For a state that's over, it returns the score for the current 27 | player of that state. 28 | - For a state that's not over: 29 | - If there is a move that results in the current player winning, 30 | return 1. 31 | - If all moves result in states where the other player can 32 | immediately win, return -1. 33 | - Otherwise; return a number between -1 and 1 corresponding to how 34 | 'likely' the current player will win from the current state. 35 | 36 | In essence: rough_outcome() will only look 1 or 2 states ahead to 37 | 'guess' the outcome of the game, but no further. It's better than 38 | random, but worse than minimax. 39 | """ 40 | current_state = game.current_state 41 | best_move = None 42 | best_outcome = -2 # Temporarily -- just so we can replace this easily later 43 | 44 | # Get the move that results in the lowest rough_outcome for the opponent 45 | for move in current_state.get_possible_moves(): 46 | new_state = current_state.make_move(move) 47 | 48 | # We multiply the below by -1 since a state that's bad for the opponent 49 | # is good for us. 50 | guessed_score = new_state.rough_outcome() * -1 51 | if guessed_score > best_outcome: 52 | best_outcome = guessed_score 53 | best_move = move 54 | 55 | # Return the move that resulted in the best rough_outcome 56 | return best_move 57 | 58 | 59 | # TODO: Implement a recursive version of the minimax strategy. 60 | def helper_recursive(game: Any, state: Any) -> int: 61 | """ 62 | return one move's score 63 | """ 64 | game.current_state = state 65 | if game.is_over(state): 66 | player = state.get_current_player_name() 67 | if player == 'p1': 68 | opposite = 'p2' 69 | else: 70 | opposite = 'p1' 71 | if game.is_winner(player): 72 | return 1 73 | elif not game.is_winner(player) and game.is_winner(opposite): 74 | return -1 75 | return 0 76 | else: 77 | return -1 * min([helper_recursive(game, state.make_move(move)) 78 | for move in state.get_possible_moves()]) 79 | 80 | 81 | def recursive_strategy(game: Any) -> Any: 82 | """ 83 | Return a move for game by picking a move which results in a state with 84 | the lowest score for the opponent. 85 | """ 86 | moves = game.current_state.get_possible_moves() 87 | current_state = game.current_state 88 | states = [current_state.make_move(move) for move in moves] 89 | score_for_move_next_player = [helper_recursive(game, state_) 90 | for state_ in states] 91 | score_for_move_original_player = [-1 * score 92 | for score in score_for_move_next_player] 93 | game.current_state = current_state 94 | if 1 in score_for_move_original_player: 95 | return moves[score_for_move_original_player.index(1)] 96 | elif 0 in score_for_move_original_player: 97 | return moves[score_for_move_original_player.index(0)] 98 | return moves[0] 99 | 100 | 101 | # TODO: Implement an iterative version of the minimax strategy. 102 | class StateNode: 103 | """ 104 | a class tree_like_node to implement iterative strategy 105 | 106 | state - state 107 | score - score 108 | children - children 109 | """ 110 | state: Any 111 | score: int 112 | children: list 113 | 114 | def __init__(self, state: Any) -> None: 115 | """ 116 | initialize a new StateNode 117 | """ 118 | self.state = state 119 | self.score = None 120 | self.children = None 121 | 122 | def __repr__(self) -> str: 123 | """ 124 | return a str representation of StateNode for evaluating 125 | """ 126 | return "StateNodeScore: {}, StateNodeChildren: {}, State: {}".\ 127 | format(self.score, self.children, str(self.state)) 128 | 129 | 130 | def iterative_strategy(game: Any) -> Any: 131 | """ 132 | Return a move for game by picking a move which results in a state with 133 | the lowest score for the opponent. 134 | """ 135 | current_state = game.current_state 136 | old_state = game.current_state 137 | possible_moves = current_state.get_possible_moves() 138 | original_state_node = StateNode(current_state) 139 | stack = [original_state_node] 140 | while stack: 141 | last_one_pop = stack.pop() 142 | if game.is_over(last_one_pop.state): 143 | game.current_state = last_one_pop.state 144 | player = game.current_state.get_current_player_name() 145 | if player == 'p1': 146 | opposite = 'p2' 147 | else: 148 | opposite = 'p1' 149 | if game.is_winner(player): 150 | last_one_pop.score = 1 151 | elif not game.is_winner(player) and game.is_winner(opposite): 152 | last_one_pop.score = -1 153 | else: 154 | last_one_pop.score = 0 155 | else: 156 | if last_one_pop.children is not None: 157 | last_one_pop.score = -1 * min([child.score 158 | for child in 159 | last_one_pop.children]) 160 | else: 161 | last_one_pop.children = [ 162 | StateNode(last_one_pop.state.make_move(move)) 163 | for move in last_one_pop.state.get_possible_moves()] 164 | stack.append(last_one_pop) 165 | stack.extend(last_one_pop.children) 166 | game.current_state = old_state 167 | if last_one_pop.score == 1: 168 | for child in last_one_pop.children: 169 | if child.score == -1: 170 | return possible_moves[last_one_pop.children.index(child)] 171 | elif last_one_pop.score == 0: 172 | for child in last_one_pop.children: 173 | if child.score == 0: 174 | return possible_moves[last_one_pop.children.index(child)] 175 | 176 | return possible_moves[0] 177 | 178 | 179 | if __name__ == "__main__": 180 | from python_ta import check_all 181 | check_all(config="a2_pyta.txt") 182 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_above_ex5.py: -------------------------------------------------------------------------------- 1 | """ 2 | count above unit tests 3 | """ 4 | import unittest 5 | from typing import List 6 | from hypothesis import given 7 | from hypothesis.strategies import integers 8 | from hypothesis.strategies import lists 9 | from ex5 import count_above 10 | 11 | 12 | def create_nested_list(list_values: list, nested_index_sets: List[List[int]]) -> list: 13 | """ 14 | Create nested lists from values in list_values and indices in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 25 | [[0, 1], 2, [3], 4] 26 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 27 | [[[0, 1], 2], 3, 4] 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 29 | [[[0, 1], 2, [3]], 4] 30 | """ 31 | 32 | nested_list_values = [] 33 | 34 | list_to_add_to = nested_list_values 35 | list_to_use = list_values 36 | 37 | sublist = [] 38 | finished_forming_sublist = True 39 | 40 | return_list = [] 41 | 42 | for n in range(len(nested_index_sets)): 43 | nested_indices = nested_index_sets[n] 44 | 45 | if n == len(nested_index_sets) - 1: 46 | list_to_add_to = return_list 47 | 48 | for i in range(len(list_to_use)): 49 | if nested_indices: 50 | if i == nested_indices[0]: 51 | nested_indices.pop(0) 52 | finished_forming_sublist = not finished_forming_sublist 53 | 54 | sublist.append(list_to_use[i]) 55 | 56 | # Add the formed sublist into nested_list_values 57 | if finished_forming_sublist: 58 | list_to_add_to.append(sublist) 59 | sublist = [] 60 | 61 | if nested_indices and nested_indices[0] == i: 62 | finished_forming_sublist = True 63 | list_to_add_to.append(sublist) 64 | sublist = [] 65 | while nested_indices and nested_indices[0] == i: 66 | nested_indices.pop(0) 67 | else: 68 | if not finished_forming_sublist: 69 | sublist.append(list_to_use[i]) 70 | else: 71 | # We're not forming a sublist at the moment, so 72 | # append to nested_list_values. 73 | list_to_add_to.append(list_to_use[i]) 74 | else: 75 | if not finished_forming_sublist: 76 | list_to_add_to.append(sublist) 77 | sublist = [] 78 | finished_forming_sublist = True 79 | 80 | list_to_add_to.append(list_to_use[i]) 81 | 82 | if not finished_forming_sublist: 83 | list_to_add_to.append(sublist) 84 | sublist = [] 85 | finished_forming_sublist = True 86 | 87 | list_to_use = list_to_add_to 88 | list_to_add_to = [] 89 | 90 | return return_list 91 | 92 | 93 | class CountAboveTests(unittest.TestCase): 94 | def test_returns_int(self): 95 | """ 96 | Test count_above to make sure it returns an int. 97 | """ 98 | return_type = type(count_above(1, 2)) 99 | self.assertEqual(return_type, int, "count_above should return type " + 100 | "int, but instead returned type {}.".format( 101 | return_type)) 102 | 103 | return_type = type(count_above([1], 2)) 104 | self.assertEqual(return_type, int, "count_above should return type " + 105 | "int, but instead returned type {}.".format( 106 | return_type)) 107 | 108 | def test_smaller_integer(self): 109 | """ 110 | Test count_above on an integer <= n. 111 | """ 112 | self.assertEqual(count_above(2, 2), 0, "count_above should return 0 " + 113 | "when passed an integer <= n.") 114 | 115 | def test_larger_integer(self): 116 | """ 117 | Test count_above on an integer > n 118 | """ 119 | self.assertEqual(count_above(2, 1), 1, "count_above should return 1 " + 120 | "when given an integer > n.") 121 | 122 | def test_one_nested_sublist(self): 123 | """ 124 | Test count_above on a list with only one sublist in it. 125 | """ 126 | self.assertEqual(count_above([[2]], 1), 1, "count_above should return" + 127 | " the number of integers > n in nested sublists.") 128 | 129 | def test_one_nested_sublist_and_integers(self): 130 | """ 131 | Test count_above on a list with at most one level of nested sublists in 132 | it mixed with integers. 133 | """ 134 | self.assertEqual(count_above([[2], 3, [4]], 2), 2, 135 | "count_above should return the number of integers " + 136 | "> n in nested sublists and in the list passed " + 137 | "in.") 138 | 139 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 140 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 141 | max_size = 20), 142 | integers(min_value = -1)) 143 | def test_count_even(self, list_values, list_indices, n): 144 | """ 145 | Test the submitted count_even against a randomly generated list. 146 | """ 147 | 148 | # Gather all of the even values 149 | expected = 0 150 | for i in list_values: 151 | if i > n: 152 | expected += 1 153 | 154 | # Create up to 2 levels of nesting for the values in list_values, where 155 | # the indices we turn into sublists are contained in 156 | # nesting_indices_1 and nesting_indices_2 157 | nesting_indices_1 = list_indices[:len(list_indices)//2] 158 | nesting_indices_2 = list_indices[len(list_indices)//2:] 159 | nesting_indices_1.sort() 160 | nesting_indices_2.sort() 161 | 162 | obj = create_nested_list(list_values, [nesting_indices_1, 163 | nesting_indices_2]) 164 | 165 | # Ignoring the order of the values, in case students have an 166 | # out-of-order version for some reason. 167 | actual = count_above(obj, n) 168 | 169 | self.assertEqual(actual, expected, 170 | ("Using count_above with n = {} on {} returned" + 171 | " {} instead of {}.").format(n, obj, actual, expected) 172 | ) 173 | 174 | 175 | if __name__ == "__main__": 176 | unittest.main() 177 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_above_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | count above unit tests 3 | """ 4 | import unittest 5 | from typing import List 6 | from hypothesis import given 7 | from hypothesis.strategies import integers 8 | from hypothesis.strategies import lists 9 | from recursion_exercise import count_above 10 | 11 | 12 | def create_nested_list(list_values: list, nested_index_sets: List[List[int]]) -> list: 13 | """ 14 | Create nested lists from values in list_values and indices in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 25 | [[0, 1], 2, [3], 4] 26 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 27 | [[[0, 1], 2], 3, 4] 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 29 | [[[0, 1], 2, [3]], 4] 30 | """ 31 | 32 | nested_list_values = [] 33 | 34 | list_to_add_to = nested_list_values 35 | list_to_use = list_values 36 | 37 | sublist = [] 38 | finished_forming_sublist = True 39 | 40 | return_list = [] 41 | 42 | for n in range(len(nested_index_sets)): 43 | nested_indices = nested_index_sets[n] 44 | 45 | if n == len(nested_index_sets) - 1: 46 | list_to_add_to = return_list 47 | 48 | for i in range(len(list_to_use)): 49 | if nested_indices: 50 | if i == nested_indices[0]: 51 | nested_indices.pop(0) 52 | finished_forming_sublist = not finished_forming_sublist 53 | 54 | sublist.append(list_to_use[i]) 55 | 56 | # Add the formed sublist into nested_list_values 57 | if finished_forming_sublist: 58 | list_to_add_to.append(sublist) 59 | sublist = [] 60 | 61 | if nested_indices and nested_indices[0] == i: 62 | finished_forming_sublist = True 63 | list_to_add_to.append(sublist) 64 | sublist = [] 65 | while nested_indices and nested_indices[0] == i: 66 | nested_indices.pop(0) 67 | else: 68 | if not finished_forming_sublist: 69 | sublist.append(list_to_use[i]) 70 | else: 71 | # We're not forming a sublist at the moment, so 72 | # append to nested_list_values. 73 | list_to_add_to.append(list_to_use[i]) 74 | else: 75 | if not finished_forming_sublist: 76 | list_to_add_to.append(sublist) 77 | sublist = [] 78 | finished_forming_sublist = True 79 | 80 | list_to_add_to.append(list_to_use[i]) 81 | 82 | if not finished_forming_sublist: 83 | list_to_add_to.append(sublist) 84 | sublist = [] 85 | finished_forming_sublist = True 86 | 87 | list_to_use = list_to_add_to 88 | list_to_add_to = [] 89 | 90 | return return_list 91 | 92 | 93 | class CountAboveTests(unittest.TestCase): 94 | def test_returns_int(self): 95 | """ 96 | Test count_above to make sure it returns an int. 97 | """ 98 | return_type = type(count_above(1, 2)) 99 | self.assertEqual(return_type, int, "count_above should return type " + 100 | "int, but instead returned type {}.".format( 101 | return_type)) 102 | 103 | return_type = type(count_above([1], 2)) 104 | self.assertEqual(return_type, int, "count_above should return type " + 105 | "int, but instead returned type {}.".format( 106 | return_type)) 107 | 108 | def test_smaller_integer(self): 109 | """ 110 | Test count_above on an integer <= n. 111 | """ 112 | self.assertEqual(count_above(2, 2), 0, "count_above should return 0 " + 113 | "when passed an integer <= n.") 114 | 115 | def test_larger_integer(self): 116 | """ 117 | Test count_above on an integer > n 118 | """ 119 | self.assertEqual(count_above(2, 1), 1, "count_above should return 1 " + 120 | "when given an integer > n.") 121 | 122 | def test_one_nested_sublist(self): 123 | """ 124 | Test count_above on a list with only one sublist in it. 125 | """ 126 | self.assertEqual(count_above([[2]], 1), 1, "count_above should return" + 127 | " the number of integers > n in nested sublists.") 128 | 129 | def test_one_nested_sublist_and_integers(self): 130 | """ 131 | Test count_above on a list with at most one level of nested sublists in 132 | it mixed with integers. 133 | """ 134 | self.assertEqual(count_above([[2], 3, [4]], 2), 2, 135 | "count_above should return the number of integers " + 136 | "> n in nested sublists and in the list passed " + 137 | "in.") 138 | 139 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 140 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 141 | max_size = 20), 142 | integers(min_value = -1)) 143 | def test_count_even(self, list_values, list_indices, n): 144 | """ 145 | Test the submitted count_even against a randomly generated list. 146 | """ 147 | 148 | # Gather all of the even values 149 | expected = 0 150 | for i in list_values: 151 | if i > n: 152 | expected += 1 153 | 154 | # Create up to 2 levels of nesting for the values in list_values, where 155 | # the indices we turn into sublists are contained in 156 | # nesting_indices_1 and nesting_indices_2 157 | nesting_indices_1 = list_indices[:len(list_indices)//2] 158 | nesting_indices_2 = list_indices[len(list_indices)//2:] 159 | nesting_indices_1.sort() 160 | nesting_indices_2.sort() 161 | 162 | obj = create_nested_list(list_values, [nesting_indices_1, 163 | nesting_indices_2]) 164 | 165 | # Ignoring the order of the values, in case students have an 166 | # out-of-order version for some reason. 167 | actual = count_above(obj, n) 168 | 169 | self.assertEqual(actual, expected, 170 | ("Using count_above with n = {} on {} returned" + 171 | " {} instead of {}.").format(n, obj, actual, expected) 172 | ) 173 | 174 | 175 | if __name__ == "__main__": 176 | unittest.main() 177 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_even_ex5.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for count_even 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from ex5 import count_even 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 29 | [[0, 1], 2, [3], 4] 30 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 31 | [[[0, 1], 2], 3, 4] 32 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 33 | [[[0, 1], 2, [3]], 4] 34 | """ 35 | 36 | nested_list_values = [] 37 | 38 | list_to_add_to = nested_list_values 39 | list_to_use = list_values 40 | 41 | sublist = [] 42 | finished_forming_sublist = True 43 | 44 | return_list = [] 45 | 46 | for n in range(len(nested_index_sets)): 47 | nested_indices = nested_index_sets[n] 48 | 49 | if n == len(nested_index_sets) - 1: 50 | list_to_add_to = return_list 51 | 52 | for i in range(len(list_to_use)): 53 | if nested_indices: 54 | if i == nested_indices[0]: 55 | nested_indices.pop(0) 56 | finished_forming_sublist = not finished_forming_sublist 57 | 58 | sublist.append(list_to_use[i]) 59 | 60 | # Add the formed sublist into nested_list_values 61 | if finished_forming_sublist: 62 | list_to_add_to.append(sublist) 63 | sublist = [] 64 | 65 | if nested_indices and nested_indices[0] == i: 66 | finished_forming_sublist = True 67 | list_to_add_to.append(sublist) 68 | sublist = [] 69 | while nested_indices and nested_indices[0] == i: 70 | nested_indices.pop(0) 71 | else: 72 | if not finished_forming_sublist: 73 | sublist.append(list_to_use[i]) 74 | else: 75 | # We're not forming a sublist at the moment, so 76 | # append to nested_list_values. 77 | list_to_add_to.append(list_to_use[i]) 78 | else: 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_add_to.append(list_to_use[i]) 85 | 86 | if not finished_forming_sublist: 87 | list_to_add_to.append(sublist) 88 | sublist = [] 89 | finished_forming_sublist = True 90 | 91 | list_to_use = list_to_add_to 92 | list_to_add_to = [] 93 | 94 | return return_list 95 | 96 | class CountEvenTests(unittest.TestCase): 97 | def test_returns_int(self): 98 | """ 99 | Test list_even to make sure it returns an int. 100 | """ 101 | return_type = type(count_even(1)) 102 | self.assertEqual(return_type, int, "count_even should return type " + 103 | "int, but instead returned type {}.".format( 104 | return_type)) 105 | 106 | return_type = type(count_even([1])) 107 | self.assertEqual(return_type, int, "count_even should return type " + 108 | "int, but instead returned type {}.".format( 109 | return_type)) 110 | 111 | def test_odd_integer(self): 112 | """ 113 | Test count_even on an odd integer. 114 | """ 115 | self.assertEqual(count_even(1), 0, "count_even should return 0 " + 116 | "when passed an odd integer.") 117 | 118 | def test_even_integer(self): 119 | """ 120 | Test count_even on an even integer. 121 | """ 122 | self.assertEqual(count_even(2), 1, "count_even should return 1 " + 123 | "when given an even integer.") 124 | 125 | def test_one_nested_sublist(self): 126 | """ 127 | Test count_even on a list with only one sublist in it. 128 | """ 129 | self.assertEqual(count_even([[2]]), 1, "count_even should return " + 130 | "the number of even integers in nested sublists.") 131 | 132 | 133 | def test_one_nested_sublist_and_integers(self): 134 | """ 135 | Test count_even on a list with at most one level of nested sublists in 136 | it mixed with integers. 137 | """ 138 | self.assertEqual(count_even([[2], 3, [4]]), 2, 139 | "count_even should return the number of even " + 140 | "integers in nested sublists and in the list passed " + 141 | "in.") 142 | 143 | 144 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 145 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 146 | max_size = 20)) 147 | def test_count_even(self, list_values, list_indices): 148 | """ 149 | Test the submitted count_even against a randomly generated list. 150 | """ 151 | 152 | # Gather all of the even values 153 | expected = 0 154 | for n in list_values: 155 | if n % 2 == 0: 156 | expected += 1 157 | 158 | # Create up to 2 levels of nesting for the values in list_values, where 159 | # the indices we turn into sublists are contained in 160 | # nesting_indices_1 and nesting_indices_2 161 | nesting_indices_1 = list_indices[:len(list_indices)//2] 162 | nesting_indices_2 = list_indices[len(list_indices)//2:] 163 | nesting_indices_1.sort() 164 | nesting_indices_2.sort() 165 | 166 | obj = create_nested_list(list_values, [nesting_indices_1, 167 | nesting_indices_2]) 168 | 169 | # Ignoring the order of the values, in case students have an 170 | # out-of-order version for some reason. 171 | actual = count_even(obj) 172 | 173 | self.assertEqual(actual, expected, 174 | ("Using count_even on {} returned" + 175 | " {} instead of {}.").format(obj, actual, expected)) 176 | 177 | if __name__ == "__main__": 178 | unittest.main() 179 | -------------------------------------------------------------------------------- /Labs/Lab 5/test_count_even_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | unit tests for count_even 3 | """ 4 | import unittest 5 | from hypothesis import given 6 | from hypothesis.strategies import integers 7 | from hypothesis.strategies import lists 8 | from recursion_exercise import count_even 9 | 10 | 11 | def create_nested_list(list_values, nested_index_sets): 12 | """ 13 | Create nested lists containing the values in list_values based on the 14 | indices to turn into sublists in nested_index_sets. 15 | 16 | To clarify: Initially, the first two indices in nested_index_sets[0] will 17 | be taken (referred to as 'start' and 'end'), and list_values[start:end] will 18 | be replaced with a sublist containing values from list_values[start:end]. 19 | Once all indices in nested_index_sets[0] are used, the resulting list will 20 | be used and sublists formed using indices in nested_index_sets[1]. 21 | 22 | Precondition: All of the lists in nested_index_sets are sorted. 23 | 24 | @param list list_values: The non-list values in the list to be returned. 25 | @param list[list[int]]: Lists containing the indices to turn into sublists. 26 | @rtype list[obj] 27 | 28 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4]]) 29 | [[0, 1], 2, [3], 4] 30 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2], [0, 2]]) 31 | [[[0, 1], 2], 3, 4] 32 | >>> create_nested_list([0, 1, 2, 3, 4], [[0, 2, 3, 4], [0, 4]]) 33 | [[[0, 1], 2, [3]], 4] 34 | """ 35 | 36 | nested_list_values = [] 37 | 38 | list_to_add_to = nested_list_values 39 | list_to_use = list_values 40 | 41 | sublist = [] 42 | finished_forming_sublist = True 43 | 44 | return_list = [] 45 | 46 | for n in range(len(nested_index_sets)): 47 | nested_indices = nested_index_sets[n] 48 | 49 | if n == len(nested_index_sets) - 1: 50 | list_to_add_to = return_list 51 | 52 | for i in range(len(list_to_use)): 53 | if nested_indices: 54 | if i == nested_indices[0]: 55 | nested_indices.pop(0) 56 | finished_forming_sublist = not finished_forming_sublist 57 | 58 | sublist.append(list_to_use[i]) 59 | 60 | # Add the formed sublist into nested_list_values 61 | if finished_forming_sublist: 62 | list_to_add_to.append(sublist) 63 | sublist = [] 64 | 65 | if nested_indices and nested_indices[0] == i: 66 | finished_forming_sublist = True 67 | list_to_add_to.append(sublist) 68 | sublist = [] 69 | while nested_indices and nested_indices[0] == i: 70 | nested_indices.pop(0) 71 | else: 72 | if not finished_forming_sublist: 73 | sublist.append(list_to_use[i]) 74 | else: 75 | # We're not forming a sublist at the moment, so 76 | # append to nested_list_values. 77 | list_to_add_to.append(list_to_use[i]) 78 | else: 79 | if not finished_forming_sublist: 80 | list_to_add_to.append(sublist) 81 | sublist = [] 82 | finished_forming_sublist = True 83 | 84 | list_to_add_to.append(list_to_use[i]) 85 | 86 | if not finished_forming_sublist: 87 | list_to_add_to.append(sublist) 88 | sublist = [] 89 | finished_forming_sublist = True 90 | 91 | list_to_use = list_to_add_to 92 | list_to_add_to = [] 93 | 94 | return return_list 95 | 96 | class CountEvenTests(unittest.TestCase): 97 | def test_returns_int(self): 98 | """ 99 | Test list_even to make sure it returns an int. 100 | """ 101 | return_type = type(count_even(1)) 102 | self.assertEqual(return_type, int, "count_even should return type " + 103 | "int, but instead returned type {}.".format( 104 | return_type)) 105 | 106 | return_type = type(count_even([1])) 107 | self.assertEqual(return_type, int, "count_even should return type " + 108 | "int, but instead returned type {}.".format( 109 | return_type)) 110 | 111 | def test_odd_integer(self): 112 | """ 113 | Test count_even on an odd integer. 114 | """ 115 | self.assertEqual(count_even(1), 0, "count_even should return 0 " + 116 | "when passed an odd integer.") 117 | 118 | def test_even_integer(self): 119 | """ 120 | Test count_even on an even integer. 121 | """ 122 | self.assertEqual(count_even(2), 1, "count_even should return 1 " + 123 | "when given an even integer.") 124 | 125 | def test_one_nested_sublist(self): 126 | """ 127 | Test count_even on a list with only one sublist in it. 128 | """ 129 | self.assertEqual(count_even([[2]]), 1, "count_even should return " + 130 | "the number of even integers in nested sublists.") 131 | 132 | 133 | def test_one_nested_sublist_and_integers(self): 134 | """ 135 | Test count_even on a list with at most one level of nested sublists in 136 | it mixed with integers. 137 | """ 138 | self.assertEqual(count_even([[2], 3, [4]]), 2, 139 | "count_even should return the number of even " + 140 | "integers in nested sublists and in the list passed " + 141 | "in.") 142 | 143 | 144 | @given(lists(integers(min_value = 0, max_value = 100), max_size = 20), 145 | lists(integers(min_value = 0, max_value = 20), min_size = 1, 146 | max_size = 20)) 147 | def test_count_even(self, list_values, list_indices): 148 | """ 149 | Test the submitted count_even against a randomly generated list. 150 | """ 151 | 152 | # Gather all of the even values 153 | expected = 0 154 | for n in list_values: 155 | if n % 2 == 0: 156 | expected += 1 157 | 158 | # Create up to 2 levels of nesting for the values in list_values, where 159 | # the indices we turn into sublists are contained in 160 | # nesting_indices_1 and nesting_indices_2 161 | nesting_indices_1 = list_indices[:len(list_indices)//2] 162 | nesting_indices_2 = list_indices[len(list_indices)//2:] 163 | nesting_indices_1.sort() 164 | nesting_indices_2.sort() 165 | 166 | obj = create_nested_list(list_values, [nesting_indices_1, 167 | nesting_indices_2]) 168 | 169 | # Ignoring the order of the values, in case students have an 170 | # out-of-order version for some reason. 171 | actual = count_even(obj) 172 | 173 | self.assertEqual(actual, expected, 174 | ("Using count_even on {} returned" + 175 | " {} instead of {}.").format(obj, actual, expected)) 176 | 177 | if __name__ == "__main__": 178 | unittest.main() 179 | -------------------------------------------------------------------------------- /Assignments/Assignment 1/chopstick_state.py: -------------------------------------------------------------------------------- 1 | """ 2 | subclass of State: ChopstickState 3 | """ 4 | from typing import Any, List 5 | from state import State 6 | 7 | 8 | class ChopstickState(State): 9 | """ 10 | subclass of State 11 | """ 12 | current_list: List 13 | 14 | def __init__(self, is_p1_turn: bool) -> None: 15 | """ 16 | initialize a new subclass of state: ChopstickState 17 | 18 | >>> is_p1_turn = True 19 | >>> c1 = ChopstickState(is_p1_turn) 20 | >>> c1.is_p1_turn 21 | True 22 | >>> c1.is_game_over 23 | False 24 | >>> c1.current_list 25 | [1, 1, 1, 1] 26 | """ 27 | State.__init__(self, is_p1_turn) 28 | self.current_list = [1, 1, 1, 1] 29 | 30 | def __eq__(self, other: Any) -> bool: 31 | """ 32 | return whether self is equivalent to other 33 | 34 | >>> is_p1_turn = True 35 | >>> c1 = ChopstickState(is_p1_turn) 36 | >>> c2 = ChopstickState(False) 37 | >>> c3 = 3 38 | >>> c4 = 'Any' 39 | >>> c5 = ChopstickState(True) 40 | >>> c1 == c2 41 | False 42 | >>> c1 == c3 43 | False 44 | >>> c1 == c4 45 | False 46 | >>> c1 == c5 47 | True 48 | """ 49 | return (State.__eq__(self, other) 50 | and self.current_list == other.current_list) 51 | 52 | def __str__(self) -> str: 53 | """ 54 | return a str representation of game state: ChopstickState 55 | 56 | >>> is_p1_turn = True 57 | >>> c1 = ChopstickState(is_p1_turn) 58 | >>> print(c1) 59 | Player 1: 1 - 1; Player 2: 1 - 1 60 | """ 61 | return "Player 1: {} - {}; Player 2: {} - {}".\ 62 | format(self.current_list[0], self.current_list[1], 63 | self.current_list[2], self.current_list[3]) 64 | 65 | def get_possible_moves(self) -> List: 66 | """ 67 | return a list containing possible moves for the game 68 | 69 | >>> is_p1_turn = True 70 | >>> c1 = ChopstickState(is_p1_turn) 71 | >>> c1.get_possible_moves() 72 | ['ll', 'lr', 'rl', 'rr'] 73 | >>> c1.current_list[1] = 0 74 | >>> c1.get_possible_moves() 75 | ['ll', 'lr'] 76 | """ 77 | p1_left, p1_right = self.current_list[0], self.current_list[1] 78 | p1_list = [p1_left, p1_right] 79 | p2_left, p2_right = self.current_list[2], self.current_list[3] 80 | p2_list = [p2_left, p2_right] 81 | possible_moves = [] 82 | if self.is_p1_turn: 83 | if p1_list[0] != 0 and p2_list[0] != 0: 84 | possible_moves.append('ll') 85 | if p1_list[0] != 0 and p2_list[1] != 0: 86 | possible_moves.append('lr') 87 | if p1_list[1] != 0 and p2_list[0] != 0: 88 | possible_moves.append('rl') 89 | if p1_list[1] != 0 and p2_list[1] != 0: 90 | possible_moves.append('rr') 91 | return possible_moves 92 | else: 93 | if p2_list[0] != 0 and p1_list[0] != 0: 94 | possible_moves.append('ll') 95 | if p2_list[0] != 0 and p1_list[1] != 0: 96 | possible_moves.append('lr') 97 | if p2_list[1] != 0 and p1_list[0] != 0: 98 | possible_moves.append('rl') 99 | if p2_list[1] != 0 and p1_list[1] != 0: 100 | possible_moves.append('rr') 101 | return possible_moves 102 | 103 | def is_valid_move(self, move_to_take: Any) -> bool: 104 | """ 105 | return whether a move_to_take is valid for the game 106 | 107 | >>> is_p1_turn = True 108 | >>> c1 = ChopstickState(is_p1_turn) 109 | >>> c1.current_list[1] = 0 110 | >>> c1.is_valid_move(5) 111 | False 112 | >>> c1.is_valid_move('Any') 113 | False 114 | >>> c1.is_valid_move('rl') 115 | False 116 | >>> c1.is_valid_move('ll') 117 | True 118 | """ 119 | return move_to_take in self.get_possible_moves() 120 | 121 | def get_current_player_name(self) -> str: 122 | """ 123 | get current player name 124 | 125 | >>> is_p1_turn = True 126 | >>> c1 = ChopstickState(is_p1_turn) 127 | >>> c1.get_current_player_name() 128 | 'p1' 129 | >>> c1.is_p1_turn = False 130 | >>> c1.get_current_player_name() 131 | 'p2' 132 | >>> c2 = ChopstickState(False) 133 | >>> c2.get_current_player_name() 134 | 'p2' 135 | """ 136 | return State.get_current_player_name(self) 137 | 138 | def make_move(self, move_to_make: str) -> 'ChopstickState': 139 | """ 140 | apply the move_to_make and return a new_state 141 | 142 | >>> is_p1_turn = True 143 | >>> c1 = ChopstickState(is_p1_turn) 144 | >>> c2 = c1.make_move('ll') 145 | >>> c2.current_list 146 | [1, 1, 2, 1] 147 | >>> c2.get_current_player_name() 148 | 'p2' 149 | >>> c2.is_game_over 150 | False 151 | """ 152 | current_player = self.is_p1_turn 153 | new_list = [item for item in self.current_list] 154 | new_is_game_over = self.is_game_over 155 | if current_player: 156 | if move_to_make == 'll': 157 | new_list[2] = new_list[0] + new_list[2] 158 | elif move_to_make == 'lr': 159 | new_list[3] = new_list[0] + new_list[3] 160 | elif move_to_make == 'rl': 161 | new_list[2] = new_list[1] + new_list[2] 162 | elif move_to_make == 'rr': 163 | new_list[3] = new_list[1] + new_list[3] 164 | if new_list[2] >= 5: 165 | a = new_list[2] 166 | new_list[2] = a % 5 167 | if new_list[3] >= 5: 168 | b = new_list[3] 169 | new_list[3] = b % 5 170 | else: 171 | if move_to_make == 'll': 172 | new_list[0] = new_list[2] + new_list[0] 173 | elif move_to_make == 'lr': 174 | new_list[1] = new_list[2] + new_list[1] 175 | elif move_to_make == 'rl': 176 | new_list[0] = new_list[3] + new_list[0] 177 | elif move_to_make == 'rr': 178 | new_list[1] = new_list[3] + new_list[1] 179 | if new_list[0] >= 5: 180 | c = new_list[0] 181 | new_list[0] = c % 5 182 | if new_list[1] >= 5: 183 | d = new_list[1] 184 | new_list[1] = d % 5 185 | if (new_list[0] == 0 and new_list[1] == 0) or (new_list[2] == 0 and 186 | new_list[3] == 0): 187 | new_is_game_over = True 188 | else: 189 | if current_player: 190 | current_player = False 191 | else: 192 | current_player = True 193 | new_state = ChopstickState(current_player) 194 | new_state.current_list = [item for item in new_list] 195 | new_state.is_game_over = new_is_game_over 196 | return new_state 197 | 198 | 199 | if __name__ == '__main__': 200 | import python_ta 201 | python_ta.check_all(config="a1_pyta.txt") 202 | --------------------------------------------------------------------------------