···11+from typing import List, Optional
22+33+44+class Odometer:
55+ """An odometer where all digits must be in ascending order"""
66+77+ miles: int
88+99+ @staticmethod
1010+ def _is_error(miles: int) -> bool:
1111+ """Return True if the given miles are not in ascending order or contain a zero."""
1212+ try:
1313+ Odometer(miles)
1414+ except ValueError:
1515+ return True
1616+ return False
1717+1818+ @staticmethod
1919+ def possible_values(odo_len: int) -> List[int]:
2020+ """Return a list of possible values for the given miles."""
2121+ min = Odometer._get_minimum(odo_len)
2222+ max = Odometer._get_maximum(odo_len)
2323+ return [i for i in range(min, max + 1) if not Odometer._is_error(i)]
2424+2525+ @staticmethod
2626+ def _ascending(digits: List[int]) -> bool:
2727+ return all(digits[i] < digits[i + 1] for i in range(len(digits) - 1))
2828+2929+ @staticmethod
3030+ def _get_digits(miles: int) -> List[int]:
3131+ """Return a list of digits from the given miles."""
3232+ return list(map(int, str(miles)))
3333+3434+ @staticmethod
3535+ def _verify_miles(miles: int) -> None:
3636+ """Verify that the given miles are in ascending order and do not contain a zero. Throws ValueError if not."""
3737+ digits = Odometer._get_digits(miles)
3838+ if len(digits) > 9:
3939+ raise ValueError("Miles cannot be greater than 9 digits")
4040+ if not Odometer._ascending(digits):
4141+ raise ValueError("Miles must be in ascending order")
4242+ if any(d == 0 for d in digits):
4343+ raise ValueError("Miles cannot contain a zero")
4444+4545+ @staticmethod
4646+ def _get_maximum(odo_len: int) -> int:
4747+ """Return the maximum possible miles given the current odometer length."""
4848+ return int("".join([str(i) for i in range(10 - odo_len, 10)]))
4949+5050+ @staticmethod
5151+ def _get_minimum(odo_len: int) -> int:
5252+ """Return the minimum possible miles given the current odometer length."""
5353+ return int("".join([str(i) for i in range(1, odo_len + 1)]))
5454+5555+ def __init__(self, starting_miles: int = 1) -> None:
5656+ """Initialize an odometer with the given starting miles."""
5757+ if starting_miles < 0:
5858+ raise ValueError("Starting miles cannot be negative")
5959+ Odometer._verify_miles(starting_miles)
6060+ self.miles = starting_miles
6161+6262+6363+ def verify_miles(self) -> bool:
6464+ """Verify that the odometer's miles are in ascending order and do not contain a zero."""
6565+ try:
6666+ Odometer._verify_miles(self.miles)
6767+ except ValueError:
6868+ return False
6969+ return True
7070+7171+ def get_digits(self) -> List[int]:
7272+ """Return the odometer's miles as a list of digits."""
7373+ return list(map(int, str(self.miles)))
7474+7575+ def get_minimum(self) -> int:
7676+ """Return the minimum valid odometer reading."""
7777+ return Odometer._get_minimum(len(self.get_digits()))
7878+7979+ def get_maximum(self) -> int:
8080+ """Return the maximum valid odometer reading."""
8181+ return Odometer._get_maximum(len(self.get_digits()))
8282+8383+ def next_reading(self) -> Optional[int]:
8484+ """Return the next valid odometer reading."""
8585+ first_run = True
8686+ if self.miles == self.get_maximum():
8787+ return None
8888+ while not self.verify_miles() or first_run:
8989+ first_run = False
9090+ self.miles += 1
9191+ return self.miles
9292+9393+ def previous_reading(self) -> Optional[int]:
9494+ """Return the previous valid odometer reading."""
9595+ first_run = True
9696+ if self.miles == self.get_minimum():
9797+ return None
9898+ while not self.verify_miles() or first_run:
9999+ first_run = False
100100+ self.miles -= 1
101101+ return self.miles
102102+103103+ def nth_reading_after(self, n: int) -> Optional[int]:
104104+ """Return the nth valid odometer reading."""
105105+ first_run = True
106106+ i = 0
107107+ while not self.verify_miles() or first_run or i < n:
108108+ if self.miles == self.get_maximum():
109109+ return None
110110+ first_run = False
111111+ self.miles += 1
112112+ if self.verify_miles():
113113+ i += 1
114114+ return self.miles
115115+116116+ def nth_reading_before(self, n: int) -> Optional[int]:
117117+ """Return the nth valid odometer reading before the current one."""
118118+ first_run = True
119119+ i = 0
120120+ while not self.verify_miles() or first_run or i < n:
121121+ if self.miles == self.get_minimum():
122122+ return None
123123+ first_run = False
124124+ self.miles -= 1
125125+ if self.verify_miles():
126126+ i += 1
127127+ return self.miles
128128+129129+ @staticmethod
130130+ def print(start: Optional[int], end) -> None:
131131+ """Print the start of the odometer with some other value."""
132132+ print(f"{start} -> {end}")
133133+134134+ @staticmethod
135135+ def _distance(start: int, end: int) -> int:
136136+ """Calculate the distance between two odometer readings."""
137137+ odo_len = len(Odometer._get_digits(start))
138138+ if odo_len != len(Odometer._get_digits(end)):
139139+ raise ValueError("Odometer readings must have the same number of digits")
140140+ n = 0
141141+ while start != end:
142142+ try:
143143+ Odometer._verify_miles(start)
144144+ n += 1
145145+ if start == Odometer._get_maximum(odo_len):
146146+ start = Odometer._get_minimum(odo_len)
147147+ else:
148148+ start += 1
149149+ except:
150150+ start += 1
151151+ return n
152152+153153+ def distance(self, end: int) -> Optional[int]:
154154+ """Calculate the distance between the current odometer reading and another."""
155155+ try:
156156+ return Odometer._distance(self.miles, end)
157157+ except:
158158+ return None
159159+160160+odometer = Odometer(2467)
161161+Odometer.print(odometer.miles, odometer.get_minimum())
162162+Odometer.print(odometer.miles, odometer.get_maximum())
163163+Odometer.print(odometer.miles, odometer.nth_reading_after(6))
164164+Odometer.print(odometer.miles, odometer.nth_reading_before(6))
165165+Odometer.print(odometer.miles, odometer.next_reading())
166166+Odometer.print(odometer.miles, odometer.previous_reading())
167167+Odometer.print(odometer.miles, f"1234: {odometer.distance(1234)}")
168168+169169+odo2 = Odometer(123)
170170+Odometer.print(odo2.miles, odo2.get_minimum())
171171+Odometer.print(odo2.miles, odo2.get_maximum())
172172+Odometer.print(odo2.miles, odo2.nth_reading_after(83))
173173+Odometer.print(odo2.miles, f"123: {odo2.distance(123)}")
174174+175175+print(Odometer.possible_values(8))