├── calculator ├── __init__.py ├── README.md ├── magic_calc.py └── basic_calc.py ├── Mastermind ├── .idea │ ├── .name │ └── .gitignore ├── app │ ├── consts.py │ ├── main.py │ └── game_logic │ │ ├── player.py │ │ └── checkers.py └── tests │ └── game_locig │ └── test_check_player_guess_with_duplicates.py ├── .gitignore ├── .DS_Store ├── ProfilingExample ├── .idea │ └── .gitignore ├── main.py └── rate_tweets.py ├── code_jam └── 2018 │ ├── test_files │ └── senate_evacuation.txt │ ├── output_files │ └── senate_evacuation.txt │ └── senate_evacuation.py ├── bit_manipulation ├── README.md ├── check_bit_set.py ├── check_all_bits_set.py ├── find_single_number.py ├── get_revers_bits.py └── get_all_powers_of_two.py ├── hello_world ├── README.md ├── hello_world_go.go ├── hello_world_html.html ├── hello_world_python_rec.py ├── hello_world_python.py ├── hello_world_scala.scala └── hello_world_elixir.exs ├── dot_files ├── .repo_switch ├── git_hooks │ ├── pre-commit │ └── pre-merge-commit ├── git_wrapper └── .gitconfig ├── README.md ├── multiply.py ├── seven-boom ├── seven_boom_original.py └── seven_boom_alt.py ├── recursion ├── bad_fib.py └── memoizedFib.py ├── fibsum.py ├── last_word.py ├── copy_bits.py ├── nextBigger.py ├── find_median_of_three.py ├── power_set.py ├── queues ├── indexed_queue.py └── linked_list_queue.py ├── palindrome.py ├── longest_sub_sequence_length.py ├── approximate_sort.py ├── anagrams.py ├── descriptive_numbers.py ├── jump_game.py ├── four_in_a_row ├── logic.py ├── board.py └── tests.py ├── first_ancestor.py ├── stones.py ├── merge_meetings.py ├── recur_multiply.py ├── longest_k_unique.py ├── file_search.py ├── island_journey.py ├── sudoku_checker.py ├── sudoku_checker_better.py ├── ice_cream.py ├── matrix_sums.py ├── maze.py ├── paint_and_fill.py ├── coins_and_weights.py └── data.txt /calculator/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Mastermind/.idea/.name: -------------------------------------------------------------------------------- 1 | consts.py -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.xml 3 | *.iml 4 | *.pyc 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgershovitz/maya_solves/HEAD/.DS_Store -------------------------------------------------------------------------------- /Mastermind/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /ProfilingExample/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /code_jam/2018/test_files/senate_evacuation.txt: -------------------------------------------------------------------------------- 1 | 6 2 | 2 3 | 2 2 4 | 3 5 | 3 2 2 6 | 3 7 | 1 1 2 8 | 3 9 | 2 3 1 10 | 2 11 | 1 1 12 | 10 13 | 1 1 1 1 1 5 -------------------------------------------------------------------------------- /bit_manipulation/README.md: -------------------------------------------------------------------------------- 1 | A collection of simple bit manipulation exercises in Python. 2 | 3 | Related blog post - https://algoritmim.co.il/2019/07/25/or-xor-and-shift/ -------------------------------------------------------------------------------- /hello_world/README.md: -------------------------------------------------------------------------------- 1 | A collection of simple hello_world implementations in various languages. 2 | 3 | Related blog posts - https://algoritmim.co.il/tag/hello_world/ 4 | -------------------------------------------------------------------------------- /code_jam/2018/output_files/senate_evacuation.txt: -------------------------------------------------------------------------------- 1 | Case #1: AB AB 2 | Case #2: A A B C A BC 3 | Case #3: C A BC 4 | Case #4: B A B A BC 5 | Case #5: AB 6 | Case #6: F F F F A B C D EF 7 | -------------------------------------------------------------------------------- /hello_world/hello_world_go.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | space := "" 7 | for _, c := range "Hello World" { 8 | fmt.Println(space + string(c)) 9 | space += " " 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /hello_world/hello_world_html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
 4 | H
 5 |  e
 6 |   l
 7 |    l
 8 |     o
 9 | 
