101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
from stats import Stats, finalize_waiting_stats, show_stats
|
|
from entities import Plane, ProcessedRequest, Request
|
|
from queues import EnforcingQueue, PermissiveQueue, Queue
|
|
|
|
from numpy import random
|
|
from typing import Final, Iterable, Optional
|
|
|
|
from numpy.typing import NDArray
|
|
|
|
|
|
def warn_about_outcoming_queue_overload(queue: Queue) -> None:
|
|
print(f"Outcoming queue is overloaded: {len(queue)} planes/{queue.size} planes")
|
|
|
|
def reject_plane(plane: Plane) -> None:
|
|
stats.rejected_in_requests += 1
|
|
print(f"Rejected incoming plane №{plane.id}")
|
|
|
|
def launch_plane(plane: Plane, stats: Stats) -> None:
|
|
stats.launches_count += 1
|
|
print(f"Launched plane №{plane.id}")
|
|
|
|
def land_plane(plane: Plane, stats: Stats) -> None:
|
|
stats.landings_count += 1
|
|
print(f"Plane №{plane.id} landed")
|
|
|
|
def generate_timeline(incoming_planes_per_hour: float, outcoming_planes_per_hour: float, interval_minutes: int) -> Iterable[tuple[int, int]]:
|
|
def _generate(planes_per_hour: float) -> NDArray:
|
|
return random.poisson(planes_per_hour / 60, interval_minutes)
|
|
|
|
incoming_planes_per_minute = _generate(incoming_planes_per_hour)
|
|
outcoming_planes_per_minute = _generate(outcoming_planes_per_hour)
|
|
return zip(incoming_planes_per_minute, outcoming_planes_per_minute)
|
|
|
|
def process_new_request(in_queue: Queue[Request], out_queue: Queue[Request], current_time: int, process_duration: int) -> ProcessedRequest:
|
|
plane: Optional[Plane]
|
|
if in_queue:
|
|
request = in_queue.pop()
|
|
plane = request.plane
|
|
stats.in_waiting_time.append(current_time - request.request_time)
|
|
print(f"{current_time}: Processing incoming plane №{plane.id}")
|
|
process_type = "landing"
|
|
else:
|
|
request = out_queue.pop()
|
|
plane = request.plane
|
|
stats.out_waiting_time.append(current_time - request.request_time)
|
|
print(f"{current_time}: Processing outcoming plane №{plane.id}")
|
|
process_type = "launching"
|
|
return ProcessedRequest(request.request_time, request.plane, current_time, current_time + process_duration, process_type)
|
|
|
|
takeoff_duration: Final[int] = int(input("Takeoff duration: ")) # minutes
|
|
|
|
max_queue: Final[int] = int(input("Max queue: "))
|
|
interval: Final[int] = int(input("Interval: ")) # minutes
|
|
incoming_planes, outcoming_planes = map(float, input("Planes: ").split()) # per hour
|
|
|
|
in_queue: Queue[Request] = EnforcingQueue[Request](max_queue)
|
|
out_queue: Queue[Request] = PermissiveQueue[Request](max_queue, warn_about_outcoming_queue_overload)
|
|
|
|
current_request: Optional[ProcessedRequest] = None
|
|
|
|
stats = Stats()
|
|
timeline = generate_timeline(5,2, interval)
|
|
|
|
i = 0
|
|
|
|
for i, (in_planes_count, out_planes_count) in enumerate(timeline):
|
|
stats.total_plane_requests += in_planes_count + out_planes_count
|
|
stats.in_requests += in_planes_count
|
|
stats.out_requests += out_planes_count
|
|
|
|
for _ in range(in_planes_count):
|
|
new_plane = Plane()
|
|
try:
|
|
in_queue.add(Request(i, new_plane))
|
|
stats.accepted_in_requests += 1
|
|
except IndexError:
|
|
reject_plane(new_plane)
|
|
stats.rejected_in_requests += 1
|
|
for _ in range(out_planes_count):
|
|
new_plane = Plane()
|
|
out_queue.add(Request(i, new_plane))
|
|
stats.accepted_out_requests += 1
|
|
|
|
if not current_request:
|
|
if len(in_queue) or len(out_queue):
|
|
current_request = process_new_request(in_queue, out_queue, i, takeoff_duration)
|
|
continue
|
|
stats.sleep_minutes += 1
|
|
if current_request and current_request.process_time == i:
|
|
if current_request.type_ == "launching":
|
|
launch_plane(current_request.plane, stats)
|
|
else:
|
|
land_plane(current_request.plane, stats)
|
|
current_request = None
|
|
|
|
stats.in_queued = len(in_queue)
|
|
stats.out_queued = len(out_queue)
|
|
|
|
finalize_waiting_stats(stats, in_queue, out_queue, i)
|
|
show_stats(stats)
|