From 71b6090aba230c0eb5ac0ad25221ed78675982ba Mon Sep 17 00:00:00 2001 From: Dmitry Tsuprunov Date: Sat, 14 Sep 2019 22:28:39 -0400 Subject: [PATCH 1/2] Added frog jump calculator --- frog-jumps-calc.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 frog-jumps-calc.py diff --git a/frog-jumps-calc.py b/frog-jumps-calc.py new file mode 100644 index 0000000..4532b25 --- /dev/null +++ b/frog-jumps-calc.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" + File name: frog-jumps-calc.py + Author: Dmitry Tsuprunov + Date created: September 14, 2019 + Python Version: 3.7 +""" +import sys + + +def memo(fn): + """ + Memoizing all the things + """ + cache = {} + + def memo_fn(*args): + cached_val = cache.get(args) + if cached_val: + return cached_val + cached_val = fn(*args) + cache[args] = cached_val + return cached_val + + return memo_fn + + +def possible_jumps(distance, jumps_made=0): + """ + Calculates total number of jumps for all possible paths + """ + if distance == 0: + return jumps_made + total_jumps = 0 + for i in range(distance): + total_jumps += memo_possible_jumps(i, jumps_made + 1.0) + return total_jumps + + +memo_possible_jumps = memo(possible_jumps) + + +def possible_paths(distance): + """ + Calculating total number of possible paths + """ + if distance == 0: + return 1.0 + total = 0 + for i in range(distance): + total += memo_possible_paths(i) + return total + + +memo_possible_paths = memo(possible_paths) + + +def expected_jumps(distance): + if distance == 0: + return 0 + return possible_jumps(distance) / possible_paths(distance) + + +if __name__ == "__main__": + try: + arg = int(sys.argv[1]) + except: + arg = 10 + for i in range(1, arg + 1): + num_expected_jumps = expected_jumps(i) + # uncomment line below to make sure that expected number of jumps + # is equal to (distance + 1) / 2 + # tested up to a distance of 498 jumps + # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + # if (float(i)+1)/2 != num_expected_jumps: + # print('', i, num_expected_jumps) + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + # This line will print all values for all paths up to selected number + # Feel free to test with >>> python3 frog-jumps-calc.py {distance} + num_possible_paths = possible_paths(i) + num_possible_jumps = possible_jumps(i) + print(f"For a distance {i} there're {num_possible_paths} possible paths " + f"containing {num_possible_jumps} jumps " + f"with expected jumps equal to {num_expected_jumps}.") From 68bd7e6fb9ce5e6fd15f8d1e4114cadd40e9fc40 Mon Sep 17 00:00:00 2001 From: Dmitry Tsuprunov Date: Sat, 14 Sep 2019 23:54:36 -0400 Subject: [PATCH 2/2] Added probability --- frog-jumps-calc.py | 59 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/frog-jumps-calc.py b/frog-jumps-calc.py index 4532b25..a01b71d 100644 --- a/frog-jumps-calc.py +++ b/frog-jumps-calc.py @@ -55,31 +55,54 @@ def possible_paths(distance): memo_possible_paths = memo(possible_paths) -def expected_jumps(distance): +# def expected_jumps(distance): +# if distance == 0: +# return 0 +# return possible_jumps(distance) / possible_paths(distance) + + +def expected_jumps(distance, jumps_made=0, probability=1.0): + """ + Calculates expected number of jumps for all possible paths + Probability of jumps for each step calculated recursively + by dividing probability for current jump by possible number of following jumps + """ if distance == 0: - return 0 - return possible_jumps(distance) / possible_paths(distance) + return jumps_made * probability + probability /= distance + expected_jumps_number = 0 + for i in range(distance): + expected_jumps_number += memo_expected_jumps( + i, jumps_made + 1.0, probability) + return expected_jumps_number + +memo_expected_jumps = memo(expected_jumps) if __name__ == "__main__": try: arg = int(sys.argv[1]) except: arg = 10 - for i in range(1, arg + 1): - num_expected_jumps = expected_jumps(i) - # uncomment line below to make sure that expected number of jumps - # is equal to (distance + 1) / 2 - # tested up to a distance of 498 jumps - # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - # if (float(i)+1)/2 != num_expected_jumps: - # print('', i, num_expected_jumps) - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - # This line will print all values for all paths up to selected number - # Feel free to test with >>> python3 frog-jumps-calc.py {distance} - num_possible_paths = possible_paths(i) - num_possible_jumps = possible_jumps(i) - print(f"For a distance {i} there're {num_possible_paths} possible paths " + try: + loop = bool(sys.argv[2]) + except: + loop = False + + if loop: + for i in range(1, arg + 1): + # This line will print all values for all paths up to selected number + # Feel free to test with >>> python3 frog-jumps-calc.py {distance} {loop} + num_expected_jumps = expected_jumps(i) + num_possible_paths = possible_paths(i) + num_possible_jumps = possible_jumps(i) + print(f"For a distance {i} there're {num_possible_paths} possible paths " + f"containing {num_possible_jumps} jumps " + f"with expected jumps equal to {num_expected_jumps}.") + else: + num_expected_jumps = expected_jumps(arg) + num_possible_paths = possible_paths(arg) + num_possible_jumps = possible_jumps(arg) + print(f"For a distance {arg} there're {num_possible_paths} possible paths " f"containing {num_possible_jumps} jumps " f"with expected jumps equal to {num_expected_jumps}.")