Repository navigation
Expand file tree
/
Copy pathkaprekar_constant.py
More file actions
207 lines (165 loc) · 6.19 KB
/
Copy pathkaprekar_constant.py
File metadata and controls
207 lines (165 loc) · 6.19 KB
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
"""
Kaprekar's Constant (6174) - also known as Kaprekar's Routine
Kaprekar's constant is a special number discovered by Indian mathematician
D. R. Kaprekar in 1949. It is notable for the following property:
1. Take any four-digit number with at least two different digits (leading zeros allowed)
2. Arrange the digits in descending order to form the largest possible number
3. Arrange the digits in ascending order to form the smallest possible number
4. Subtract the smaller number from the larger number
5. Repeat the process with the result
This process will always reach 6174 in at most 7 iterations, and once 6174 is
reached, the process will continue to yield 6174.
Example:
3524 -> 5432 - 2345 = 3087
3087 -> 8730 - 0378 = 8352
8352 -> 8532 - 2358 = 6174
6174 -> 7641 - 1467 = 6174 (repeats)
Reference: https://en.wikipedia.org/wiki/6174_(number)
OEIS: https://oeis.org/A099009
"""
def kaprekar_routine(number: int) -> int:
"""
Perform one iteration of Kaprekar's routine.
Args:
number: A 4-digit number (0-9999)
Returns:
The result of one Kaprekar iteration
>>> kaprekar_routine(3524)
3087
>>> kaprekar_routine(3087)
8352
>>> kaprekar_routine(8352)
6174
>>> kaprekar_routine(6174)
6174
>>> kaprekar_routine(1)
999
>>> kaprekar_routine(1111)
0
"""
if not isinstance(number, int) or number < 0 or number > 9999:
msg = f"Input must be a non-negative integer between 0 and 9999, got {number}"
raise ValueError(msg)
# Convert to 4-digit string with leading zeros
digits = str(number).zfill(4)
# Check if all digits are the same (repdigit)
if len(set(digits)) == 1:
return 0
# Sort digits in descending and ascending order
descending = int("".join(sorted(digits, reverse=True)))
ascending = int("".join(sorted(digits)))
return descending - ascending
def kaprekar_constant(number: int, max_iterations: int = 7) -> tuple[int, list[int]]:
"""
Apply Kaprekar's routine until reaching the constant 6174 or max iterations.
Args:
number: A 4-digit number (0-9999)
max_iterations: Maximum number of iterations to perform (default: 7)
Returns:
A tuple containing:
- The number of iterations taken to reach 6174 (or -1 if not reached)
- A list of all intermediate results
>>> kaprekar_constant(3524)
(3, [3524, 3087, 8352, 6174])
>>> kaprekar_constant(6174)
(0, [6174])
>>> kaprekar_constant(1234)
(3, [1234, 3087, 8352, 6174])
>>> kaprekar_constant(1111)
(-1, [1111, 0])
>>> kaprekar_constant(495)
(4, [495, 9081, 9621, 8352, 6174])
>>> kaprekar_constant(9998)
(5, [9998, 999, 8991, 8082, 8532, 6174])
"""
if not isinstance(number, int) or number < 0 or number > 9999:
msg = f"Input must be a non-negative integer between 0 and 9999, got {number}"
raise ValueError(msg)
if not isinstance(max_iterations, int) or max_iterations < 1:
msg = f"max_iterations must be a positive integer, got {max_iterations}"
raise ValueError(msg)
sequence = [number]
current = number
# If already at Kaprekar's constant
if current == 6174:
return (0, sequence)
for iteration in range(max_iterations):
current = kaprekar_routine(current)
sequence.append(current)
# Check if we've reached the constant
if current == 6174:
return (iteration + 1, sequence)
# Check if we've reached a repdigit (all same digits) which gives 0
if current == 0:
return (-1, sequence)
# Did not reach 6174 within max_iterations
return (-1, sequence)
def is_kaprekar_valid(number: int) -> bool:
"""
Check if a number is valid for Kaprekar's routine.
A number is valid if it has at least two different digits.
Args:
number: A 4-digit number (0-9999)
Returns:
True if the number is valid for Kaprekar's routine, False otherwise
>>> is_kaprekar_valid(3524)
True
>>> is_kaprekar_valid(1111)
False
>>> is_kaprekar_valid(1000)
True
>>> is_kaprekar_valid(1)
True
>>> is_kaprekar_valid(6174)
True
"""
if not isinstance(number, int) or number < 0 or number > 9999:
msg = f"Input must be a non-negative integer between 0 and 9999, got {number}"
raise ValueError(msg)
# Convert to 4-digit string with leading zeros
digits = str(number).zfill(4)
# Check if at least two different digits exist
return len(set(digits)) > 1
def main() -> None:
"""
Demonstrate Kaprekar's constant with user input and examples.
"""
print("Kaprekar's Constant (6174) - Demonstration\n")
print("=" * 50)
# Example demonstrations
examples = [3524, 1234, 6174, 9998, 1111, 5]
for num in examples:
print(f"\nStarting number: {num:04d}")
if not is_kaprekar_valid(num):
print(" ❌ Invalid: All digits are the same (repdigit)")
continue
iterations, sequence = kaprekar_constant(num)
match iterations:
case -1:
print(f" ❌ Did not reach 6174. Sequence: {sequence}")
case 0:
print(" ✓ Already at Kaprekar's constant!")
case _:
print(f" ✓ Reached 6174 in {iterations} iteration(s)")
print(f" Sequence: {' -> '.join(str(n) for n in sequence)}")
# Interactive mode
print("\n" + "=" * 50)
print("\nTry your own number (0-9999):")
try:
user_input = int(input("Enter a 4-digit number: "))
if 0 <= user_input <= 9999:
if not is_kaprekar_valid(user_input):
print("Invalid: All digits are the same!")
else:
iterations, sequence = kaprekar_constant(user_input)
print(f"\nSequence: {' -> '.join(str(n) for n in sequence)}")
if iterations != -1:
print(f"Reached 6174 in {iterations} iteration(s)!")
else:
print("Number must be between 0 and 9999")
except ValueError, EOFError:
print("Invalid input or no input provided")
if __name__ == "__main__":
import doctest
doctest.testmod()
main()