aboutsummaryrefslogtreecommitdiff
path: root/challenge-054/lubos-kolouch/python/ch-2.py
blob: 311158273b4d2143ef44e7d23177c5e9ba069e55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env python
""" PerlWeeklyChallenge 054 Task 2"""


class Collatz:
    """ Collatz Conjecture """

    def __init__(self):
        self.length_cache = dict()

    def get_next_sequence(self, seq_pos: int):
        """ Calculate next position number """

        if seq_pos % 2 == 0:
            return seq_pos // 2

        return 3 * seq_pos + 1

    def single_sequence(self, seq_pos: int):
        """ For the first task, it is easier to separate to own function """
        seq = []
        while seq_pos > 1:

            seq.append(seq_pos)
            seq_pos = self.get_next_sequence(seq_pos)

        seq.append(1)
        return seq

    def get_sequence_length(self, seq_pos: int):
        """ Calculate the sequence """

        if seq_pos == 1:
            # special case
            self.length_cache[1] = 1
            return 1

        seq_length = 0

        cur_pos = seq_pos

        while cur_pos >= 1:

            if self.length_cache.get(cur_pos):
                # If we have already the length cached, return it """
                seq_length += self.length_cache[cur_pos]
                break

            # otherwise increse the length and move to next step
            seq_length += 1
            cur_pos = self.get_next_sequence(cur_pos)

        self.length_cache[seq_pos] = seq_length

        return seq_length

class TestCollatz:
    """Test for the NthPermut class"""

    def do_tests(self):
        """Run the tests"""
        collatz = Collatz()
        assert collatz.single_sequence(1) == [1]
        assert collatz.single_sequence(23) == [23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]


def main():
    """Main method"""

#    assert len(sys.argv) == 3

    collatz = Collatz()
    print(collatz.single_sequence(23))

    for seq_pos in range(1, 1_000_001):
        collatz.get_sequence_length(seq_pos)

    print(sorted(collatz.length_cache.items(),
                 key=lambda x: x[1], reverse=True)[:20])

    tester = TestCollatz()
    tester.do_tests()


if __name__ == "__main__":
    main()