10 |       W
11 |        o
12 |         r
13 |          l
14 |           d
15 | 
16 | 17 | 18 | -------------------------------------------------------------------------------- /dot_files/.repo_switch: -------------------------------------------------------------------------------- 1 | function repo { 2 | source ~/virtual_envs/$1/bin/activate; 3 | cd ~/git_repositories/$1 4 | } 5 | 6 | function _repo { 7 | _arguments "1: :($(ls ~/git_repositories))" 8 | } 9 | 10 | compdef _repo repo 11 | -------------------------------------------------------------------------------- /hello_world/hello_world_python_rec.py: -------------------------------------------------------------------------------- 1 | def print_diag(spaces, word): 2 | if len(word) > 0: 3 | print(spaces + word[0]) 4 | print_diag(spaces + " ", word[1:]) 5 | 6 | 7 | if __name__ == '__main__': 8 | print_diag("", "Hello World!") 9 | -------------------------------------------------------------------------------- /hello_world/hello_world_python.py: -------------------------------------------------------------------------------- 1 | def hello_world(): 2 | space_counter = 0 3 | s = "Hello World" 4 | for c in s: 5 | print(" " * space_counter + c) 6 | space_counter += 1 7 | 8 | 9 | if __name__ == '__main__': 10 | hello_world() -------------------------------------------------------------------------------- /hello_world/hello_world_scala.scala: -------------------------------------------------------------------------------- 1 | def printDiag(spaces: String, word: String): Unit = { 2 | if (!word.isEmpty) { 3 | Console.println(spaces + word.head) 4 | printDiag(spaces.concat(" "), word.tail) 5 | } 6 | } 7 | 8 | printDiag("", "Hello World!") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # maya_solves 2 | Solutions to programming problems 3 | 4 | This repository holds solutions and tests to programming problems I solved practicing for job interviews! 5 | 6 | Full written steps to solutions (in hebrew) can be found here - 7 | https://algoritmim.co.il 8 | 9 | Enjoy! 10 | -------------------------------------------------------------------------------- /hello_world/hello_world_elixir.exs: -------------------------------------------------------------------------------- 1 | "Hello World" 2 | |> String.graphemes 3 | |> Enum.map(fn char -> char <> "\n" end) 4 | |> Enum.reduce( 5 | { "", "" }, 6 | fn next_char, { spaces, text } -> 7 | { spaces <> " ", text <> spaces <> next_char } 8 | end 9 | ) 10 | |> elem(1) 11 | |> IO.puts 12 | -------------------------------------------------------------------------------- /dot_files/git_hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Related blog post (in Hebrew) - https://algoritmim.co.il/2019/12/18/git-me-baby-one-more-time 4 | 5 | if git diff --cached | grep '^[+d].*NO_COMMIT'; then 6 | echo "Can't commit file with NO_COMMIT comment, remove the debug code and try again" 7 | exit 1 8 | fi -------------------------------------------------------------------------------- /multiply.py: -------------------------------------------------------------------------------- 1 | # Related blog post - 2 | 3 | 4 | def multiply(x,y): 5 | return 1*x-y 6 | 7 | def run_tests(): 8 | assert multiply(5,5) == 25 9 | assert multiply(0,5) == 0 10 | assert multiply(1,5) == 5 11 | assert multiply(-5,5) == -25 12 | assert multiply(0.5,5) == 2.5 13 | 14 | if __name__ == '__main__': 15 | run_tests() 16 | -------------------------------------------------------------------------------- /Mastermind/app/consts.py: -------------------------------------------------------------------------------- 1 | COLORS = ["red", "blue", "green", "purple", "orange", "yellow"] 2 | COLORS_DICT = {color[0]: color for color in COLORS} 3 | CODE_LENGTH = 2 4 | TOTAL_ROUNDS = 12 5 | 6 | USER_INPUT_PROMPT = "Please enter your next guess. (r=red b=blue g=green p=purple o=orange y=yellow\n" 7 | USER_SCORE = "Bul: {}, Pgia: {}\n" 8 | USER_WON = "You Win!" 9 | USER_LOST = "You Lose!" 10 | 11 | -------------------------------------------------------------------------------- /bit_manipulation/check_bit_set.py: -------------------------------------------------------------------------------- 1 | def bit_set(x, y): 2 | mask = 1 << (y - 1) 3 | return (x & mask) != 0 4 | 5 | 6 | def run_tests(): 7 | assert bit_set(5, 1) is True 8 | assert bit_set(5, 2) is False 9 | assert bit_set(5, 3) is True 10 | assert bit_set(15, 3) is True 11 | assert bit_set(0, 3) is False 12 | assert bit_set(0, 30) is False 13 | 14 | 15 | if __name__ == '__main__': 16 | run_tests() 17 | -------------------------------------------------------------------------------- /seven-boom/seven_boom_original.py: -------------------------------------------------------------------------------- 1 | def divisible_by_seven(num): 2 | divisible = num % 7 == 0 3 | return divisible 4 | 5 | def contains_seven(num): 6 | contains = '7' in str(num) 7 | return contains 8 | 9 | def seven_boom(): 10 | num = 1 11 | while True: 12 | if divisible_by_seven(num) | contains_seven(num): 13 | print("BOOM") 14 | else: 15 | print(num) 16 | num += 1 17 | 18 | if __name__ == "__main__": 19 | seven_boom() 20 | -------------------------------------------------------------------------------- /bit_manipulation/check_all_bits_set.py: -------------------------------------------------------------------------------- 1 | def exact_bit_set(x, y, z): 2 | n1 = 1 << (x - 1) 3 | n2 = 1 << (y - 1) 4 | N = n1 | n2 5 | return z == N 6 | 7 | 8 | def run_tests(): 9 | assert exact_bit_set(2, 8, 20) is False 10 | assert exact_bit_set(1, 3, 20) is False 11 | assert exact_bit_set(1, 3, 5) is True 12 | assert exact_bit_set(1, 11, 1025) is True 13 | 14 | 15 | if __name__ == '__main__': 16 | run_tests() 17 | -------------------------------------------------------------------------------- /dot_files/git_wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function git { 4 | if [[ "$1" = "merge" && "$@" != *"--help"* && "$@" != *"--abort"* ]]; then 5 | git_merge_wrapper "$@"; 6 | else 7 | command git "$@" 8 | fi 9 | } 10 | 11 | function git_merge_wrapper { 12 | command git "$@" 13 | ret_code=$? 14 | if [[ "$ret_code" != 0 ]]; then 15 | command git merge --abort 16 | fi 17 | } -------------------------------------------------------------------------------- /bit_manipulation/find_single_number.py: -------------------------------------------------------------------------------- 1 | def find_single_number(arr): 2 | result = arr[0] 3 | for n in arr[1:]: 4 | result = result ^ n 5 | return result 6 | 7 | 8 | def run_tests(): 9 | arr = [0] 10 | assert find_single_number(arr) == 0 11 | 12 | arr = [1, 1, 2, 3, 3] 13 | assert find_single_number(arr) == 2 14 | 15 | arr = [2, 1, 1, 3, 3, 1, 1] 16 | assert find_single_number(arr) == 2 17 | 18 | 19 | if __name__ == '__main__': 20 | run_tests() 21 | -------------------------------------------------------------------------------- /bit_manipulation/get_revers_bits.py: -------------------------------------------------------------------------------- 1 | def revers_bits(x): 2 | result = 0 3 | for i in range(0, 32): 4 | current_bit = x >> i & 1 5 | result = result | current_bit << (32 - i - 1) 6 | return result 7 | 8 | 9 | def run_tests(): 10 | assert revers_bits(0) == 0 11 | assert revers_bits(1) == pow(2, 31) 12 | assert revers_bits(pow(2, 31)) == 1 13 | assert revers_bits(pow(2, 31) + 1) == pow(2, 31) + 1 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | run_tests() 19 | -------------------------------------------------------------------------------- /recursion/bad_fib.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | 4 | def fib(n): 5 | if (n <= 2): 6 | return 1 7 | else: 8 | return fib(n - 1) + fib(n - 2) 9 | 10 | 11 | def run(n): 12 | start_time = datetime.now() 13 | res = fib(n) 14 | print("Calculating fib(%d) = %d took %s seconds" % (n, res, datetime.now() - start_time)) 15 | 16 | 17 | if __name__ == '__main__': 18 | run(2) 19 | run(5) 20 | run(10) 21 | run(20) 22 | run(30) 23 | run(40) 24 | run(60) 25 | -------------------------------------------------------------------------------- /dot_files/git_hooks/pre-merge-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Related blog post (in Hebrew) - https://algoritmim.co.il/2019/12/18/git-me-baby-one-more-time 4 | 5 | # Get the current branch name 6 | branch_name=$(git branch | grep "*" | sed "s/\* //") 7 | 8 | # if the merged branch was master - don't do anything 9 | if [[ $branch_name = "master" ]]; then 10 | echo "Preparing to merge to master..." 11 | if git diff --cached | grep '^[+d].*NO_MERGE'; then 12 | echo "Can't merge branch with 'NO_MERGE' comment, fix what you need and try again!" 13 | exit 1 14 | fi 15 | fi -------------------------------------------------------------------------------- /seven-boom/seven_boom_alt.py: -------------------------------------------------------------------------------- 1 | def divisible_by_seven(num): 2 | divisible = num % 7 == 0 3 | return divisible 4 | 5 | def contains_seven(num): 6 | contains = '7' in str(num) 7 | return contains 8 | 9 | def seven_boom(): 10 | num = 1 11 | counter = 1 12 | while True: 13 | if counter == 7: 14 | print("BOOM") 15 | counter = 0 16 | elif contains_seven(num): 17 | print("BOOM") 18 | else: 19 | print(num) 20 | num += 1 21 | counter += 1 22 | 23 | if __name__ == "__main__": 24 | seven_boom() 25 | -------------------------------------------------------------------------------- /ProfilingExample/main.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from viztracer import VizTracer 3 | 4 | 5 | def create_list(): 6 | return [1] * 10000000 7 | 8 | 9 | def remove_from_start(li): 10 | li.pop(0) 11 | 12 | 13 | def remove_from_end(li): 14 | li.pop(len(li) - 1) 15 | 16 | 17 | def delete_list(my_list): 18 | while len(my_list) > 0: 19 | remove_from_start(my_list) 20 | remove_from_end(my_list) 21 | 22 | 23 | if __name__ == '__main__': 24 | tracer = VizTracer() 25 | tracer.start() 26 | my_list = create_list() 27 | delete_list(my_list) 28 | tracer.stop() 29 | tracer.save("profile.json") 30 | -------------------------------------------------------------------------------- /bit_manipulation/get_all_powers_of_two.py: -------------------------------------------------------------------------------- 1 | def get_all_powers_of_two(x): 2 | res = [] 3 | power_of_two = 1 4 | while power_of_two <= x: 5 | if power_of_two & x != 0: 6 | res.append(power_of_two) 7 | power_of_two = power_of_two << 1 8 | return res 9 | 10 | 11 | def run_tests(): 12 | assert get_all_powers_of_two(330) == [2, 8, 64, 256] 13 | assert get_all_powers_of_two(3) == [1, 2] 14 | assert get_all_powers_of_two(22) == [2, 4, 16] 15 | assert get_all_powers_of_two(0) == [] 16 | assert get_all_powers_of_two(1) == [1] 17 | 18 | 19 | if __name__ == '__main__': 20 | run_tests() 21 | -------------------------------------------------------------------------------- /Mastermind/tests/game_locig/test_check_player_guess_with_duplicates.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | from app.game_logic.checkers import check_player_guess_with_duplicates 4 | 5 | 6 | def test_check_duplicates_in_guess_not_scored_twice(): 7 | code = ["red", "blue", "green"] 8 | 9 | guess1 = ["red", "red", "red"] 10 | assert check_player_guess_with_duplicates(code, guess1) == (1, 0) 11 | 12 | guess2 = ["blue", "blue", "blue"] 13 | assert check_player_guess_with_duplicates(code, guess2) == (1, 0) 14 | 15 | guess3 = ["blue", "blue", "red"] 16 | assert check_player_guess_with_duplicates(code, guess3) == (1, 1) 17 | -------------------------------------------------------------------------------- /fibsum.py: -------------------------------------------------------------------------------- 1 | def fibsum(N): 2 | if N == 0: 3 | return 0 4 | 5 | previous = 0 6 | current = 1 7 | while current <= N: 8 | tmp = current 9 | current = current + previous 10 | previous = tmp 11 | 12 | ########## here current >= A 13 | 14 | count = 0 15 | remain = N 16 | while remain >= previous: 17 | count += 1 18 | remain -= previous 19 | 20 | return count + fibsum(remain) 21 | 22 | 23 | if __name__ == '__main__': 24 | assert fibsum(0) == 0 25 | assert fibsum(2) == 1 26 | assert fibsum(8) == 1 27 | assert fibsum(11) == 2 28 | assert fibsum(12) == 3 29 | -------------------------------------------------------------------------------- /last_word.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/18/last-word/ 2 | 3 | def find_last_word(s): 4 | last_word = "" 5 | i = len(s) - 1 6 | while i >= 0 and s[i] == " ": 7 | i -= 1 8 | while i >= 0 and s[i] != " ": 9 | last_word = s[i] + last_word 10 | i -= 1 11 | return last_word 12 | 13 | def run_tests(): 14 | assert find_last_word("") == "" 15 | assert find_last_word(" ") == "" 16 | assert find_last_word("a") == "a" 17 | assert find_last_word("dog ") == "dog" 18 | assert find_last_word("hello world") == "world" 19 | 20 | 21 | if __name__ == '__main__': 22 | run_tests() -------------------------------------------------------------------------------- /copy_bits.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/25/copy-bits/ 2 | 3 | def copy_bits(N, M, i, j): 4 | x = -1 << i 5 | y = (1 << j+1) - 1 6 | mask = ~(x & y) 7 | N = N & mask 8 | M = M << i 9 | return N | M 10 | 11 | def run_tests(): 12 | assert copy_bits(0, 0, 2, 6) == 0 13 | assert copy_bits(1, 0, 2, 6) == 1 14 | assert copy_bits(1, 0, 0, 1) == 0 15 | 16 | assert copy_bits(int('10001111100', 2), int('10011', 2), 2, 6) == int('10001001100', 2) 17 | assert copy_bits(int('11111111111', 2), int('0000', 2), 5, 8) == int('11000011111', 2) 18 | 19 | 20 | if __name__ == '__main__': 21 | run_tests() -------------------------------------------------------------------------------- /calculator/README.md: -------------------------------------------------------------------------------- 1 | An implementation of a "flexible" calculator that receives 2 | a mathematical expression in a form of a list of chars, 3 | and recursively calculates the results. 4 | 5 | The calculator allows the user to choose one of two possible 6 | mathematical writing notation for interpreting the given expression. 7 | 8 | The two possible notation relate specifically to the interpretation 9 | of implied multiplication - 10 | 11 | 1. 8÷2(2+2) = 8÷2*(2+2) = 8÷2*4 = 4*4 = 16 12 | 2. 8÷2(2+2) = 8/(2*(2+2)) = 8/(2*4) = 8/8 = 1 13 | 14 | Related blog posts - 15 | 16 | Calculator part A - https://algoritmim.co.il/2019/08/24/cala-part-a/ 17 | Calculator part B - https://algoritmim.co.il/2019/08/24/cala-part-b/ -------------------------------------------------------------------------------- /nextBigger.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2020/05/24/next-bigger-number/ 2 | 3 | 4 | def nextBigger(n): 5 | digits = [int(d) for d in str(n)] 6 | for i in range(len(digits) - 2, -1, -1): 7 | for j in range(len(digits) - 1, i, -1): 8 | if digits[i] < digits[j]: 9 | digits[i], digits[j] = digits[j], digits[i] 10 | digits[i+1:] = sorted(digits[i+1:]) 11 | return int(''.join([str(d) for d in digits])) 12 | return -1 13 | 14 | 15 | def run_tests(): 16 | assert nextBigger(12) == 21 17 | assert nextBigger(513) == 531 18 | assert nextBigger(111) == -1 19 | assert nextBigger(1144) == 1414 20 | assert nextBigger(1662) == 2166 21 | 22 | 23 | if __name__ == '__main__': 24 | run_tests() 25 | -------------------------------------------------------------------------------- /find_median_of_three.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/17/find-median-of-three/ 2 | 3 | def is_median(x,y,z): 4 | # Returns True if x is the median of the group x,y,z 5 | if x <= y and x >= z or x>=y and x<=z: 6 | return True 7 | else: 8 | return False 9 | 10 | def get_median_of_three(a,b,c): 11 | if is_median(a,b,c): 12 | return a 13 | if is_median(b,c,a): 14 | return b 15 | else: 16 | return c 17 | 18 | def run_test(): 19 | print("The median of [0,0,0] is %d" % get_median_of_three(0,0,0)) 20 | print("The median of [10,2,6] is %d" % get_median_of_three(10,2,6)) 21 | print("The median of [100,-100,-100] is %d" % get_median_of_three(100,-100,-100)) 22 | print("The median of [1,1,9] is %d" % get_median_of_three(1,1,9)) 23 | 24 | if __name__ == "__main__": 25 | run_test() 26 | -------------------------------------------------------------------------------- /recursion/memoizedFib.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | 4 | def memoized_fib(n): 5 | results_cache = {} 6 | 7 | def fib(num): 8 | if num in results_cache: 9 | return results_cache[num] 10 | else: 11 | if num <= 2: 12 | res = 1 13 | else: 14 | res = fib(num - 1) + fib(num - 2) 15 | 16 | results_cache[num] = res 17 | return res 18 | 19 | return fib(n) 20 | 21 | 22 | def run(n): 23 | start_time = datetime.now() 24 | res = memoized_fib(n) 25 | print("Calculating fib(%d) = %d took %s seconds" % (n, res, datetime.now() - start_time)) 26 | 27 | 28 | if __name__ == '__main__': 29 | run(2) 30 | run(5) 31 | run(10) 32 | run(50) 33 | run(100) 34 | run(500) 35 | run(1000) 36 | -------------------------------------------------------------------------------- /power_set.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/20/power-set/ 2 | 3 | def get_padded_bin(num, padded_length): 4 | format_str = '0%db' % padded_length 5 | return format(num, format_str) 6 | 7 | 8 | def get_all_subsets(group): 9 | group = list(group) 10 | subsets = list() 11 | arr_size = len(group) 12 | max_num = pow(2, arr_size) 13 | for i in range(0, max_num): 14 | current_subset = set() 15 | bin_repr = get_padded_bin(i, arr_size) 16 | for j in range(0, arr_size): 17 | if bin_repr[j] == '1': 18 | current_subset.add(group[j]) 19 | subsets.append(current_subset) 20 | return subsets 21 | 22 | def run_tests(): 23 | for group in [{}, {1, 2, 3}, {"dog", "cat", "mouse", "bird"}]: 24 | print("all the subsets of %s are - " % group) 25 | print(get_all_subsets(group)) 26 | 27 | 28 | if __name__ == '__main__': 29 | run_tests() -------------------------------------------------------------------------------- /queues/indexed_queue.py: -------------------------------------------------------------------------------- 1 | class IndexedQueue: 2 | def __init__(self): 3 | self.queue = list() 4 | self.__queue_size = 0 5 | self.start_index = 0 6 | 7 | def size(self): 8 | return self.__queue_size 9 | 10 | def add(self, item): 11 | self.queue.append(item) 12 | self.__queue_size += 1 13 | 14 | def pop_first(self): 15 | if self.__queue_size == 0: 16 | return None 17 | 18 | if self.start_index == self.__queue_size - 1: 19 | return None 20 | else: 21 | first_item = self.queue[self.start_index] 22 | self.__queue_size -= 1 23 | self.start_index += 1 24 | return first_item 25 | 26 | 27 | def test(): 28 | q = IndexedQueue() 29 | assert (q.pop_first() is None) 30 | q.add(1) 31 | q.add(2) 32 | assert (q.pop_first() == 1) 33 | assert (q.pop_first() == 2) 34 | assert (q.pop_first() is None) 35 | assert (q.size() == 0) 36 | 37 | -------------------------------------------------------------------------------- /Mastermind/app/main.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from consts import * 4 | from app.game_logic.player import get_player_guess 5 | from app.game_logic.checkers import check_player_guess_with_duplicates 6 | 7 | 8 | def generate_code(): 9 | code = [] 10 | for i in range(0, CODE_LENGTH): 11 | code.append(random.choice(COLORS)) 12 | return code 13 | 14 | 15 | def play(): 16 | computer_code = generate_code() 17 | 18 | game_won = False 19 | rounds = 0 20 | while not game_won and rounds < TOTAL_ROUNDS: 21 | player_guess = get_player_guess() 22 | bul, pgia = check_player_guess_with_duplicates(computer_code, player_guess) 23 | if bul == CODE_LENGTH: 24 | game_won = True 25 | break 26 | else: 27 | print(USER_SCORE.format(bul, pgia)) 28 | rounds += 1 29 | 30 | if game_won: 31 | print(USER_WON) 32 | else: 33 | print(USER_LOST) 34 | 35 | 36 | if __name__ == '__main__': 37 | play() 38 | -------------------------------------------------------------------------------- /palindrome.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2020/02/03 2 | 3 | 4 | def is_palindrome_v1(word): 5 | word = str(word) 6 | i = 0 7 | j = len(word) - 1 8 | 9 | while i < j: 10 | if word[i] != word[j]: 11 | return False 12 | i += 1 13 | j -= 1 14 | return True 15 | 16 | 17 | def _is_palindrome_recur(word): 18 | if len(word) <= 1: 19 | return True 20 | if word[0] != word[-1]: 21 | return False 22 | return _is_palindrome_recur(word[1:-1]) 23 | 24 | 25 | def is_palindrome_v2(word): 26 | return _is_palindrome_recur(str(word)) 27 | 28 | 29 | def run_tests(): 30 | for func in [is_palindrome_v1, is_palindrome_v2]: 31 | assert func("a") is True 32 | assert func("aba") is True 33 | assert func("abba") is True 34 | assert func("dog") is False 35 | assert func(123) is False 36 | assert func(123321) is True 37 | 38 | 39 | if __name__ == '__main__': 40 | run_tests() 41 | -------------------------------------------------------------------------------- /longest_sub_sequence_length.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/08/04/longest-subsequence-length/ 2 | 3 | def longest_subsequence_length(arr): 4 | longest_length = 0 5 | seq = dict() 6 | for n in arr: 7 | if n - 1 in seq: 8 | seq_min = seq.pop(n - 1)[0] 9 | else: 10 | seq_min = n 11 | if n + 1 in seq: 12 | seq_max = seq.pop(n + 1)[1] 13 | else: 14 | seq_max = n 15 | current_seq = (seq_min, seq_max) 16 | seq[seq_min] = seq[seq_max] = current_seq 17 | longest_length = max(longest_length, current_seq[1]-current_seq[0] + 1) 18 | return longest_length 19 | 20 | def run_tests(): 21 | assert longest_subsequence_length([2, 5, 3, 10, 9, 4]) == 4 22 | assert longest_subsequence_length([2]) == 1 23 | assert longest_subsequence_length([2, 4, 7, 20, 0]) == 1 24 | assert longest_subsequence_length([101, 2, 3, 4, 5, 6, 100, 1]) == 6 25 | assert longest_subsequence_length([]) == 0 26 | 27 | 28 | if __name__ == '__main__': 29 | run_tests() -------------------------------------------------------------------------------- /approximate_sort.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/19/approximate-sort/ 2 | 3 | from heapq import heappop, heappush 4 | 5 | def sort_approximate(arr, k): 6 | if k == 0: 7 | return arr 8 | sorted_arr = list() 9 | heap = [] 10 | 11 | for i in range(0, k): 12 | heappush(heap, arr[i]) 13 | 14 | for i in range(k, len(arr)): 15 | sorted_arr.append(heappop(heap)) 16 | heappush(heap,arr[i]) 17 | 18 | for i in range(0, k): 19 | sorted_arr.append(heappop(heap)) 20 | 21 | return sorted_arr 22 | 23 | def run_tests(): 24 | examples = [ 25 | (3,[3, 1, 4, 2, 7, 6, 5]), 26 | (0,[1,2]), 27 | (7, [3, 1, 4, 2, 7, 6, 5]), 28 | (7, [35, 70, 61, 24, 53, 40, 1, 14, 30, 29, 100, 99, 36]), 29 | ] 30 | for (k,arr) in examples: 31 | print("Original array - ") 32 | print(arr) 33 | sorted_array = sort_approximate(arr, k) 34 | print("Array after sorting - ") 35 | print(sorted_array) 36 | 37 | 38 | if __name__ == '__main__': 39 | run_tests() 40 | -------------------------------------------------------------------------------- /anagrams.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/17/anagrams/ 2 | 3 | import string 4 | from collections import defaultdict 5 | 6 | 7 | def get_word_key(word): 8 | hist = defaultdict(int) 9 | for c in word: 10 | hist[c] += 1 11 | str_hist = "" 12 | for c in string.ascii_letters: 13 | str_hist += "%s%d" % (c, hist[c]) 14 | 15 | return ''.join(str_hist) 16 | 17 | 18 | def find_anagrams(arr): 19 | results = defaultdict(list) 20 | for i in range(0, len(arr)): 21 | word = arr[i] 22 | word_key = get_word_key(word) 23 | results[word_key].append(i + 1) 24 | return list(results.values()) 25 | 26 | def run_tests(): 27 | assert find_anagrams(["dog", "god", "odg"]) == [[1,2,3]] 28 | assert find_anagrams(["dog", "cat", "god", "odg"]) == [[1,3,4], [2]] 29 | assert find_anagrams(["dog"]) == [[1]] 30 | assert find_anagrams(["dog", "dog"]) == [[1, 2]] 31 | assert find_anagrams(["dog", "Dog"]) == [[1], [2]] 32 | assert find_anagrams(["dog", "cat", "toy", "boy"]) == [[1], [2], [3], [4]] 33 | 34 | 35 | if __name__ == '__main__': 36 | run_tests() -------------------------------------------------------------------------------- /descriptive_numbers.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/18/descriptive-numbers/ 2 | 3 | def get_number_description(num): 4 | res = "" 5 | current_count = 1 6 | current_digit = num[0] 7 | for i in range(1, len(num)): 8 | if num[i] == current_digit: 9 | current_count += 1 10 | else: 11 | res = res + str(current_count) + current_digit 12 | current_digit = num[i] 13 | current_count = 1 14 | res = res + str(current_count) + current_digit 15 | return int(res) 16 | 17 | 18 | def get_nth_descriptive(n): 19 | if n == 1: 20 | return 1 21 | else: 22 | i = 1 23 | current_number = 1 24 | while i < n: 25 | current_number = get_number_description(str(current_number)) 26 | i += 1 27 | 28 | return current_number 29 | 30 | def run_tests(): 31 | assert get_nth_descriptive(1) == 1 32 | assert get_nth_descriptive(2) == 11 33 | assert get_nth_descriptive(5) == 111221 34 | assert get_nth_descriptive(10) == 13211311123113112211 35 | 36 | 37 | if __name__ == '__main__': 38 | run_tests() -------------------------------------------------------------------------------- /Mastermind/app/game_logic/player.py: -------------------------------------------------------------------------------- 1 | from app.consts import * 2 | 3 | 4 | def validate_player_guess(player_guess): 5 | valid_input = True 6 | if len(player_guess) != CODE_LENGTH: 7 | print("Guess should be {} colors long".format(CODE_LENGTH)) 8 | valid_input = False 9 | 10 | for item in player_guess: 11 | if item not in COLORS: 12 | print("Bad input: {}".format(item)) 13 | valid_input = False 14 | 15 | return valid_input 16 | 17 | 18 | def format_player_guess(player_guess): 19 | guess = player_guess.split(" ") 20 | formatted_guess = [] 21 | for item in guess: 22 | if item in COLORS_DICT: 23 | formatted_guess.append(COLORS_DICT.get(item)) 24 | else: 25 | formatted_guess.append(item) 26 | return formatted_guess 27 | 28 | 29 | def get_player_guess(): 30 | guess = format_player_guess(input(USER_INPUT_PROMPT)) 31 | valid_input = validate_player_guess(guess) 32 | 33 | while not valid_input: 34 | guess = format_player_guess(input(USER_INPUT_PROMPT)) 35 | valid_input = validate_player_guess(guess) 36 | 37 | return guess 38 | 39 | -------------------------------------------------------------------------------- /Mastermind/app/game_logic/checkers.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def check_player_guess_no_duplicates(code, guess): 5 | code_set = set(code) 6 | bul = 0 7 | pgia = 0 8 | for i in range(0, len(guess)): 9 | color = guess[i] 10 | if color == code[i]: 11 | bul += 1 12 | elif color in code_set: 13 | pgia += 1 14 | 15 | return bul, pgia 16 | 17 | 18 | def check_player_guess_with_duplicates(code, guess): 19 | code_counter = Counter(code) 20 | bul = 0 21 | pgia = 0 22 | for i in range(0, len(guess)): 23 | color = guess[i] 24 | if color == code[i]: 25 | bul += 1 26 | decrease_color(code_counter, color) 27 | 28 | for i in range(0, len(guess)): 29 | color = guess[i] 30 | if color in code_counter: 31 | pgia += 1 32 | decrease_color(code_counter, color) 33 | 34 | return bul, pgia 35 | 36 | 37 | def decrease_color(code_counter, color): 38 | if color in code_counter: 39 | updated_color_count = code_counter.pop(color) - 1 40 | if updated_color_count > 0: 41 | code_counter[color] = updated_color_count 42 | -------------------------------------------------------------------------------- /jump_game.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/23/jump-game/ 2 | 3 | class JumpGame(object): 4 | def __init__(self): 5 | self.jumps = {} 6 | self.arr = None 7 | 8 | def can_finish_from_index(self, i): 9 | if i >= len(self.arr): 10 | self.jumps[i] = False 11 | elif i == len(self.arr) - 1: 12 | self.jumps[i] = True 13 | elif self.arr[i] == 0: 14 | self.jumps[i] = False 15 | else: 16 | self.jumps[i] = False 17 | for jump_size in range(1, self.arr[i]+1): 18 | if i + jump_size not in self.jumps: 19 | self.jumps[i + jump_size] = self.can_finish_from_index(i + jump_size) 20 | self.jumps[i] = self.jumps[i] or self.jumps[i + jump_size] 21 | return self.jumps[i] 22 | 23 | def can_finish_game(self, arr): 24 | self.arr = arr 25 | return self.can_finish_from_index(0) 26 | 27 | def run_tests(): 28 | assert JumpGame().can_finish_game([]) is False 29 | assert JumpGame().can_finish_game([0]) is True 30 | assert JumpGame().can_finish_game([1, 2, 0, 3]) is True 31 | assert JumpGame().can_finish_game([2, 1, 0, 1]) is False 32 | 33 | 34 | if __name__ == '__main__': 35 | run_tests() -------------------------------------------------------------------------------- /four_in_a_row/logic.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/just-code/connect-four-game-in-python/ 2 | 3 | from four_in_a_row.board import Color 4 | 5 | from four_in_a_row.board import BoardUtils 6 | 7 | 8 | def four_sequence_exists(discs_vector): 9 | longest_seq = 1 10 | current_seq = 1 11 | for i in range(1, len(discs_vector)): 12 | if discs_vector[i] == discs_vector[i - 1] and not (discs_vector[i] is Color.EMPTY.value): 13 | current_seq += 1 14 | if current_seq > longest_seq: 15 | longest_seq = current_seq 16 | else: 17 | current_seq = 1 18 | return longest_seq == 4 19 | 20 | 21 | def add_disc(current_color, board, column): 22 | row = 0 23 | success = False 24 | while row < board.rows and not success: 25 | if board.get(row, column) is Color.EMPTY: 26 | board.set(row, column, current_color) 27 | success = True 28 | else: 29 | row += 1 30 | return success 31 | 32 | 33 | def is_win(board, row, column): 34 | vector_getters = [BoardUtils.get_row_vector, BoardUtils.get_column_vector, BoardUtils.get_positive_diagonal_vector, 35 | BoardUtils.get_negative_diagonal_vector 36 | ] 37 | for getter in vector_getters: 38 | discs_vector = getter(board, row, column) 39 | if four_sequence_exists(discs_vector): 40 | return True 41 | return False 42 | -------------------------------------------------------------------------------- /first_ancestor.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/24/first-ancestor/ 2 | 3 | class Node(object): 4 | def __init__(self, val, parent): 5 | self.val = val 6 | self.parent = parent 7 | self.visited = False 8 | 9 | def __repr__(self): 10 | return self.val 11 | 12 | def find_first_ancestor_recur(x, y): 13 | if x is not None and y is not None and x == y: 14 | return x 15 | next_nodes = [] 16 | for node in [x, y]: 17 | if node is not None: 18 | if node.visited: 19 | return node 20 | else: 21 | node.visited = True 22 | next_nodes.append(node.parent) 23 | return find_first_ancestor_recur(next_nodes[0], next_nodes[1]) 24 | 25 | def find_first_ancestor(x, y): 26 | if x.parent is None or y.parent is None: 27 | return 28 | return find_first_ancestor_recur(x.parent, y.parent) 29 | 30 | def run_tests(): 31 | a = Node("A", None) 32 | assert find_first_ancestor(a, a) is None 33 | 34 | b = Node("B", a) 35 | c = Node("C", a) 36 | 37 | assert find_first_ancestor(b, c) == a 38 | 39 | d = Node("D", b) 40 | e = Node("E", d) 41 | f = Node("F", d) 42 | 43 | assert find_first_ancestor(b, c) == a 44 | assert find_first_ancestor(d, e) == b 45 | assert find_first_ancestor(f, e) == d 46 | assert find_first_ancestor(e, c) == a 47 | 48 | 49 | if __name__ == '__main__': 50 | run_tests() -------------------------------------------------------------------------------- /ProfilingExample/rate_tweets.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import timeit 3 | 4 | 5 | class Fields: 6 | LIKES_FIELD = 'nlikes' 7 | POPULARITY_FIELD = 'tweet_popularity' 8 | 9 | 10 | def rate_tweet_popularity(num_likes): 11 | if num_likes <= 50: 12 | return 'low' 13 | if 50 < num_likes <= 500: 14 | return 'medium' 15 | if num_likes > 500: 16 | return 'high' 17 | 18 | 19 | def run_with_iter(df): 20 | tweet_popularity = [] 21 | for i, row in df.iterrows(): 22 | tweet_popularity.append(rate_tweet_popularity(row[Fields.LIKES_FIELD])) 23 | df[Fields.POPULARITY_FIELD] = tweet_popularity 24 | 25 | 26 | def run_with_apply(df): 27 | df[Fields.POPULARITY_FIELD] = df.apply(lambda row: rate_tweet_popularity(row[Fields.LIKES_FIELD]), axis=1) 28 | 29 | 30 | def run_with_vectors(df): 31 | df[Fields.POPULARITY_FIELD] = 0 32 | df.loc[(df[Fields.LIKES_FIELD] <= 50), Fields.POPULARITY_FIELD] = 'low' 33 | df.loc[(50 <= df[Fields.LIKES_FIELD]) & (df[Fields.LIKES_FIELD] < 500), Fields.POPULARITY_FIELD] = 'medium' 34 | df.loc[(500 < df[Fields.LIKES_FIELD]), Fields.POPULARITY_FIELD] = 'high' 35 | 36 | 37 | if __name__ == '__main__': 38 | data_set = pd.read_csv('~/Downloads/elon-musk/2020.csv') 39 | print("Method run_with_vectors finished in", timeit.timeit( 40 | "run_with_vectors(data_set)", globals=globals(), number=1 41 | ), "ms") 42 | print("Popularity results: \n", data_set[Fields.POPULARITY_FIELD].value_counts()) 43 | -------------------------------------------------------------------------------- /stones.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def play(self, nums, start, end, p, totalSum, bestScoreMemo): 3 | if start > end: 4 | return 0 5 | 6 | if (start, end, p) in bestScoreMemo: 7 | return bestScoreMemo[start, end, p] 8 | 9 | if p == "p1": 10 | p2MaxScore1 = self.play( 11 | nums, start + 1, end, "p2", totalSum - nums[start], bestScoreMemo 12 | ) 13 | p2MaxScore2 = self.play( 14 | nums, start, end - 1, "p2", totalSum - nums[end], bestScoreMemo 15 | ) 16 | bestScoreMemo[start, end, p] = max( 17 | totalSum - p2MaxScore1, totalSum - p2MaxScore2 18 | ) 19 | else: 20 | p1MaxScore1 = self.play( 21 | nums, start + 1, end, "p1", totalSum - nums[start], bestScoreMemo 22 | ) 23 | p1MaxScore2 = self.play( 24 | nums, start, end - 1, "p1", totalSum - nums[end], bestScoreMemo 25 | ) 26 | bestScoreMemo[start, end, p] = max( 27 | totalSum - p1MaxScore1, totalSum - p1MaxScore2 28 | ) 29 | 30 | return bestScoreMemo[start, end, p] 31 | 32 | def predictTheWinner(self, nums: List[int]) -> bool: 33 | bestScoreMemo = {} 34 | total_sum = sum(nums) 35 | self.play(nums, 0, len(nums) - 1, "p1", total_sum, bestScoreMemo) 36 | p1BestScore = bestScoreMemo[(0, len(nums) - 1, "p1")] 37 | return p1BestScore >= total_sum - p1BestScore 38 | -------------------------------------------------------------------------------- /merge_meetings.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/06/merge-meetings/ 2 | 3 | class Meeting(object): 4 | def __init__(self, start, end): 5 | self.start_time = start 6 | self.end_time = end 7 | 8 | def __lt__(self, other): 9 | return self.start_time < other.start_time 10 | 11 | def __eq__(self, other): 12 | return self.start_time == other.start_time and self.end_time == other.end_time 13 | 14 | def __repr__(self): 15 | return "(%d,%d)" % (self.start_time, self.end_time) 16 | 17 | 18 | def merge_meetings(arr): 19 | if len(arr) <= 1: 20 | return arr 21 | 22 | arr.sort() 23 | res = [arr[0]] 24 | previous_meeting = arr[0] 25 | for i in range(1, len(arr)): 26 | new_meeting = arr[i] 27 | if new_meeting.start_time <= previous_meeting.end_time: 28 | previous_meeting.end_time = new_meeting.end_time 29 | else: 30 | res.append(new_meeting) 31 | previous_meeting = new_meeting 32 | 33 | return res 34 | 35 | 36 | def run_tests(): 37 | arr = [Meeting(3, 4), Meeting(0, 2)] 38 | assert merge_meetings(arr) == [Meeting(0, 2), Meeting(3, 4)] 39 | 40 | arr = [Meeting(3, 4), Meeting(0, 2), Meeting(1, 3)] 41 | assert merge_meetings(arr) == [Meeting(0, 4)] 42 | 43 | arr = [Meeting(0, 1), Meeting(3, 5), Meeting(4, 8), Meeting(10, 12), Meeting(9, 10)] 44 | assert merge_meetings(arr) == [Meeting(0, 1), Meeting(3, 8), Meeting(9, 12)] 45 | 46 | 47 | if __name__ == '__main__': 48 | run_tests() 49 | -------------------------------------------------------------------------------- /code_jam/2018/senate_evacuation.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/11/23/senate-evacuation/ 2 | 3 | import string 4 | 5 | def remove_senators(senators_counter, senators_to_evict): 6 | for senator in senators_to_evict: 7 | senators_counter[senator] -= 1 8 | if senators_counter[senator] == 0: 9 | senators_counter.pop(senator) 10 | 11 | def format_results(eviction_plan_list): 12 | eviction_plan_list = ["".join(senators) for senators in eviction_plan_list] 13 | return " ".join(eviction_plan_list) 14 | 15 | 16 | def choose_next_to_evict(senators_counter): 17 | if len(senators_counter) == 2: 18 | return list(senators_counter.keys()) 19 | else: 20 | return [max(senators_counter, key=senators_counter.get)] 21 | 22 | 23 | def evict_the_senate_iter(senators_counter): 24 | eviction_plan = [] 25 | while len(senators_counter) > 0: 26 | senators_to_evict = choose_next_to_evict(senators_counter) 27 | remove_senators(senators_counter, senators_to_evict) 28 | eviction_plan.append(senators_to_evict) 29 | return format_results(eviction_plan) 30 | 31 | 32 | if __name__ == '__main__': 33 | num_test_cases = int(input()) 34 | for i in range(1, num_test_cases + 1): 35 | num_parties = int(input()) 36 | parties = [c for c in string.ascii_uppercase[:num_parties]] 37 | senators_count_per_party = [int(s) for s in input().split(" ")] 38 | counter = dict(zip(parties, senators_count_per_party)) 39 | 40 | print("Case #{}: {}".format(i, evict_the_senate_iter(counter))) 41 | -------------------------------------------------------------------------------- /recur_multiply.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/20/recur-multiply/ 2 | 3 | class Multiplier(object): 4 | def __init__(self): 5 | self.results_cache = {} 6 | 7 | def recur_multiply(self, a, b): 8 | if a == 0: 9 | return 0 10 | if b not in self.results_cache: 11 | if b == 0: 12 | self.results_cache[0] = 0 13 | elif b == 1: 14 | self.results_cache[1] = a 15 | elif b % 2 == 0: 16 | if b / 2 not in self.results_cache: 17 | self.results_cache[b / 2] = self.recur_multiply(a, b / 2) 18 | self.results_cache[b] = self.results_cache[b / 2] + self.results_cache[b / 2] 19 | else: 20 | self.results_cache[(b - 1) / 2] = self.recur_multiply(a, (b - 1) / 2) 21 | self.results_cache[b] = self.results_cache[(b - 1) / 2] + \ 22 | self.results_cache[(b - 1) / 2] + \ 23 | self.recur_multiply(a, 1) 24 | return self.results_cache[b] 25 | 26 | def multiply(self, a, b): 27 | if a > b: 28 | return self.recur_multiply(a, b) 29 | else: 30 | return self.recur_multiply(b, a) 31 | 32 | def run_tests(): 33 | assert Multiplier().multiply(3, 10) == 30 34 | assert Multiplier().multiply(10, 3) == 30 35 | assert Multiplier().multiply(3, 0) == 0 36 | assert Multiplier().multiply(0, 10) == 0 37 | assert Multiplier().multiply(pow(2, 3), pow(2, 10)) == 8192 38 | 39 | 40 | if __name__ == '__main__': 41 | run_tests() -------------------------------------------------------------------------------- /longest_k_unique.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/04/k-unique-sequence/ 2 | 3 | import copy 4 | from collections import defaultdict 5 | 6 | def find_longest_k_unique(arr, k): 7 | longest_k_uniuqe = [] 8 | if len(arr) == 1: 9 | return arr 10 | else: 11 | i = j = 0 12 | current_k_unique = [arr[i]] 13 | current_range = defaultdict(int) 14 | current_range[arr[i]] += 1 15 | unique_count = len(current_range.keys()) 16 | 17 | while j < len(arr)-1: 18 | if unique_count <= k: 19 | j += 1 20 | current_k_unique.append(arr[j]) 21 | current_range[arr[j]] += 1 22 | else: 23 | del current_k_unique[0] 24 | 25 | current_range[arr[i]] -= 1 26 | if current_range[arr[i]] == 0: 27 | current_range.pop(arr[i]) 28 | i += 1 29 | unique_count = len(current_range.keys()) 30 | if unique_count == k: 31 | if len(current_k_unique) > len(longest_k_uniuqe): 32 | longest_k_uniuqe = copy.deepcopy(current_k_unique) 33 | 34 | return longest_k_uniuqe 35 | 36 | def run_tests(): 37 | arr = [1, 5, 3, 100, 3, 2, 2] 38 | k=1 39 | assert find_longest_k_unique(arr, k) == [2,2] 40 | 41 | k=2 42 | assert find_longest_k_unique(arr, k) == [3,100,3] 43 | 44 | k = 3 45 | assert find_longest_k_unique(arr, k) == [3,100,3,2,2] 46 | 47 | arr = [1, 2, 3, 4] 48 | k=1 49 | assert find_longest_k_unique(arr,k) == [2] 50 | 51 | k=2 52 | assert find_longest_k_unique(arr,k) == [1,2] 53 | 54 | 55 | if __name__ == '__main__': 56 | run_tests() -------------------------------------------------------------------------------- /queues/linked_list_queue.py: -------------------------------------------------------------------------------- 1 | class LinkedListNode: 2 | def __init__(self, value): 3 | self.__value = value 4 | self.next_node = None 5 | 6 | def value(self): 7 | return self.__value 8 | 9 | def set_next(self, node): 10 | self.next_node = node 11 | 12 | def get_next(self): 13 | return self.next_node 14 | 15 | 16 | class NullNode(LinkedListNode): 17 | def __init__(self): 18 | super().__init__(None) 19 | 20 | 21 | class LinkedListQueue: 22 | def __init__(self): 23 | self.__queue_size = 0 24 | self.first_node = NullNode() 25 | self.last_node = NullNode() 26 | 27 | def size(self): 28 | return self.__queue_size 29 | 30 | def add(self, value): 31 | if self.__queue_size == 0: 32 | self.first_node = LinkedListNode(value) 33 | self.first_node.set_next(NullNode()) 34 | self.last_node = self.first_node 35 | else: 36 | new_last_node = LinkedListNode(value) 37 | self.last_node.set_next(new_last_node) 38 | self.last_node = new_last_node 39 | self.__queue_size += 1 40 | 41 | def pop_first(self): 42 | if self.__queue_size == 0: 43 | return None 44 | else: 45 | first_value = self.first_node.value() 46 | self.first_node = self.first_node.get_next() 47 | self.__queue_size -= 1 48 | return first_value 49 | 50 | 51 | def test(): 52 | q = LinkedListQueue() 53 | assert (q.pop_first() is None) 54 | q.add(1) 55 | q.add(2) 56 | assert (q.pop_first() == 1) 57 | assert (q.pop_first() == 2) 58 | assert (q.pop_first() is None) 59 | assert (q.size() == 0) 60 | -------------------------------------------------------------------------------- /dot_files/.gitconfig: -------------------------------------------------------------------------------- 1 | # This is Git's per-user configuration file. 2 | [user] 3 | # Please adapt and uncomment the following lines: 4 | name = Maya Gershovitz Bar 5 | email = maya.solves@gmail.com 6 | [alias] 7 | co = checkout 8 | br = branch 9 | ci = commit 10 | st = status 11 | up = pull --rebase 12 | sq = "!f() { git rebase -i HEAD~$1; }; f" 13 | cm = "!f() { git add .; git commit -m $1; }; f" 14 | fix = "!f() { git add .; git commit -m "[fixup]"; }; f" 15 | fixit = "!f() { git add .; git commit --amend; }; f" 16 | open = "!f() { url="$(git config --get remote.origin.url | tr : /)"; full_url="$(echo "${url/git@/http://}")"; open $full_url; }; f" 17 | discard = reset --hard 18 | cbr = rev-parse --abbrev-ref HEAD 19 | delete-remote = !sh -c \"git push origin --delete $(git cbr)\" 20 | branches-by-order = branch --sort=-committerdate -vv --format='%(refname:short)' 21 | branches = "!f() { allBranches="$(git branches-by-order)"; branchesList=($allBranches); for i in {0..2}; do echo ${branchesList[i]}; done }; f" 22 | cob = !sh -c \"git checkout $(git branches | fzf )\" 23 | colb = checkout @{-1} 24 | pt = !sh -c \"git push --force-with-lease origin HEAD:refs/heads/$(git lcbr) \" 25 | pb = !sh -c \"git push --force-with-lease origin HEAD:refs/heads/$1 \" 26 | lc = rev-parse --short HEAD 27 | lcbr = "!f() { lastCommit="$(git lc)"; git cbr $lastCommit; }; f" 28 | [core] 29 | excludesfile = /Users/mayagershovitzbar/.gitignore_global 30 | [filter "lfs"] 31 | smudge = git-lfs smudge -- %f 32 | process = git-lfs filter-process 33 | required = true 34 | clean = git-lfs clean -- %f 35 | [init] 36 | templatedir = /Users/mayagershovitzbar/.git_template 37 | -------------------------------------------------------------------------------- /file_search.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/interview-practice/recursive-search-in-a-file-system/ 2 | 3 | import os 4 | import shutil 5 | 6 | 7 | def find_files_recur(root, file_name): 8 | def __get_files(folder): 9 | folder_files = os.listdir(folder) 10 | for f in folder_files: 11 | yield os.path.join(folder, f) 12 | 13 | def __find_file(f, name): 14 | if not os.path.isdir(f): 15 | if os.path.basename(f) == name: 16 | return f 17 | else: 18 | return __find_file_in_folder(f, name) 19 | 20 | def __find_file_in_folder(folder, name): 21 | for f in __get_files(folder): 22 | result = __find_file(f, name) 23 | if result: 24 | return result 25 | return None 26 | 27 | return __find_file(root, file_name) 28 | 29 | 30 | def run_tests(path): 31 | def __before(path): 32 | os.mkdir(path) 33 | file_path = os.path.join(path, "file1.txt") 34 | f = open(file_path, "w+") 35 | f.write("hello!") 36 | 37 | subdir = os.path.join(path, "hello") 38 | os.mkdir(subdir) 39 | sub_file_path = os.path.join(subdir, "file2.txt") 40 | f = open(sub_file_path, "w+") 41 | f.write("goodbye") 42 | 43 | return file_path, sub_file_path 44 | 45 | def __after(path): 46 | shutil.rmtree(path) 47 | 48 | file_path, sub_file_path = __before(path) 49 | try: 50 | assert find_files_recur(path, "file1.txt") == file_path 51 | assert find_files_recur(path, "file2.txt") == sub_file_path 52 | assert find_files_recur(path, "hello") is None 53 | except: 54 | print("TESTS FAILED") 55 | finally: 56 | __after(path) 57 | 58 | 59 | if __name__ == '__main__': 60 | tests_path = "/tmp/file_search_tests" 61 | run_tests(tests_path) 62 | -------------------------------------------------------------------------------- /island_journey.py: -------------------------------------------------------------------------------- 1 | class Island(object): 2 | def __init__(self, name): 3 | self.name = name 4 | 5 | def __repr__(self): 6 | return self.name 7 | 8 | class Bridge(object): 9 | def __init__(self, I1, I2, danger_grade): 10 | self.I1 = I1 11 | self.I2 = I2 12 | self.danger_grade = danger_grade 13 | 14 | def __repr__(self): 15 | return str(self.danger_grade) 16 | 17 | 18 | def add_bridge_islands(map_v, bridge): 19 | for island_set in map_v: 20 | found_i1 = bridge.I1 in island_set 21 | found_i2 = bridge.I2 in island_set 22 | if found_i1 and found_i2: 23 | return 0 24 | if found_i1 and not found_i2: 25 | island_set.add(bridge.I2) 26 | return 1 27 | elif found_i2 and not found_i1: 28 | island_set.add(bridge.I1) 29 | return 1 30 | 31 | map_v.append({bridge.I1, bridge.I2}) 32 | return 2 33 | 34 | def create_map(V, E): 35 | if len(V) <= 1: 36 | return E 37 | import IPython 38 | IPython.embed() 39 | ordered_bridges = sorted(E, key=lambda x: x.danger_grade) 40 | islands_count = 0 41 | 42 | map_e = list() 43 | map_v = list() 44 | for bridge in ordered_bridges: 45 | added_islands = add_bridge_islands(map_v, bridge) 46 | if added_islands: 47 | map_e.append(bridge) 48 | islands_count += added_islands 49 | if islands_count == len(V) and len(map_v) == 1: 50 | break 51 | 52 | return list(map_e) 53 | 54 | 55 | def run_tests(): 56 | A = Island("A") 57 | B = Island("B") 58 | C = Island("C") 59 | D = Island("D") 60 | V = [A, B, C, D] 61 | # 62 | # e_1 = Bridge(A,B,1) 63 | # e_2 = Bridge(A,D,6) 64 | # e_3 = Bridge(A,C,2) 65 | # e_4 = Bridge(B,C,3) 66 | # e_5 = Bridge(D,C,8) 67 | # E = [e_1, e_2, e_3, e_4, e_5] 68 | # assert create_map(V,E) == [e_1,e_3,e_2] 69 | 70 | e_1 = Bridge(A,B,1) 71 | e_2 = Bridge(A,D,3) 72 | e_3 = Bridge(A,C,10) 73 | e_4 = Bridge(B,C,4) 74 | e_5 = Bridge(D,C,2) 75 | E = [e_1, e_2, e_3, e_4, e_5] 76 | print (create_map(V,E)) 77 | assert create_map(V,E) == [e_1,e_5,e_3] 78 | 79 | 80 | if __name__ == '__main__': 81 | run_tests() -------------------------------------------------------------------------------- /calculator/magic_calc.py: -------------------------------------------------------------------------------- 1 | from basic_calc import BasicCalculator, OpStr 2 | 3 | 4 | def is_number(val): 5 | return not isinstance(val, str) 6 | 7 | class Config(object): 8 | CONF_1 = 1 9 | CONF_2 = 2 10 | 11 | class MagicCalculator(BasicCalculator): 12 | def __init__(self): 13 | super(MagicCalculator, self).__init__() 14 | 15 | @staticmethod 16 | def __apply_writing_conv(exp_arr, config): 17 | new_exp = [] 18 | i = 0 19 | parenthesis_counter = 0 20 | 21 | while i < len(exp_arr): 22 | next_val = exp_arr[i] 23 | new_exp.append(next_val) 24 | 25 | if is_number(next_val) and i < len(exp_arr) - 1 and exp_arr[i + 1] == OpStr.PAR_L: 26 | if config == Config.CONF_1: 27 | new_exp.append(OpStr.MUL) 28 | elif config == Config.CONF_2: 29 | parenthesis_counter += 1 30 | number = new_exp.pop() 31 | new_exp.extend([OpStr.PAR_L, number, OpStr.MUL]) 32 | elif next_val == OpStr.PAR_R: 33 | parenthesis_counter -= 1 34 | if parenthesis_counter == 0: 35 | new_exp.append(OpStr.PAR_R) 36 | i += 1 37 | return new_exp 38 | 39 | def solve(self, exp_arr, config=Config.CONF_1): 40 | exp_arr = self.__apply_writing_conv(exp_arr, config) 41 | return super(MagicCalculator, self).solve(exp_arr) 42 | 43 | def run_tests(): 44 | calc = MagicCalculator() 45 | assert calc.solve([1, "+", 2]) == 3 46 | assert calc.solve([1, "-", 2]) == -1 47 | assert calc.solve([2, "*", "(", 1, "+", 3, ")"]) == 8 48 | assert calc.solve([2, "*", "(", 1, "+", 6, "/", 3, ")"]) == 6 49 | assert calc.solve([2, "*", "(", 1, "+", 6, "/", 3, ")", "-", "(", 5, "*", 2, ")"]) == -4 50 | assert calc.solve([2, "+", "(", 3, "*", "(", 8, "/", 2, ")", "-", 10, ")"]) == 4 51 | 52 | assert calc.solve([8, "/", 2, "(", 2, "+", 2, ")"]) == 16 53 | assert calc.solve([8, "/", 2, "(", 2, "+", 2, ")"], Config.CONF_2) == 1 54 | 55 | assert calc.solve([1, "+", "(", 2, "/", 2, "(", 1, "+", 1, ")", "+", 3, ")"]) == 6 56 | assert calc.solve([1, "+", "(", 2, "/", 2, "(", 1, "+", 1, ")", "+", 3, ")"], Config.CONF_2) == 4.5 57 | 58 | 59 | if __name__ == '__main__': 60 | run_tests() 61 | -------------------------------------------------------------------------------- /sudoku_checker.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | 3 | 4 | def check_valid_vector(vector): 5 | for i in range(1, 10): 6 | if vector.count(i) != 1: 7 | return False 8 | return True 9 | 10 | 11 | def check_row_and_columns_are_valid(sudoku): 12 | for i in range(0, 9): 13 | row = sudoku[i] 14 | if not check_valid_vector(row): 15 | return False 16 | column = [sudoku[j][i] for j in range(0, 9)] 17 | if not check_valid_vector(column): 18 | return False 19 | return True 20 | 21 | 22 | def check_cubes_are_valid(sudoku, board_size): 23 | cube_size = int(sqrt(board_size)) 24 | for cube_row in range(0, cube_size): 25 | for cube_column in range(0, cube_size): 26 | cube = [] 27 | for i in range(0, cube_size): 28 | for j in range(0, cube_size): 29 | row = cube_row * cube_size + i 30 | column = cube_column * cube_size + j 31 | cube.append(sudoku[row][column]) 32 | if not check_valid_vector(cube): 33 | return False 34 | return True 35 | 36 | 37 | def check_sudoku_is_valid(sudoku): 38 | board_size = len(sudoku) 39 | return check_row_and_columns_are_valid(sudoku) and check_cubes_are_valid(sudoku, board_size) 40 | 41 | 42 | def run_tests(): 43 | valid_sudoku = [[5, 3, 4, 6, 7, 8, 9, 1, 2], 44 | [6, 7, 2, 1, 9, 5, 3, 4, 8], 45 | [1, 9, 8, 3, 4, 2, 5, 6, 7], 46 | [8, 5, 9, 7, 6, 1, 4, 2, 3], 47 | [4, 2, 6, 8, 5, 3, 7, 9, 1], 48 | [7, 1, 3, 9, 2, 4, 8, 5, 6], 49 | [9, 6, 1, 5, 3, 7, 2, 8, 4], 50 | [2, 8, 7, 4, 1, 9, 6, 3, 5], 51 | [3, 4, 5, 2, 8, 6, 1, 7, 9]] 52 | assert check_sudoku_is_valid(valid_sudoku) 53 | 54 | not_valid_sudoku = [[5, 3, 4, 6, 7, 8, 9, 1, 2], 55 | [6, 7, 2, 1, 9, 5, 3, 4, 8], 56 | [1, 9, 8, 3, 4, 2, 5, 6, 7], 57 | [8, 5, 9, 7, 6, 1, 4, 2, 3], 58 | [4, 2, 6, 8, 5, 3, 7, 9, 1], 59 | [7, 1, 3, 9, 2, 4, 8, 5, 6], 60 | [9, 6, 1, 5, 3, 7, 2, 8, 4], 61 | [2, 8, 7, 4, 1, 9, 6, 3, 5], 62 | [3, 4, 7, 2, 8, 6, 1, 5, 9]] 63 | 64 | assert not check_sudoku_is_valid(not_valid_sudoku) 65 | 66 | if __name__ == '__main__': 67 | run_tests() 68 | -------------------------------------------------------------------------------- /sudoku_checker_better.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/22/check-sudoku-better/ 2 | 3 | from math import sqrt 4 | 5 | 6 | def check_valid_vector(vector): 7 | num_set = set(vector) 8 | return len(num_set) == 9 9 | 10 | def check_row_and_columns_are_valid(sudoku): 11 | for i in range(0, 9): 12 | row = sudoku[i] 13 | if not check_valid_vector(row): 14 | return False 15 | column = [sudoku[j][i] for j in range(0, 9)] 16 | if not check_valid_vector(column): 17 | return False 18 | return True 19 | 20 | 21 | def check_cubes_are_valid(sudoku, board_size): 22 | cube_size = int(sqrt(board_size)) 23 | for cube_row in range(0, cube_size): 24 | for cube_column in range(0, cube_size): 25 | cube = [] 26 | for i in range(0, cube_size): 27 | for j in range(0, cube_size): 28 | row = cube_row * cube_size + i 29 | column = cube_column * cube_size + j 30 | cube.append(sudoku[row][column]) 31 | if not check_valid_vector(cube): 32 | return False 33 | return True 34 | 35 | 36 | def check_sudoku_is_valid(sudoku): 37 | board_size = len(sudoku) 38 | return check_row_and_columns_are_valid(sudoku) and check_cubes_are_valid(sudoku, board_size) 39 | 40 | 41 | def run_tests(): 42 | valid_sudoku = [[5, 3, 4, 6, 7, 8, 9, 1, 2], 43 | [6, 7, 2, 1, 9, 5, 3, 4, 8], 44 | [1, 9, 8, 3, 4, 2, 5, 6, 7], 45 | [8, 5, 9, 7, 6, 1, 4, 2, 3], 46 | [4, 2, 6, 8, 5, 3, 7, 9, 1], 47 | [7, 1, 3, 9, 2, 4, 8, 5, 6], 48 | [9, 6, 1, 5, 3, 7, 2, 8, 4], 49 | [2, 8, 7, 4, 1, 9, 6, 3, 5], 50 | [3, 4, 5, 2, 8, 6, 1, 7, 9]] 51 | assert check_sudoku_is_valid(valid_sudoku) 52 | 53 | not_valid_sudoku = [[5, 3, 4, 6, 7, 8, 9, 1, 2], 54 | [6, 7, 2, 1, 9, 5, 3, 4, 8], 55 | [1, 9, 8, 3, 4, 2, 5, 6, 7], 56 | [8, 5, 9, 7, 6, 1, 4, 2, 3], 57 | [4, 2, 6, 8, 5, 3, 7, 9, 1], 58 | [7, 1, 3, 9, 2, 4, 8, 5, 6], 59 | [9, 6, 1, 5, 3, 7, 2, 8, 4], 60 | [2, 8, 7, 4, 1, 9, 6, 3, 5], 61 | [3, 4, 7, 2, 8, 6, 1, 5, 9]] 62 | 63 | assert not check_sudoku_is_valid(not_valid_sudoku) 64 | 65 | if __name__ == '__main__': 66 | run_tests() 67 | -------------------------------------------------------------------------------- /calculator/basic_calc.py: -------------------------------------------------------------------------------- 1 | from operator import add, truediv, imul, isub 2 | 3 | 4 | class OpStr(object): 5 | ADD = "+" 6 | SUB = "-" 7 | MUL = "*" 8 | DIV = "/" 9 | PAR_L = "(" 10 | PAR_R = ")" 11 | 12 | class BasicCalculator(object): 13 | def __init__(self): 14 | self.operator_to_action = { 15 | OpStr.ADD: add, 16 | OpStr.SUB: isub, 17 | OpStr.MUL: imul, 18 | OpStr.DIV: truediv 19 | } 20 | 21 | def __eval_expression(self, arg_1, operator, arg_2): 22 | action = self.operator_to_action[operator] 23 | return action(arg_1, arg_2) 24 | 25 | def __evaluate_next_val_and_get_length(self, exp_arr, index): 26 | sub_exp_length = 2 27 | val = exp_arr[index + 1] 28 | if val == OpStr.PAR_L: 29 | sub_exp_length, val = self.__solve_expression_wrap(exp_arr[index + 2:]) 30 | return sub_exp_length, val 31 | 32 | def __solve_expression(self, exp_arr, current_operators): 33 | new_exp = [exp_arr[0]] 34 | i = 1 35 | while i < len(exp_arr): 36 | operator = exp_arr[i] 37 | if operator == OpStr.PAR_R: 38 | current_exp_length = i + 2 39 | return current_exp_length, new_exp 40 | 41 | sub_exp_length, val = self.__evaluate_next_val_and_get_length(exp_arr, i) 42 | 43 | if operator in current_operators: 44 | res = self.__eval_expression(new_exp.pop(), operator, val) 45 | new_exp.append(res) 46 | else: 47 | new_exp.append(operator) 48 | new_exp.append(val) 49 | 50 | i += sub_exp_length 51 | 52 | return len(exp_arr), new_exp 53 | 54 | def __solve_expression_wrap(self, exp_arr): 55 | sub_exp_length, exp_arr = self.__solve_expression(exp_arr, [OpStr.MUL, OpStr.DIV]) 56 | _, exp_arr = self.__solve_expression(exp_arr, [OpStr.ADD, OpStr.SUB]) 57 | return sub_exp_length + 1, exp_arr[0] 58 | 59 | def solve(self, exp_arr): 60 | sub_exp_length, res = self.__solve_expression_wrap(exp_arr) 61 | return res 62 | 63 | 64 | def run_tests(): 65 | calc = BasicCalculator() 66 | assert calc.solve([1, "+", 2]) == 3 67 | assert calc.solve([1, "-", 2]) == -1 68 | assert calc.solve([2, "*", "(", 1, "+", 3, ")"]) == 8 69 | assert calc.solve([2, "*", "(", 1, "+", 6, "/", 3, ")"]) == 6 70 | assert calc.solve([2, "*", "(", 1, "+", 6, "/", 3, ")", "-", "(", 5, "*", 2, ")"]) == -4 71 | assert calc.solve([2, "+", "(", 3, "*", "(", 8, "/", 2, ")", "-", 10, ")"]) == 4 72 | 73 | 74 | if __name__ == '__main__': 75 | run_tests() 76 | -------------------------------------------------------------------------------- /ice_cream.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/18/ice-cream/ 2 | 3 | class IceCreamChooser(object): 4 | def __init__(self, ice_cream_costs): 5 | self.ice_cream_costs = ice_cream_costs 6 | 7 | def choose_ice_cream_once(self, money): 8 | raise NotImplementedError 9 | 10 | def choose_ice_cream(self, money_sums): 11 | results = [] 12 | for money in money_sums: 13 | results.append(self.choose_ice_cream_once(money)) 14 | return results 15 | 16 | 17 | class IceCreamChooseLimitedVisits(IceCreamChooser): 18 | def choose_ice_cream_once(self, money): 19 | diff_to_cost = {} 20 | for i in range(0, len(self.ice_cream_costs)): 21 | cost = self.ice_cream_costs[i] 22 | if cost in diff_to_cost: 23 | return diff_to_cost[cost], i 24 | else: 25 | diff = money - cost 26 | diff_to_cost[diff] = i 27 | 28 | 29 | class IceCreamChooseManyVisits(IceCreamChooser): 30 | def __init__(self, ice_cream_costs): 31 | super(IceCreamChooseManyVisits, self).__init__(ice_cream_costs) 32 | self.all_possible_costs_sums = self.preprocess_ice_cream_costs() 33 | 34 | def preprocess_ice_cream_costs(self): 35 | all_possible_costs_sums = {} 36 | for i in range(0, len(self.ice_cream_costs)): 37 | for j in range(i + 1, len(self.ice_cream_costs)): 38 | costs_sum = self.ice_cream_costs[i] + self.ice_cream_costs[j] 39 | all_possible_costs_sums[costs_sum] = (i, j) 40 | 41 | return all_possible_costs_sums 42 | 43 | def choose_ice_cream_once(self, money): 44 | return self.all_possible_costs_sums[money] 45 | 46 | 47 | def choose_ice_cream_flavours(ice_cream_costs, money_sums): 48 | if len(money_sums) >= len(ice_cream_costs): 49 | return IceCreamChooseManyVisits(ice_cream_costs).choose_ice_cream(money_sums) 50 | else: 51 | return IceCreamChooseLimitedVisits(ice_cream_costs).choose_ice_cream(money_sums) 52 | 53 | 54 | def run_tests(): 55 | assert choose_ice_cream_flavours([2, 5, 3, 1], [3, 8]) == [(0, 3), (1, 2)] 56 | assert choose_ice_cream_flavours([2, 5, 3, 1], [3, 8, 7, 6, 5]) == [(0, 3), (1, 2), (0, 1), (1, 3), (0, 2)] 57 | assert choose_ice_cream_flavours([2, 5, 3.5, 4, 4.5, 1.5, 2.5, 0.5], [3, 8]) == [(6, 7), (2, 4)] 58 | assert choose_ice_cream_flavours([1, 2, 3], [3, 3, 3, 4, 5, 3, 4]) == [(0, 1), (0, 1), (0, 1), (0, 2), (1, 2), 59 | (0, 1), (0, 2)] 60 | assert choose_ice_cream_flavours([2, 5, 3.5, 4, 4.5, 1.5, 2.5, 0.5], [3.5]) == [(0,5)] 61 | 62 | 63 | 64 | if __name__ == '__main__': 65 | run_tests() 66 | -------------------------------------------------------------------------------- /four_in_a_row/board.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/just-code/connect-four-game-in-python/ 2 | 3 | from enum import Enum 4 | 5 | ROWS = 6 6 | COLUMNS = 9 7 | 8 | 9 | class Color(Enum): 10 | EMPTY = 0 11 | RED = 1 12 | BLUE = 2 13 | 14 | def __str__(self): 15 | return '%s' % self.value 16 | 17 | 18 | class BoardUtils: 19 | 20 | @staticmethod 21 | def get_row_vector(board, row, column): 22 | start = max(0, column - 3) 23 | end = min(board.columns-1, column + 3) 24 | vector = [] 25 | for c in range(start, end + 1): 26 | vector.append(board.get(row, c)) 27 | return vector 28 | 29 | @staticmethod 30 | def get_column_vector(board, row, column): 31 | start = max(0, row - 3) 32 | end = min(board.rows-1, row + 3) 33 | vector = [] 34 | for r in range(start, end + 1): 35 | vector.append(board.get(r, column)) 36 | return vector 37 | 38 | @staticmethod 39 | def get_positive_diagonal_vector(board, row, column): 40 | start_row = row - 3 41 | start_column = column - 3 42 | 43 | end_row = row + 3 44 | end_column = column + 3 45 | vector = [] 46 | 47 | r = start_row 48 | c = start_column 49 | while r <= end_row and c <= end_column: 50 | vector.append(board.get(r, c)) 51 | r += 1 52 | c += 1 53 | return vector 54 | 55 | @staticmethod 56 | def get_negative_diagonal_vector(board, row, column): 57 | start_row = row + 3 58 | start_column = column - 3 59 | 60 | end_row = row - 3 61 | end_column = column + 3 62 | vector = [] 63 | 64 | r = start_row 65 | c = start_column 66 | while r >= end_row and c <= end_column: 67 | vector.append(board.get(r, c)) 68 | r -= 1 69 | c += 1 70 | return vector 71 | 72 | 73 | class Board: 74 | def __init__(self, rows=ROWS, columns=COLUMNS, state=None): 75 | self.rows = rows 76 | self.columns = columns 77 | if state is None: 78 | self.init_empty_board() 79 | else: 80 | self.state = state 81 | 82 | def __repr__(self): 83 | result = "" 84 | for r in range(self.rows - 1, -1, -1): 85 | row = " ".join([str(self.state[r][c]) for c in range(0, self.columns)]) 86 | result += row + '\n' 87 | return '\n' + result + '\n' 88 | 89 | def init_empty_board(self): 90 | self.state = [[Color.EMPTY for _ in range(0, self.columns)] for _ in range(0, self.rows)] 91 | 92 | @classmethod 93 | def read(cls, input_board): 94 | rows = len(input_board) 95 | columns = len(input_board[0]) 96 | board_state = [] 97 | for r in range(rows - 1, -1, -1): 98 | board_state.append(input_board[r]) 99 | return Board(rows, columns, board_state) 100 | 101 | def get(self, r, c): 102 | return self.state[r][c] if r >=0 and r < self.rows and c >= 0 and c < self.columns else Color.EMPTY 103 | 104 | def set(self, r, c, val): 105 | self.state[r][c] = val 106 | -------------------------------------------------------------------------------- /matrix_sums.py: -------------------------------------------------------------------------------- 1 | class MatrixPosistion(object): 2 | def __init__(self,i,j): 3 | self.i = i 4 | self.j = j 5 | 6 | class MatrixSums(object): 7 | def __init__(self): 8 | self.sums_matrix = None 9 | self.rows = 0 10 | self.columns = 0 11 | 12 | def sum(self, pos_a,pos_b): 13 | pos_b_sum = self.get_cell_value(pos_b) 14 | left_mat_sum = self.get_cell_value(MatrixPosistion(pos_b.i, pos_a.j-1)) 15 | top_mat_sum = self.get_cell_value(MatrixPosistion(pos_a.i-1,pos_b.j)) 16 | corner_mat_sum = self.get_cell_value(MatrixPosistion(pos_a.i-1, pos_a.j-1)) 17 | 18 | return pos_b_sum - left_mat_sum - top_mat_sum + corner_mat_sum 19 | 20 | def get(self, pos_a): 21 | return self.sum(pos_a, pos_a) 22 | 23 | def set(self,pos,val): 24 | original_set_value = self.get(pos) 25 | diff = val - original_set_value 26 | for i in range(pos.i,self.rows): 27 | for j in range(pos.j,self.columns): 28 | self.sums_matrix[i][j] += diff 29 | 30 | def init_sums_matrix(self, base_matrix): 31 | self.rows = len(base_matrix) 32 | self.columns = len(base_matrix[0]) 33 | self.sums_matrix = [] 34 | for i in range(0,self.rows): 35 | self.sums_matrix.append(list()) 36 | for j in range(0,self.columns): 37 | self.sums_matrix[i].append(0) 38 | 39 | for i in range(self.rows-1,-1,-1): 40 | for j in range(self.columns-1,-1,-1): 41 | self.set(MatrixPosistion(i,j),base_matrix[i][j]) 42 | 43 | def get_cell_value(self,pos): 44 | if pos.i < 0: 45 | return 0 46 | if pos.j < 0: 47 | return 0 48 | return self.sums_matrix[pos.i][pos.j] 49 | 50 | 51 | def run_tests(): 52 | t = MatrixSums() 53 | 54 | # [1] 55 | t.init_sums_matrix([[1]]) 56 | assert t.get(MatrixPosistion(0, 0)) == 1 57 | assert t.sum(MatrixPosistion(0, 0),MatrixPosistion(0, 0)) == 1 58 | t.set(MatrixPosistion(0, 0),5) 59 | assert t.get(MatrixPosistion(0, 0)) == 5 60 | assert t.sum(MatrixPosistion(0, 0),MatrixPosistion(0, 0)) == 5 61 | 62 | # [[1,2,3] 63 | # [2,0,1]] 64 | t.init_sums_matrix([[1, 2, 3], [2, 0, 1]]) 65 | assert t.get(MatrixPosistion(0, 0)) == 1 66 | assert t.get(MatrixPosistion(0, 2)) == 3 67 | assert t.sum(MatrixPosistion(0, 0), MatrixPosistion(0, 2)) == 6 68 | assert t.get(MatrixPosistion(1, 2)) == 1 69 | assert t.sum(MatrixPosistion(1, 1), MatrixPosistion(1, 2)) == 1 70 | 71 | # [[1,0,3] 72 | # [2,0,1]] 73 | t.set(MatrixPosistion(0, 1), 0) 74 | assert t.get(MatrixPosistion(0, 1)) == 0 75 | assert t.get(MatrixPosistion(0, 2)) == 3 76 | assert t.sum(MatrixPosistion(0, 0), MatrixPosistion(0, 2)) == 4 77 | assert t.sum(MatrixPosistion(0, 0), MatrixPosistion(1, 2)) == 7 78 | assert t.get(MatrixPosistion(1, 2)) == 1 79 | assert t.sum(MatrixPosistion(1, 1), MatrixPosistion(1, 2)) == 1 80 | 81 | # [[5,2,3] 82 | # [2,0,1]] 83 | t.set(MatrixPosistion(0, 1), 2) 84 | t.set(MatrixPosistion(0, 0), 5) 85 | assert t.get(MatrixPosistion(0, 0)) == 5 86 | assert t.get(MatrixPosistion(0, 2)) == 3 87 | assert t.sum(MatrixPosistion(0, 0), MatrixPosistion(0, 2)) == 10 88 | assert t.sum(MatrixPosistion(0, 0), MatrixPosistion(1, 2)) == 13 89 | assert t.get(MatrixPosistion(1, 2)) == 1 90 | assert t.sum(MatrixPosistion(1, 1), MatrixPosistion(1, 2)) == 1 91 | 92 | 93 | if __name__ == '__main__': 94 | run_tests() -------------------------------------------------------------------------------- /maze.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/18/maze-path/ 2 | 3 | class MazeCell(object): 4 | def __init__(self, i, j, is_wall=False, is_exit=False): 5 | self.i = i 6 | self.j = j 7 | self.visited = False 8 | self.is_wall = is_wall 9 | self.is_exit = is_exit 10 | 11 | def __eq__(self, other): 12 | return self.i == other.i and self.j == other.j 13 | 14 | def __repr__(self): 15 | repr = "%d,%d" % (self.i, self.j) 16 | if self.visited: 17 | repr += ',visited' 18 | if self.is_exit: 19 | repr += ' (EXIT)' 20 | return repr 21 | 22 | 23 | class Maze(object): 24 | def __init__(self, maze_matrix): 25 | self.maze = maze_matrix 26 | self.cells_cache = {} 27 | self.rows = len(maze_matrix) 28 | self.columns = len(maze_matrix[0]) 29 | 30 | def find_path_to_exit_in_maze(self, start_cell): 31 | path = [start_cell] 32 | while len(path) > 0: 33 | current_cell = path[-1] 34 | current_cell.visited = True 35 | 36 | adjacent_cell = self.get_available_adjacent_cell(current_cell) 37 | if adjacent_cell is None: 38 | path.pop() 39 | else: 40 | path.append(adjacent_cell) 41 | if adjacent_cell.is_exit: 42 | return path 43 | return -1 44 | 45 | def get_cell(self, i, j): 46 | if (i,j) not in self.cells_cache: 47 | self.cells_cache[(i,j)] = MazeCell(i, j, self.maze[i][j] == 1, self.maze[i][j] == "EXIT") 48 | return self.cells_cache[(i,j)] 49 | 50 | def get_available_adjacent_cell(self, cell): 51 | for (i, j) in [(cell.i - 1, cell.j), (cell.i, cell.j - 1), (cell.i + 1, cell.j), (cell.i, cell.j + 1)]: 52 | if 0 <= i < self.rows and 0 <= j < self.columns: 53 | adj = self.get_cell(i,j) 54 | if adj.visited or adj.is_wall: 55 | continue 56 | else: 57 | return adj 58 | 59 | return None 60 | 61 | 62 | def run_tests(): 63 | maze_matrix = [[1, "ENTERANEC", 1, 1], 64 | [1, 0, 0, 1], 65 | [1, 0, 1, 1], 66 | [1, 0, 0, 1], 67 | [1, 1, "EXIT", 1]] 68 | maze = Maze(maze_matrix) 69 | expected_path = [MazeCell(0, 1), MazeCell(1, 1), MazeCell(2, 1), MazeCell(3, 1), MazeCell(3, 2), 70 | MazeCell(4, 2, is_exit=True)] 71 | assert maze.find_path_to_exit_in_maze(MazeCell(0, 1)) == expected_path 72 | 73 | maze_matrix = [[1, "ENTERANEC", 1, 1], 74 | [1, 0, 0, 1], 75 | [1, 1, 1, 1], 76 | [1, 0, 0, 1], 77 | [1, 1, "EXIT", 1]] 78 | maze = Maze(maze_matrix) 79 | assert maze.find_path_to_exit_in_maze(MazeCell(0, 1)) == -1 80 | 81 | maze_matrix = [[1, "ENTERANEC", 1, 1], 82 | [1, 1, "EXIT", 1]] 83 | maze = Maze(maze_matrix) 84 | assert maze.find_path_to_exit_in_maze(MazeCell(0, 1)) == -1 85 | 86 | maze_matrix = [[1, "ENTERANEC", 1, 1], 87 | [1, "EXIT", 1, 1]] 88 | maze = Maze(maze_matrix) 89 | expected_path = [MazeCell(0, 1), MazeCell(1, 1, is_exit=True)] 90 | assert maze.find_path_to_exit_in_maze(MazeCell(0, 1)) == expected_path 91 | 92 | maze_matrix = [["ENTERANEC", 0, 0, "EXIT"]] 93 | maze = Maze(maze_matrix) 94 | expected_path = [MazeCell(0, 0), MazeCell(0, 1), MazeCell(0, 2), MazeCell(0,3, is_exit=True)] 95 | assert maze.find_path_to_exit_in_maze(MazeCell(0, 0)) == expected_path 96 | 97 | 98 | if __name__ == '__main__': 99 | run_tests() 100 | -------------------------------------------------------------------------------- /paint_and_fill.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/06/24/paint-and-fill/ 2 | 3 | from termcolor import colored 4 | 5 | class Position(object): 6 | def __init__(self, x, y): 7 | self.x = x 8 | self.y = y 9 | 10 | def get_neighbours(self): 11 | return [ 12 | Position(self.x - 1, self.y), 13 | Position(self.x + 1, self.y), 14 | Position(self.x, self.y - 1), 15 | Position(self.x, self.y + 1) 16 | ] 17 | 18 | 19 | class Screen(object): 20 | def __init__(self, base_mat): 21 | self.mat = base_mat 22 | 23 | def get_color(self, pos): 24 | return self.mat[pos.x][pos.y] 25 | 26 | def set_color(self, pos, new_color): 27 | self.mat[pos.x][pos.y] = new_color 28 | 29 | def pos_in_bounds(self, pos): 30 | return 0 <= pos.x < len(self.mat) and 0 <= pos.y < len(self.mat[0]) 31 | 32 | def get_neighbour(self, pos, old_color): 33 | possible_neighbours = pos.get_neighbours() 34 | for neighbour in possible_neighbours: 35 | if self.pos_in_bounds(neighbour) and self.get_color(neighbour) == old_color: 36 | return neighbour 37 | 38 | def print(self): 39 | for i in range(0, len(self.mat)): 40 | row = "" 41 | for j in range(0, len(self.mat[0])): 42 | row += colored("\u2588", self.get_color(Position(i, j))) 43 | print(row) 44 | 45 | def paint_and_fill_recur(self, pos, new_color, old_color): 46 | self.set_color(pos, new_color) 47 | next_neighbour = self.get_neighbour(pos, old_color) 48 | while next_neighbour: 49 | self.paint_and_fill_recur(next_neighbour, new_color, old_color) 50 | next_neighbour = self.get_neighbour(pos, old_color) 51 | 52 | def paint_and_fill(self, pos, new_color): 53 | if self.get_color(pos) != new_color: 54 | self.paint_and_fill_recur(pos, new_color, self.get_color(pos)) 55 | 56 | class Colors(object): 57 | W = 'white' 58 | B = 'blue' 59 | G = 'green' 60 | M = 'magenta' 61 | R = 'red' 62 | 63 | def run_tests(): 64 | A = Screen([[Colors.W, Colors.W, Colors.R]]) 65 | print("Before:") 66 | A.print() 67 | A.paint_and_fill(Position(0,0), Colors.B) 68 | print("Paint and fill from (0,0) in blue:") 69 | A.print() 70 | 71 | A = Screen([[Colors.R]]) 72 | print("Before:") 73 | A.print() 74 | A.paint_and_fill(Position(0,0), Colors.B) 75 | print("Paint and fill from (0,0) in blue:") 76 | A.print() 77 | 78 | A = Screen([[Colors.W, Colors.W, Colors.W], [Colors.W, Colors.B, Colors.W], [Colors.W, Colors.W, Colors.W]]) 79 | print("Before:") 80 | A.print() 81 | A.paint_and_fill(Position(0,0), Colors.B) 82 | print("Paint and fill from (0,0) in blue:") 83 | A.print() 84 | A.paint_and_fill(Position(1,1), Colors.M) 85 | print("Paint and fill from (1,1) in pink:") 86 | A.print() 87 | 88 | A = Screen([[Colors.W, Colors.W, Colors.W], [Colors.W, Colors.B, Colors.W], [Colors.W, Colors.W, Colors.W]]) 89 | print("Before:") 90 | A.print() 91 | A.paint_and_fill(Position(2,2), Colors.M) 92 | print("Paint and fill from (2,2) in pink:") 93 | A.print() 94 | A.paint_and_fill(Position(1,1), Colors.W) 95 | print("Paint and fill from (1,1) in white:") 96 | A.print() 97 | 98 | A = Screen([[Colors.W, Colors.W, Colors.W], [Colors.W, Colors.W, Colors.W], [Colors.B, Colors.W, Colors.B]]) 99 | print("Before:") 100 | A.print() 101 | A.paint_and_fill(Position(0, 0), Colors.G) 102 | print("Paint and fill from (0,0) in Green:") 103 | A.print() 104 | 105 | if __name__ == '__main__': 106 | run_tests() -------------------------------------------------------------------------------- /coins_and_weights.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/2019/07/09/coins-and-weights/ 2 | 3 | class Scale(object): 4 | def __init__(self): 5 | self.weigh_count = 0 6 | 7 | def weigh(self, coins_x, coins_y): 8 | self.weigh_count += 1 9 | if sum(coins_x) > sum(coins_y): 10 | return 1 11 | elif sum(coins_y) > sum(coins_x): 12 | return -1 13 | else: 14 | return 0 15 | 16 | class CoinsAndWeights(object): 17 | def __init__(self): 18 | self.scale = Scale() 19 | 20 | @staticmethod 21 | def divide_group_to_three(group): 22 | groups_size = int(len(group)/3) 23 | groups = [] 24 | for i in range(0, 3): 25 | groups.append(group[groups_size * i: groups_size * (i + 1)]) 26 | return groups 27 | 28 | @staticmethod 29 | def add_regular_coins_to_odd_group(odd_group, control_group): 30 | if len(odd_group) % 3 == 1: 31 | odd_group.extend(control_group[0:2]) 32 | elif len(odd_group) % 3 == 2: 33 | odd_group.extend(control_group[0:1]) 34 | 35 | def find_odd_group(self, coins, odd_coin_weight): 36 | x, y, z = self.divide_group_to_three(coins) 37 | first_weigh = self.scale.weigh(x, y) 38 | if first_weigh == 0: 39 | return z 40 | else: 41 | if first_weigh == odd_coin_weight: 42 | return x 43 | else: 44 | return y 45 | 46 | def find_odd_group_and_odd_weight(self, coins): 47 | x, y, z = self.divide_group_to_three(coins) 48 | first_weigh = self.scale.weigh(x, y) 49 | second_weigh = self.scale.weigh(x, z) 50 | 51 | if first_weigh == 0 and second_weigh == 0: 52 | return None, None, None 53 | 54 | if first_weigh == 0: 55 | odd_group = z 56 | control_group = x 57 | odd_coin_weight = -1 * second_weigh 58 | elif second_weigh == 0: 59 | odd_group = y 60 | control_group = x 61 | odd_coin_weight = -1 * first_weigh 62 | else: 63 | odd_group = x 64 | control_group = y 65 | odd_coin_weight = first_weigh 66 | return odd_group, control_group, odd_coin_weight 67 | 68 | def find_odd_coin(self, coins): 69 | coins_remainder_group_size = len(coins) % 3 70 | main_groups_size = len(coins) - coins_remainder_group_size 71 | 72 | coins_remainder_group = coins[main_groups_size:] 73 | coins = coins[:main_groups_size] 74 | 75 | odd_group, control_group, odd_coin_weight = \ 76 | self.find_odd_group_and_odd_weight(coins) 77 | 78 | if odd_group is None: 79 | # odd coin is in the remainder group 80 | self.add_regular_coins_to_odd_group(coins_remainder_group, coins) 81 | odd_group, _, _ = self.find_odd_group_and_odd_weight(coins_remainder_group) 82 | return odd_group[0] 83 | 84 | while len(odd_group) > 1: 85 | self.add_regular_coins_to_odd_group(odd_group, control_group) 86 | odd_group = self.find_odd_group(odd_group, odd_coin_weight) 87 | 88 | return odd_group[0] 89 | 90 | def run_tests(): 91 | caw = CoinsAndWeights() 92 | coins = [0, 0, 1] 93 | assert caw.find_odd_coin(coins) == 1 94 | assert caw.scale.weigh_count == 2 95 | 96 | caw = CoinsAndWeights() 97 | coins = [0, 1, 1] 98 | assert caw.find_odd_coin(coins) == 0 99 | assert caw.scale.weigh_count == 2 100 | 101 | caw = CoinsAndWeights() 102 | coins = [1] * 27 103 | coins[10] = 3 104 | assert caw.find_odd_coin(coins) == 3 105 | assert caw.scale.weigh_count == 4 106 | 107 | caw = CoinsAndWeights() 108 | coins = [1] * 28 109 | coins[27] = -1 110 | assert caw.find_odd_coin(coins) == -1 111 | assert caw.scale.weigh_count == 4 112 | 113 | caw = CoinsAndWeights() 114 | coins = [1] * 100000 115 | coins[9007] = 3 116 | assert caw.find_odd_coin(coins) == 3 117 | assert caw.scale.weigh_count == 12 118 | 119 | 120 | if __name__ == '__main__': 121 | run_tests() -------------------------------------------------------------------------------- /four_in_a_row/tests.py: -------------------------------------------------------------------------------- 1 | # Related blog post - https://algoritmim.co.il/just-code/connect-four-game-in-python/ 2 | 3 | from four_in_a_row.board import Board, Color 4 | from four_in_a_row.logic import add_disc, is_win 5 | 6 | 7 | def test_add_disc(): 8 | board = Board() 9 | for i in range(0, board.columns): 10 | add_disc(Color.BLUE, board, i) 11 | assert board.get(0, i) == Color.BLUE 12 | 13 | add_disc(Color.RED, board, 1) 14 | assert (board.get(1, 0)) is Color.EMPTY 15 | assert (board.get(1, 1)) is Color.RED 16 | assert (board.get(1, 2)) is Color.EMPTY 17 | 18 | 19 | def test_is_win_basic(): 20 | board = Board() 21 | for i in range(0, 4): 22 | add_disc(Color.BLUE, board, i) 23 | for i in range(0, 4): 24 | assert (is_win(board, 0, i) is True) 25 | 26 | board = Board() 27 | for _ in range(0, 4): 28 | add_disc(Color.RED, board, 3) 29 | for i in range(0, 4): 30 | assert (is_win(board, i, 3) is True) 31 | 32 | 33 | def test_winning_boards(): 34 | winning_boards_data = [ 35 | { 36 | 'board_state': 37 | [[0, 0, 0, 0, 0], 38 | [0, 0, 0, 0, 0], 39 | [0, 0, 0, 0, 0], 40 | [1, 1, 1, 1, 0]], 41 | 'pos_r': 0, 42 | 'pos_c': 3 43 | }, 44 | { 45 | 'board_state': 46 | [[0, 0, 0, 0, 0, 0, 0], 47 | [0, 0, 0, 0, 0, 0, 0], 48 | [0, 0, 0, 0, 0, 0, 0], 49 | [1, 1, 0, 1, 1, 1, 1]], 50 | 'pos_r': 0, 51 | 'pos_c': 3 52 | }, 53 | { 54 | 'board_state': 55 | [[0, 0, 0, 0, 0], 56 | [0, 0, 0, 0, 0], 57 | [0, 0, 0, 0, 0], 58 | [0, 1, 1, 1, 1]], 59 | 'pos_r': 0, 60 | 'pos_c': 3 61 | }, 62 | { 63 | 'board_state': 64 | [[0, 2, 0, 0, 0], 65 | [0, 2, 0, 0, 0], 66 | [0, 2, 0, 0, 0], 67 | [0, 2, 1, 1, 1]], 68 | 'pos_r': 3, 69 | 'pos_c': 1 70 | }, 71 | { 72 | 'board_state': 73 | [[0, 2, 0, 0, 2], 74 | [0, 1, 0, 2, 2], 75 | [0, 2, 2, 1, 2], 76 | [0, 2, 1, 1, 1]], 77 | 'pos_r': 1, 78 | 'pos_c': 2 79 | }, 80 | { 81 | 'board_state': 82 | [[0, 1, 2, 0, 0], 83 | [0, 2, 1, 0, 2], 84 | [0, 1, 2, 1, 1], 85 | [0, 2, 2, 1, 1]], 86 | 'pos_r': 3, 87 | 'pos_c': 1 88 | }, 89 | { 90 | 'board_state': 91 | [[0, 0, 0, 0, 2], 92 | [2, 1, 0, 2, 2], 93 | [1, 2, 1, 1, 2], 94 | [2, 2, 1, 1, 2]], 95 | 'pos_r': 3, 96 | 'pos_c': 4 97 | } 98 | ] 99 | for entry in winning_boards_data: 100 | board = Board.read(entry['board_state']) 101 | assert (is_win(board, entry['pos_r'], entry['pos_c']) is True) 102 | 103 | 104 | def test_no_win_boards(): 105 | winning_boards_data = [ 106 | { 107 | 'board_state': 108 | [[0, 0, 0, 0, 0], 109 | [0, 0, 0, 0, 0], 110 | [0, 0, 0, 0, 0], 111 | [1, 2, 1, 1, 1]], 112 | 'pos_r': 0, 113 | 'pos_c': 3 114 | }, 115 | { 116 | 'board_state': 117 | [[0, 0, 0, 0, 0], 118 | [0, 0, 0, 0, 0], 119 | [0, 0, 0, 0, 0], 120 | [0, 1, 1, 1, 0]], 121 | 'pos_r': 0, 122 | 'pos_c': 3 123 | }, 124 | { 125 | 'board_state': 126 | [[0, 2, 0, 0, 0], 127 | [0, 1, 0, 0, 0], 128 | [0, 2, 0, 0, 0], 129 | [0, 2, 1, 1, 1]], 130 | 'pos_r': 3, 131 | 'pos_c': 1 132 | }, 133 | { 134 | 'board_state': 135 | [[0, 2, 0, 0, 2], 136 | [0, 1, 0, 2, 2], 137 | [0, 2, 1, 1, 2], 138 | [0, 2, 1, 1, 1]], 139 | 'pos_r': 3, 140 | 'pos_c': 4 141 | }, 142 | { 143 | 'board_state': 144 | [[0, 2, 0, 0, 2], 145 | [2, 1, 0, 2, 2], 146 | [1, 2, 1, 1, 2], 147 | [2, 2, 1, 1, 1]], 148 | 'pos_r': 2, 149 | 'pos_c': 1 150 | }, 151 | { 152 | 'board_state': 153 | [[0, 0, 0, 0, 0], 154 | [2, 1, 0, 2, 2], 155 | [1, 2, 1, 1, 2], 156 | [2, 2, 1, 1, 2]], 157 | 'pos_r': 2, 158 | 'pos_c': 4 159 | } 160 | ] 161 | for entry in winning_boards_data: 162 | board = Board.read(entry['board_state']) 163 | assert (is_win(board, entry['pos_r'], entry['pos_c']) is False) 164 | 165 | 166 | if __name__ == '__main__': 167 | test_add_disc() 168 | test_is_win_basic() 169 | test_winning_boards() 170 | test_no_win_boards() 171 | -------------------------------------------------------------------------------- /data.txt: -------------------------------------------------------------------------------- 1 | b'\n\t\n\t\n\n\n\t\t\n\t\tPastes Archive - Pastebin.com\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\n \n\t\t\n\t\t\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\t\t\n\t\t\n\t\n\t\n\t
\n\t\t
\n\t\t\t\n\t\t
\n\t\t\n\t\t
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t
\t\t\t\t\t\t\n\n\t
\r\n\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t
\t
\n\t\r\n\t\t\t
\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t
\n
\n\t
\n\t
\n\t\t\t\t\t\n\t\t\r\n\t\t\t
\r\n\t\t\t\r\n\t\t\t
\r\n\t
Pastes Archive
\r\n\t
\r\n\t\t
This page contains the most recently created \'public\' pastes.
\r\n\t
\r\n\t\t
\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t
Name / TitlePostedSyntax
Untitled3 sec agoC#
Untitled12 sec ago-
Untitled18 sec ago-
Untitled18 sec ago-
Untitled22 sec ago-
Untitled29 sec ago-
Untitled50 sec ago-
Untitled34 sec ago-
Naked photos from Patricia37 sec ago-
Untitled39 sec ago-
Untitled42 sec ago-
Untitled49 sec ago-
Untitled51 sec agoC++
Untitled54 sec ago-
Untitled59 sec ago-
Untitled59 sec ago-
Untitled1 min ago-
Untitled1 min ago-
Radio Emisoras Candela Sa2 min ago-
Untitled1 min ago-
Untitled1 min ago-
Untitled1 min ago-
Coco2 min ago-
\xf0\x9f\x92\x9aDirty secret from Mary1 min ago-
Untitled2 min ago-
Untitled2 min ago-
Dirty secret from Patricia2 min ago-
Untitled2 min ago-
Untitled2 min ago-
Go fest 3602 min ago-
cr\xc3\xa9dits2 min ago-
Untitled2 min ago-
Untitled2 min agoLua
Untitled2 min ago-
Untitled2 min ago-
Untitled2 min ago-
Untitled2 min ago-
Untitled3 min ago-
Naked photos from Patricia3 min ago-
Erotic photos from Patricia3 min ago-
Untitled3 min ago-
Untitled3 min ago-
Untitled3 min ago-
Attached intimate photos from Karen3 min ago-
Untitled3 min ago-
Untitled3 min ago-
Untitled3 min ago-
Untitled3 min ago-
Untitled3 min ago-
\r\n\t\t
\r\n\t\r\n\t
\t\t\r\n\t\t
\r\n\t\t\tWe use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand\r\n\t\t
\r\n\t\t
\r\n\t\t\t\t\t\t\r\n\t\t\t
\r\n\t\t\t
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
\r\n\t\t\t
 
\r\n\t\t
\t\t\t\t\t\t
\r\n\t\t\t\t\t
\r\n\t\t\t\t
\r\n\t\t\t
\r\n\t\t\t \r\n\t\t
\r\n\t\t\r\n\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t
Top\r\n\t\t\r\n\t\r\n\t\t\r\n\t\r\n' --------------------------------------------------------------------------------