From 44a8bdd866fd895a7ce0cd8c09f94980e1d4887a Mon Sep 17 00:00:00 2001 From: Aleksandr Balakiriev Date: Sun, 22 Jun 2014 19:35:16 +0200 Subject: [PATCH] Week-0 --- Week-0/game-2048.py | 360 +++++++++++++++++++++++++++++++++++++++++++ Week-0/hw-0.txt | 131 ++++++++++++++++ Week-0/hw-0.txt~ | 61 ++++++++ Week-0/mangala.py | 56 +++++++ Week-0/mangala.py~ | 0 Week-0/testsuite.py | 41 +++++ Week-0/testsuite.py~ | 0 7 files changed, 649 insertions(+) create mode 100644 Week-0/game-2048.py create mode 100644 Week-0/hw-0.txt create mode 100644 Week-0/hw-0.txt~ create mode 100644 Week-0/mangala.py create mode 100644 Week-0/mangala.py~ create mode 100644 Week-0/testsuite.py create mode 100644 Week-0/testsuite.py~ diff --git a/Week-0/game-2048.py b/Week-0/game-2048.py new file mode 100644 index 0000000..91387a9 --- /dev/null +++ b/Week-0/game-2048.py @@ -0,0 +1,360 @@ +""" +Clone of 2048 game. +""" + +# import poc_2048_gui +# import poc_simpletest as st +import random + +# Directions, DO NOT MODIFY +UP = 1 +DOWN = 2 +LEFT = 3 +RIGHT = 4 + +# Offsets for computing tile indices in each direction. +# DO NOT MODIFY this dictionary. +OFFSETS = {UP: (1, 0), + DOWN: (-1, 0), + LEFT: (0, 1), + RIGHT: (0, -1)} + + +def merge(line): + """ + Helper function that merges a single row or column in 2048 + """ + # 1. Start with a result list that contains the same number of 0's as the length of the line argument. + result = [0] * len(line) + last_merged = False + + # 2. Iterate over the line input looking for non-zero entries. For each non-zero entry, put the value into the + # next available entry of the result list (starting at position 0). + if len(line) < 2: + return line + + for entry_index in range(0, len(line)): + if line[entry_index] != 0: + # find the start point first + for re_index in range(0, len(result)): + # if it is 0 then can copy safely + if result[re_index] == 0: + result[re_index] = line[entry_index] + last_merged = False + break + # if current is not 0 but the next one is, then need to consider merge + elif result[re_index + 1] == 0: + # current is the same with incoming one, merge + if result[re_index] == line[entry_index] and last_merged is False: + result[re_index] = result[re_index] + line[entry_index] + last_merged = True + break + # else advance to next iter + # if current is not 0 and the next one is not 0, advance to next iter + + return result + + +# line = [2, 0, 2, 2] +# test = st.TestSuite() +# test.run_test(merge(line), [2, 2, 2, 0], "Test Merge") + +# [2, 0, 2, 4] should return [4, 4, 0, 0] +# [0, 0, 2, 2] should return [4, 0, 0, 0] +# [2, 2, 0, 0] should return [4, 0, 0, 0] +# [2, 2, 2, 2] should return [4, 4, 0, 0] +# [8, 16, 16, 8] should return [8, 32, 8, 0] + +# line = [2, 0, 2, 4] +# line_expected = [4, 4, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [0, 0, 2, 2] +# line_expected = [4, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [2, 2, 0, 0] +# line_expected = [4, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [2, 2, 2, 2] +# line_expected = [4, 4, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [8, 16, 16, 8] +# line_expected = [8, 32, 8, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") + +# line = [2, 4, 2, 4] +# line_expected = [2, 4, 2, 4] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [2, 0, 0, 0] +# line_expected = [2, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [0, 2, 0, 0] +# line_expected = [2, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [0, 0, 2, 0] +# line_expected = [2, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [0, 0, 0, 2] +# line_expected = [2, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") +# +# line = [2, 2, 0, 0] +# line_expected = [4, 0, 0, 0] +# test = st.TestSuite() +# test.run_test(merge(line), line_expected, "Test Merge") + +def get_ran_num(up_limit): + """ + randomly pick a row or col number + :param up_limit: limited by current row or col + :return: + """ + num = random.randrange(0, up_limit) + return num + + +def generate_value(): + """ + generate a 2 or 4. with 10% chance of getting a 4 and 90% chance of getting a 2 + :return: + """ + # get the probability + prob = random.random() + + # 10% chance p < 0.1, that's when we return 2 + if prob < 0.1: + return 4 + # otherwise return 2 + else: + return 2 + + +def get_initial_tiles(wid, hei): + """ + get the initial tile dictionary for the defined width and height + :param wid: width + :param hei: height + :return: + """ + ini_tiles = {} + + keys = [UP, DOWN, LEFT, RIGHT] + + # generate initial tiles for UP + for each_key in keys: + tile_ls = [] + if each_key == UP: + for each_value in range(wid): + tile_ls.append((0, each_value)) + elif each_key == DOWN: + for each_value in range(wid): + tile_ls.append((hei - 1, each_value)) + elif each_key == LEFT: + for each_value in range(hei): + tile_ls.append((each_value, 0)) + else: + for each_value in range(hei): + tile_ls.append((each_value, wid - 1)) + + ini_tiles[each_key] = ini_tiles.get(each_key, tile_ls) + + return ini_tiles + + +# test_it = get_ini_tiles(3, 3) +# print test_it + + +class TwentyFortyEight: + """ + Class to run the game logic. + """ + + def __init__(self, grid_height, grid_width): + self.height = grid_height + self.width = grid_width + self.cells = {} + self.avi_cells = [] + self.ini_tiles = get_initial_tiles(self.width, self.height) + self.ini_cells() + + def reset(self): + """ + Reset the game so the grid is empty. + """ + self.avi_cells = [] + for row in range(self.height): + for col in range(self.width): + self.cells[(row, col)] = 0 + self.avi_cells.append((row, col)) + + def ini_cells(self): + """ + Reset the game so the grid is empty. + """ + self.avi_cells = [] + for row in range(self.height): + for col in range(self.width): + self.cells[(row, col)] = self.cells.get((row, col), 0) + self.avi_cells.append((row, col)) + + def __str__(self): + """ + Return a string representation of the grid for debugging. + """ + string = "" + for row in range(self.height): + # literate to 1 element before the end + for col in range(self.width): + # this is the end of the line + if col == self.width - 1: + string += str(self.cells[(row, col)]) + "\n" + # otherwise separated by ", ". so there will be no ", " at the end of each line + else: + string += str(self.cells[(row, col)]) + ", " + + return string + + def get_grid_height(self): + """ + Get the height of the board. + """ + # replace with your code + return self.height + + def get_grid_width(self): + """ + Get the width of the board. + """ + # replace with your code + return self.width + + def move(self, direction): + """ + Move all tiles in the given direction and add + a new tile if any tiles moved. + """ + tile_changed = False + + for each in self.ini_tiles[direction]: + temp_ls = [] + + target_row = each[0] + target_col = each[1] + + # add cells to the list until the index exceeds + while (target_row, target_col) in self.cells: + temp_ls.append(self.cells[(target_row, target_col)]) + target_row += OFFSETS[direction][0] + target_col += OFFSETS[direction][1] + + # merge the line + temp_ls = merge(temp_ls) + + # traverse the cells again + target_row = each[0] + target_col = each[1] + ls_index = 0 + + # add cells to the list until the index exceeds + while (target_row, target_col) in self.cells: + # if the new value is not equal to original value, the tile must have changed + if self.cells[(target_row, target_col)] != temp_ls[ls_index]: + tile_changed = True + + self.cells[(target_row, target_col)] = temp_ls[ls_index] + target_row += OFFSETS[direction][0] + target_col += OFFSETS[direction][1] + ls_index += 1 + + # if tile has changed, and there is at least one avi cell, then must call new_tile + if tile_changed: + self.new_tile() + + def new_tile(self): + """ + Create a new tile in a randomly selected empty + square. The tile should be 2 90% of the time and + 4 10% of the time. + """ + new_row = get_ran_num(self.height) + new_col = get_ran_num(self.width) + + # cannot pick a (row, col) where there is already a tile with valid value + while self.get_tile(new_row, new_col) != 0: + new_row = get_ran_num(self.height) + new_col = get_ran_num(self.width) + + self.cells[(new_row, new_col)] = generate_value() + + def set_tile(self, row, col, value): + """ + Set the tile at position row, col to have the given value. + """ + self.cells[(row, col)] = value + self.avi_cells.remove((row, col)) + + def get_tile(self, row, col): + """ + Return the value of the tile at position row, col. + """ + return self.cells[(row, col)] + + + # test_grid = TwentyFortyEight(4, 4) + # print test_grid + # + # test_grid.set_tile(0, 0, 2) + # test_grid.set_tile(0, 1, 0) + # test_grid.set_tile(0, 2, 0) + # test_grid.set_tile(0, 3, 0) + # test_grid.set_tile(1, 0, 0) + # test_grid.set_tile(1, 1, 2) + # test_grid.set_tile(1, 2, 0) + # test_grid.set_tile(1, 3, 0) + # test_grid.set_tile(2, 0, 0) + # test_grid.set_tile(2, 1, 0) + # test_grid.set_tile(2, 2, 2) + # test_grid.set_tile(2, 3, 0) + # test_grid.set_tile(3, 0, 0) + # test_grid.set_tile(3, 1, 0) + # test_grid.set_tile(3, 2, 0) + # test_grid.set_tile(3, 3, 2) + # + # print test_grid + # + # test_grid.move(UP) + # + # print test_grid + + # test_grid.move(RIGHT) + # + # print test_grid + # + # test_grid.move(RIGHT) + # + # print test_grid + # + # test_grid.reset() + # + # print test_grid + + + # poc_2048_gui.run_gui(TwentyFortyEight(4, 4)) \ No newline at end of file diff --git a/Week-0/hw-0.txt b/Week-0/hw-0.txt new file mode 100644 index 0000000..6a1f1f0 --- /dev/null +++ b/Week-0/hw-0.txt @@ -0,0 +1,131 @@ +1. Enter the type of the Python expression 3.14159 below. Remember that capitalization is important. + - Float + +2. An if statement can have how many elif parts? + - Unlimited, i.e., 0 or more + +3. Consider the following Python code snippet: + def clock_helper(total_seconds): + """ + Helper function for a clock + """ + seconds_in_minute = total_seconds % 60 +print (clock_helper(90)) + +- None + +4. In Python, what character always appears at the end of the line before the start of an indented block of code? +- : + +5. Which of the following expressions returns the last character in the non-empty string my_string? + +- my_string[len(my_string) - 1] +- my_string[-1] + +6. What is the primary difference between a list and a tuple? +- Lists are mutable. Tuples are immutable. + +7. Consider the following snippet of Python code. What is the value of val2[1] after executing this code? + +val1 = [1, 2, 3] +val2 = val1[1:] +val1[2] = 4 +#print val2[1] + +- 3 + +8. Which of the following Python expressions is a valid key in a Python dictionary? +- False, "", 0 + +9. + +def appendsums(lst): + sum = 0 + for i in range(25): + sum = lst[len(lst) -1] + lst[len(lst) -2] + lst[len(lst) -3] + #print sum + lst.append(sum) + return lst + +sum_three = [0, 1, 2] +appendsums(sum_three) +#print sum_three[10] +print sum_three[20] + +- 101902 + +10. + +class BankAccount: + balance = 0 + fee = 0 + def __init__(self, initial_balance): + """Creates an account with the given balance.""" + self.balance = initial_balance + def deposit(self, amount): + """Deposits the amount into the account.""" + self.balance = self.balance + amount + def withdraw(self, amount): + """ + Withdraws the amount from the account. Each withdrawal resulting in a + negative balance also deducts a penalty fee of 5 dollars from the balance. + """ + if self.balance - amount < 0: + self.balance = self.balance - amount -5 + self.fee = self.fee + 5 + else: + self.balance = self.balance - amount + def get_balance(self): + """Returns the current balance in the account.""" + return self.balance + def get_fees(self): + """Returns the total fees ever deducted from the account.""" + return self.fee +my_account = BankAccount(10) +my_account.withdraw(5) +my_account.deposit(10) +my_account.withdraw(5) +my_account.withdraw(15) +my_account.deposit(20) +my_account.withdraw(5) +my_account.deposit(10) +my_account.deposit(20) +my_account.withdraw(15) +my_account.deposit(30) +my_account.withdraw(10) +my_account.withdraw(15) +my_account.deposit(10) +my_account.withdraw(50) +my_account.deposit(30) +my_account.withdraw(15) +my_account.deposit(10) +my_account.withdraw(5) +my_account.deposit(20) +my_account.withdraw(15) +my_account.deposit(10) +my_account.deposit(30) +my_account.withdraw(25) +my_account.withdraw(5) +my_account.deposit(10) +my_account.withdraw(15) +my_account.deposit(10) +my_account.withdraw(10) +my_account.withdraw(15) +my_account.deposit(10) +my_account.deposit(30) +my_account.withdraw(25) +my_account.withdraw(10) +my_account.deposit(20) +my_account.deposit(10) +my_account.withdraw(5) +my_account.withdraw(15) +my_account.deposit(10) +my_account.withdraw(5) +my_account.withdraw(15) +my_account.deposit(10) +my_account.withdraw(5) +print (my_account.get_balance(), my_account.get_fees()) + +- (-60, 75) + + diff --git a/Week-0/hw-0.txt~ b/Week-0/hw-0.txt~ new file mode 100644 index 0000000..036dcfa --- /dev/null +++ b/Week-0/hw-0.txt~ @@ -0,0 +1,61 @@ +1. Enter the type of the Python expression 3.14159 below. Remember that capitalization is important. + - Float + +2. An if statement can have how many elif parts? + - Unlimited, i.e., 0 or more + +3. Consider the following Python code snippet: + def clock_helper(total_seconds): + """ + Helper function for a clock + """ + seconds_in_minute = total_seconds % 60 +print (clock_helper(90)) + +- None + +4. In Python, what character always appears at the end of the line before the start of an indented block of code? +- : + +5. Which of the following expressions returns the last character in the non-empty string my_string? + +- my_string[len(my_string) - 1] +- my_string[-1] + +6. What is the primary difference between a list and a tuple? +- Lists are mutable. Tuples are immutable. + +7. Consider the following snippet of Python code. What is the value of val2[1] after executing this code? + +val1 = [1, 2, 3] +val2 = val1[1:] +val1[2] = 4 +#print val2[1] + +- 3 + +8. Which of the following Python expressions is a valid key in a Python dictionary? +- False, "", 0 + +9. + +def appendsums(lst): + sum = 0 + for i in range(25): + sum = lst[len(lst) -1] + lst[len(lst) -2] + lst[len(lst) -3] + #print sum + lst.append(sum) + return lst + +sum_three = [0, 1, 2] +appendsums(sum_three) +#print sum_three[10] +print sum_three[20] + +- 101902 + +10. + + + + diff --git a/Week-0/mangala.py b/Week-0/mangala.py new file mode 100644 index 0000000..0149398 --- /dev/null +++ b/Week-0/mangala.py @@ -0,0 +1,56 @@ +lass SolitaireMancala: + + def __init__(self): + self.board = [0] + + def set_board(self, configuration): + self.board = list(configuration) + return self + + def get_num_seeds(self, house_num): + return self.board[house_num] + + def is_legal_move(self, house_num): + if house_num == 0: + return False + return self.board[house_num] == house_num + + def apply_move(self, house_num): + if not self.is_legal_move(house_num): + return self + for i in range(house_num): + self.board[i] += 1 + self.board[house_num] = 0 + return self + + def choose_move(self): + for house_num in range(len(self.board)): + if self.is_legal_move(house_num): + return house_num + return 0 + + def is_game_won(self): + return sum(self.board[1:]) == 0 + + def plan_moves(self): + moves = [] + backup_board = list(self.board) + while True: + house_num = self.choose_move() + if house_num == 0: + break + else: + moves.append(house_num) + self.apply_move(house_num) + self.set_board(backup_board) + return moves + + def __str__(self): + reversed_board = [self.board[i] for i in range(len(self.board)-1, -1, -1)] + return str(reversed_board) + +# import poc_mancala_testsuite +# poc_mancala_testsuite.run_test(SolitaireMancala) + +# import poc_mancala_gui +# poc_mancala_gui.run_gui(SolitaireMancala()) diff --git a/Week-0/mangala.py~ b/Week-0/mangala.py~ new file mode 100644 index 0000000..e69de29 diff --git a/Week-0/testsuite.py b/Week-0/testsuite.py new file mode 100644 index 0000000..95112f9 --- /dev/null +++ b/Week-0/testsuite.py @@ -0,0 +1,41 @@ +""" +Lightweight testing class inspired by unittest from Pyunit +https://docs.python.org/2/library/unittest.html +Note that code is designed to be much simpler than unittest +and does NOT replicate uinittest functionality +""" + + +class TestSuite: + """ + Create a suite of tests similar to unittest + """ + + def __init__(self): + """ + Creates a test suite object + """ + self.total_tests = 0 + self.failures = 0 + + def run_test(self, computed, expected, message = ""): + """ + Compare computed and expected expressions as strings + If not equal, print message, computed, expected + """ + self.total_tests += 1 + if computed != expected: + print message + " failed." + " Computed: " + str(computed) + \ + " Expected: " + str(expected) + self.failures += 1 + else: + print message + " succeeded." + " Computed: " + str(computed) + \ + " Expected: " + str(expected) + + def report_results(self): + """" + Report back summary of successes and failures + from run_test() + """ + print "Ran " + str(self.total_tests) + " tests. " \ + + str(self.failures) + " failures." diff --git a/Week-0/testsuite.py~ b/Week-0/testsuite.py~ new file mode 100644 index 0000000..e69de29