Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import re
import sys
import os
from pprint import pprint
import logging
import unittest
from parameterized import parameterized
if 'DEBUG' in os.environ:
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='[%(levelname)s] %(message)s')
else:
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
def _printTimestamp(ts):
u = int(ts[0] / 100)
d = int(ts[1] / 100)
fill = {True: "+", False: "."}
fill_s = u > d
result = f"{u: <2} {d: <2}:"
for i in range(0,25):
if i == u:
result += "("
fill_s = True
elif i == d:
result += ")"
fill_s = False
else:
result += fill[fill_s]
logging.debug(result)
def _printTimestamps(tss):
for ts in tss:
_printTimestamp(ts)
class MarsMoonClockTests(unittest.TestCase):
def setUp(self):
self.clock = MarsMoonClock()
def test_parseInput_p(self):
parsed = self.clock._parseInput("13:91","23:05","22:05","24:45")
self.assertEquals(parsed[0], (1391, 2305))
self.assertEquals(parsed[1], (2205, 2445))
#<extra>
@parameterized.expand([
["24:100", "7:12", "5:12", "8:45", "minutes overflow"],
["24:-53", "7:12", "5:12", "8:45", "negative minutes"],
["25:53", "7:12", "5:12", "8:45", "hours overflow"],
["24:-53", "7:12", "5:12", "8:45", "negative minutes"],
["2453", "7:12", "5:12", "8:45", "invalid format"],
])
def test_parseInput_n(self, du, dd, pu, pd, msg):
with self.assertRaises(InvalidInputException, msg=msg):
self.clock._parseInput(du, dd, pu, pd)
#</extra>
@parameterized.expand([
#<extra>
[( 500, 1000), (1500, 2000), 0, '-(-)-[-]-'],
[( 500, 1000), (2000, 1500), 500, '-(+)-]-[-'],
[( 500, 1500), (1000, 2000), 500, '-(-[+)-]-'],
[( 500, 2000), (1000, 1500), 500, '-(-[+]-)-'],
[( 500, 1500), (2000, 1000), 500, '-(+]-)-[-'],
[( 500, 2000), (1500, 1000), 1000, '-(+]-[+)-'],
[(1000, 500), (1500, 2000), 500, '-)-(-[+]-'],
[(1000, 500), (2000, 1500), 1500, '+)-(+]-[+'],
[(1500, 500), (1000, 2000), 500, '-)-[-(+]-'],
[(2000, 500), (1000, 1500), 0, '-)-[-]-(-'],
[(1500, 500), (2000, 1000), 1000, '+)-]-(-[+'],
[(2000, 500), (1500, 1000), 1000, '+)-]-[-(+'],
[(1000, 1500), ( 500, 2000), 500, '-[-(+)-]-'],
[(1000, 2000), ( 500, 1500), 500, '-[-(+]-)-'],
[(1500, 1000), ( 500, 2000), 1000, '-[+)-(+]-'],
[(2000, 1000), ( 500, 1500), 500, '-[+)-]-(-'],
[(1500, 2000), ( 500, 1000), 0, '-[-]-(-)-'],
[(2000, 1500), ( 500, 1000), 500, '-[+]-)-(-'],
[(1000, 1500), (2000, 500), 0, '-]-(-)-[-'],
[(1000, 2000), (1500, 500), 500, '-]-(-[+)-'],
[(1500, 1000), (2000, 500), 1000, '+]-)-(-[+'],
[(2000, 1000), (1500, 500), 1000, '+]-)-[-(+'],
[(1500, 2000), (1000, 500), 500, '-]-[-(+)-'],
[(2000, 1500), (1000, 500), 1500, '+]-[+)-(+'],
#</extra>
[(1000, 1100), (1200, 2000), 0 , "no overlap: dd < pu"], # -(-)-[-]-
[(2400, 1000), (1200, 2000), 0 , "no overlap: dd < pu over midnight"], # -)-[-]-(-
[(1200, 2000), (1000, 1100), 0 , "no overlap: pd < du"], # -(-)-[-]-
[(1200, 2000), (2400, 1000), 0 , "no overlap: pd < du over midnight"], # -]-(-)-[-
[(1000, 1700), (1600, 2300), 100 , "overlap: d then p"], # -(-[+)-]-
[(2400, 1700), (1600, 2300), 100 , "overlap: d then p over midnight"], # -[+)-(+]-
[(1600, 2300), (1000, 1700), 100 , "overlap: p then d"], # -[-(+]-)-
[(1000, 500), ( 300, 1200), 400 , "overlap: p then d over midnight"], # -(+]-[+)-
[(1000, 2000), (1300, 1800), 500 , "overlap: d in p"], # -(-[+]-)-
[(2400, 400), (2300, 1800), 500 , "overlap: d in p over midnight"], # +)-]-[-(+
[(1300, 1800), (1000, 2000), 500 , "overlap: p in d"], # -[-(+)-]-
[(2300, 1800), (2400, 400), 500 , "overlap: p in d over midnight"], # +)-]-[-(+
[(1000, 1500), (1500, 2000), 1 , "twighlight rule pd = du"], # -(-)_[-]-
[(1500, 2000), (1000, 1500), 1 , "twighlight rule dd = pu"], # -[-]_(-)-
])
def test_getIntersectionTime_1(self, d, p, r, msg):
intersection = self.clock._calcIntersectionTime(d, p)
self.assertEquals(intersection, r, msg)
class InvalidInputException(Exception):
pass
class MarsMoonClock:
def _calcIntersectionTime(self, d, p):
du, pu, pd, dd = d[0], p[0], p[1], d[1]
_printTimestamps([(du,dd),(pu,pd)])
if dd < du:
return self._calcIntersectionTime((pu,pd),(0,dd)) + self._calcIntersectionTime((pu,pd), (du,2500))
elif pd < pu:
return self._calcIntersectionTime((0,pd),(du,dd)) + self._calcIntersectionTime((pu,2500), (du,dd))
if pd == du or dd == pu: #twilight rule
return 1
last_up = max(du,pu)
first_down = min(dd,pd)
if last_up < first_down:
result = first_down - last_up
elif last_up > first_down:
result = 0
logging.debug(f"{du},{dd},{pu},{pd}: {first_down} - {last_up} = {result}")
return result
def _parseTimestamp(self, ts):
ts_s = ts.split(':')
if len(ts_s) != 2:
raise InvalidInputException("invalid input: invalid argument format")
try:
ts_h = int(ts_s[0])
except ValueError as e:
raise InvalidInputException("invalid input: invalid hours format")
if ts_h < 0 or ts_h > 24:
raise InvalidInputException("invalid input: allowed range for timestamp hours 0-24")
try:
ts_m = int(ts_s[1])
except ValueError as e:
raise InvalidInputException("invalid input: invalid minutes format")
if ts_m < 0 or ts_m > 99:
raise InvalidInputException("invalid input: allowed range for timestamp minutes 0-99")
result = ts_h*100+ts_m
logging.debug(f"_parseTimestamp: {ts} => {result}")
return result
def _parseInput(self, du, dd, pu, pd):
du_p = self._parseTimestamp(du)
dd_p = self._parseTimestamp(dd)
pu_p = self._parseTimestamp(pu)
pd_p = self._parseTimestamp(pd)
logging.debug(f"_parseInput: d:({du_p},{dd_p}) p:({pu_p},{pd_p})")
return ((du_p,dd_p),(pu_p,pd_p))
def getIntersectionMinutes(self, du, dd, pu, pd):
d,p = self._parseInput(du, dd, pu, pd)
return self._calcIntersectionTime(d,p)
if __name__ == '__main__':
m = MarsMoonClock()
if len(sys.argv) < 5:
raise Exception("invalid input: 4 parameters needed")
try:
print(m.getIntersectionMinutes(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]))
except InvalidInputException as e:
print(e, file=sys.stderr)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.