diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2020-09-27 17:53:53 +0200 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2020-09-27 17:53:53 +0200 |
| commit | 51857521f770caae7b36e3a36a30d5b6986e66d1 (patch) | |
| tree | 8b56e84794c6a3be67db33bc3d9cea435e2a2b2c /src | |
| parent | 20e0b28ec3c8e9e0a63759116a32438c18941a59 (diff) | |
| download | philosophers_test-51857521f770caae7b36e3a36a30d5b6986e66d1.tar.gz philosophers_test-51857521f770caae7b36e3a36a30d5b6986e66d1.tar.bz2 philosophers_test-51857521f770caae7b36e3a36a30d5b6986e66d1.zip | |
Added should be dead check, Moved philo classes in src/test/philo.py
Diffstat (limited to 'src')
| -rwxr-xr-x | src/main.py | 17 | ||||
| -rw-r--r-- | src/philo/__init__.py | 16 | ||||
| -rw-r--r-- | src/philo/event.py | 21 | ||||
| -rw-r--r-- | src/philo/log.py | 53 | ||||
| -rw-r--r-- | src/philo/philo.py | 50 | ||||
| -rw-r--r-- | src/philo/table.py | 40 | ||||
| -rw-r--r-- | src/test/philo.py | 136 | ||||
| -rw-r--r-- | src/test/test.py | 9 |
8 files changed, 148 insertions, 194 deletions
diff --git a/src/main.py b/src/main.py index 861bc8e..dbe33ea 100755 --- a/src/main.py +++ b/src/main.py @@ -12,14 +12,15 @@ # # # ############################################################################ # -# invalid state switch -# none existant fork -# timestamp not in order -# crash -# should be infinity -# print lines after died -# bad output format -# should be dead +# [x] invalid state switch +# [x] none existant fork +# [x] timestamp not in order +# [ ] crash +# [ ] should be infinity +# [ ] argument error +# [x] print lines after died +# [x] bad output format +# [x] should be dead import os import sys diff --git a/src/philo/__init__.py b/src/philo/__init__.py deleted file mode 100644 index f8cb07f..0000000 --- a/src/philo/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# ############################################################################ # -# # -# ::: :::::::: # -# __init__.py :+: :+: :+: # -# +:+ +:+ +:+ # -# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2020/09/27 16:06:28 by charles #+# #+# # -# Updated: 2020/09/27 16:11:04 by charles ### ########.fr # -# # -# ############################################################################ # - -from philo.table import Table -from philo.philo import Philo -from philo.log import Log -from philo.event import Event diff --git a/src/philo/event.py b/src/philo/event.py deleted file mode 100644 index 62f7ca6..0000000 --- a/src/philo/event.py +++ /dev/null @@ -1,21 +0,0 @@ -# ############################################################################ # -# # -# ::: :::::::: # -# event.py :+: :+: :+: # -# +:+ +:+ +:+ # -# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2020/09/27 16:04:04 by charles #+# #+# # -# Updated: 2020/09/27 16:28:43 by charles ### ########.fr # -# # -# ############################################################################ # - -from enum import Enum - - -class Event(Enum): - EATING = 1 - SLEEPING = 2 - THINKING = 3 - DIED = 4 - NONE = 5 diff --git a/src/philo/log.py b/src/philo/log.py deleted file mode 100644 index cc4347e..0000000 --- a/src/philo/log.py +++ /dev/null @@ -1,53 +0,0 @@ -# ############################################################################ # -# # -# ::: :::::::: # -# log.py :+: :+: :+: # -# +:+ +:+ +:+ # -# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2020/09/27 16:04:18 by charles #+# #+# # -# Updated: 2020/09/27 16:05:21 by charles ### ########.fr # -# # -# ############################################################################ # - -import re -import time - -import philo - - -class Log: - def __init__(self, log, philo_num): - match = re.match( - "^(?P<timestamp>\d+) " - "(?P<id>\d+) " - "(?P<event>is thinking|is eating|is sleeping|died)$", - log - ) - if match is None: - raise ValueError("Bad line format |{}|".format(log)) - - curr = int(time.time() * 1000) - self.timestamp = Log._parse_ranged_int(match.group("timestamp"), curr - 100, curr + 100) - self.id = Log._parse_ranged_int(match.group("id"), 1, philo_num) - - self.event = { - "is thinking": philo.Event.THINKING, - "is eating": philo.Event.EATING, - "is sleeping": philo.Event.SLEEPING, - "died": philo.Event.DIED, - }[match.group('event')] - - @staticmethod - def _parse_ranged_int(s, lo, hi): - try: - value = int(s) - if not (lo <= value <= hi): - raise ValueError("Invalid value range {}".format(s)) - except ValueError: - raise ValueError("Invalid value {}".format(s)) - return value - - - def __repr__(self): - return "{} {} {}".format(self.timestamp, self.id, self.event) diff --git a/src/philo/philo.py b/src/philo/philo.py deleted file mode 100644 index e7e2e1d..0000000 --- a/src/philo/philo.py +++ /dev/null @@ -1,50 +0,0 @@ -# ############################################################################ # -# # -# ::: :::::::: # -# philo.py :+: :+: :+: # -# +:+ +:+ +:+ # -# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2020/09/27 12:54:12 by charles #+# #+# # -# Updated: 2020/09/27 16:50:22 by charles ### ########.fr # -# # -# ############################################################################ # - -import itertools -from philo.event import Event - -class Philo: - def __init__(self, id_: int, meal_num: int = 1): - self._logs = [] - self.id = id_ - self.meal_num = meal_num - - def add_log(self, log): - self._logs.append(log) - - def check(self): - grouped = [(e, list(g)) for e, g in itertools.groupby(self._logs, (lambda x: x.event))] - for e, g in grouped: - if e is Event.EATING: - if len(g) != self.meal_num: - raise RuntimeError("lala") - else: - if len(g) != 1: - raise RuntimeError("1lala") - - events = [e for e, _ in grouped] - for e1, e2 in zip(events, events[1:]): - if e2 is Event.DIED: - break - if e1 is Event.THINKING and e2 is not Event.EATING: - raise RuntimeError("2lala") - elif e1 is Event.EATING and e2 is not Event.SLEEPING: - raise RuntimeError("2lala") - elif e1 is Event.SLEEPING and e2 is not Event.EATING: - raise RuntimeError("2lala") - - @property - def last_event(self): - if len(self._logs) == 0: - return Event.NONE - return self._logs[-1].event diff --git a/src/philo/table.py b/src/philo/table.py deleted file mode 100644 index 8214ffb..0000000 --- a/src/philo/table.py +++ /dev/null @@ -1,40 +0,0 @@ -# ############################################################################ # -# # -# ::: :::::::: # -# table.py :+: :+: :+: # -# +:+ +:+ +:+ # -# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # -# +#+#+#+#+#+ +#+ # -# Created: 2020/09/27 12:44:48 by charles #+# #+# # -# Updated: 2020/09/27 16:54:52 by charles ### ########.fr # -# # -# ############################################################################ # - -from philo.philo import Philo -from philo.event import Event - - -class Table: - def __init__(self, philo_num): - self._philos = [Philo(id_) for id_ in range(1, philo_num + 1)] - self._logs = [] - self._philo_num = philo_num - - def add_log(self, log): - self._logs.append(log) - philo = next(p for p in self._philos if p.id == log.id) - philo.add_log(log) - - def check(self): - died_count = len([p for p in self._philos if p.last_event == Event.DIED]) - if died_count > 1: - raise RuntimeError("died") - fork_used = 2 * len([p for p in self._philos if p.last_event == Event.EATING]) - if fork_used > self._philo_num: - raise RuntimeError("too much fork") - for p in self._philos: - p.check() - for l1, l2 in zip(self._logs, self._logs[1:]): - if l1.timestamp > l2.timestamp: - raise RuntimeError("timestamp not ordered") - diff --git a/src/test/philo.py b/src/test/philo.py new file mode 100644 index 0000000..743f0cb --- /dev/null +++ b/src/test/philo.py @@ -0,0 +1,136 @@ +# ############################################################################ # +# # +# ::: :::::::: # +# philo.py :+: :+: :+: # +# +:+ +:+ +:+ # +# By: charles <me@cacharle.xyz> +#+ +:+ +#+ # +# +#+#+#+#+#+ +#+ # +# Created: 2020/09/27 17:49:41 by charles #+# #+# # +# Updated: 2020/09/27 17:53:10 by charles ### ########.fr # +# # +# ############################################################################ # + +import re +import time +import enum +import itertools + + +class Event(enum.Enum): + EATING = 1 + SLEEPING = 2 + THINKING = 3 + DIED = 4 + NONE = 5 + + +class Log: + def __init__(self, log, philo_num): + match = re.match( + "^(?P<timestamp>\d+) " + "(?P<id>\d+) " + "(?P<event>is thinking|is eating|is sleeping|died)$", + log + ) + if match is None: + raise ValueError("Bad line format |{}|".format(log)) + + curr = int(time.time() * 1000) + self.timestamp = Log._parse_ranged_int(match.group("timestamp"), curr - 100, curr + 100) + self.id = Log._parse_ranged_int(match.group("id"), 1, philo_num) + + self.event = { + "is thinking": Event.THINKING, + "is eating": Event.EATING, + "is sleeping": Event.SLEEPING, + "died": Event.DIED, + }[match.group('event')] + + @staticmethod + def _parse_ranged_int(s, lo, hi): + try: + value = int(s) + if not (lo <= value <= hi): + raise ValueError("Invalid value range {}".format(s)) + except ValueError: + raise ValueError("Invalid value {}".format(s)) + return value + + def __repr__(self): + return "{} {} {}".format(self.timestamp, self.id, self.event) + + +class Philo: + def __init__(self, id_: int, timeout_eat: int, meal_num: int = 1): + self._logs = [] + self.id = id_ + self.meal_num = meal_num + self._timeout_eat = timeout_eat + + def add_log(self, log): + self._logs.append(log) + + def check(self): + grouped = [(e, list(g)) for e, g in itertools.groupby(self._logs, (lambda x: x.event))] + for e, g in grouped: + if e is Event.EATING: + if len(g) != self.meal_num: + raise RuntimeError("lala") + else: + if len(g) != 1: + raise RuntimeError("1lala") + + events = [e for e, _ in grouped] + for e1, e2 in zip(events, events[1:]): + if e2 is Event.DIED: + break + if e1 is Event.THINKING and e2 is not Event.EATING: + raise RuntimeError("2lala") + elif e1 is Event.EATING and e2 is not Event.SLEEPING: + raise RuntimeError("2lala") + elif e1 is Event.SLEEPING and e2 is not Event.EATING: + raise RuntimeError("2lala") + + last_eat_time = int(time.time() * 1000) + for l in reversed(self._logs): + if l.event is Event.EATING: + last_eat_time = l.timestamp + break + + if int(time.time() * 1000) - last_eat_time > self._timeout_eat + 20: + raise RuntimeError("should be dead") + + @property + def last_event(self): + if len(self._logs) == 0: + return Event.NONE + return self._logs[-1].event + + +class Table: + def __init__(self, timeout_eat, philo_num): + self._philos = [Philo(id_, timeout_eat) for id_ in range(1, philo_num + 1)] + self._logs = [] + self._philo_num = philo_num + self.dead = False + + def add_log(self, log): + if self.dead: + raise RuntimeError("died") + if log.event is Event.DIED: + self.dead = True + self._logs.append(log) + philo = next(p for p in self._philos if p.id == log.id) + philo.add_log(log) + + def check(self): + if self.dead: + return + fork_used = 2 * len([p for p in self._philos if p.last_event == Event.EATING]) + if fork_used > self._philo_num: + raise RuntimeError("too much fork") + for p in self._philos: + p.check() + for l1, l2 in zip(self._logs, self._logs[1:]): + if l1.timestamp > l2.timestamp: + raise RuntimeError("timestamp not ordered") diff --git a/src/test/test.py b/src/test/test.py index 14ee097..1aa9f0a 100644 --- a/src/test/test.py +++ b/src/test/test.py @@ -6,7 +6,7 @@ # By: charles <me@cacharle.xyz> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2020/09/27 11:36:32 by charles #+# #+# # -# Updated: 2020/09/27 16:25:37 by charles ### ########.fr # +# Updated: 2020/09/27 17:51:44 by charles ### ########.fr # # # # ############################################################################ # @@ -15,10 +15,7 @@ import time import subprocess # import threading -# from result import Result - -import philo -# from test.table import Table +import test.philo as philo @@ -81,7 +78,7 @@ class Test: #(threading.Thread): process.wait() def _check_output(self, stream): - table = philo.Table(self._philo_num) + table = philo.Table(self._philo_num, self._timeout_eat) for line in stream: line = line.decode()[:-1] |
