-
Notifications
You must be signed in to change notification settings - Fork 0
/
read_answer_file.py
142 lines (106 loc) · 4.6 KB
/
read_answer_file.py
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
from collections import defaultdict
import read_in_file as rif
import utils
MAX_DISTANCE = 300
def parse_answer(answer_file):
drivers=[]
f = open(answer_file, 'r')
for line in f:
if line.strip():
driver = parse_driver(line)
drivers.append(driver)
f.close()
return drivers
def parse_driver(line):
driver = [int(x) for x in line.split()]
if len(driver) % 6 != 0:
raise Exception('All users should have origin ox oy and destination dx dy')
idxs, points = get_indexes_and_points_separated_lists(driver)
point_tuples = tuple([(x, y) for x, y in utils.pairwise(points)])
idxs_and_points = [(idx, point) for idx, point in zip(idxs, point_tuples)]
return idxs_and_points
def get_indexes_and_points_separated_lists(driver):
return [driver[idx] for idx in range(len(driver)) if idx % 3 == 0], [driver[idx] for idx in range(len(driver)) if idx % 3 != 0]
def legal_answer(answer, D, drivers, users):
if not actual_drivers(answer, D, drivers):
print('A driver is not an actual driver')
return False
if not actual_users(answer, D, drivers + users):
print('A user (driver or passenger) is not an actual user')
return False
if not users_appear_once_at_most(answer):
print('A user appears more than once')
return False
if not drivers_with_legal_passengers(answer):
print('Driver with illegal passenger')
return False
if not drivers_within_distance(answer):
print('Driver drives beyond maxim distance')
return False
return True
def drivers_with_legal_passengers(drivers):
"""checks max 2 passengers and gets/drops all of them
A passenger can only be driven once by the same driver"""
passenger_counts = defaultdict(int)
for driver in drivers:
passengers = get_driver_idx_passengers(driver)
passenger_in_car = 0
for passenger in passengers:
passenger_counts[passenger] += 1
if passenger_counts[passenger] == 1:
passenger_in_car += 1
if passenger_counts[passenger] == 2:
passenger_in_car -=1
if passenger_in_car > 3 or passenger_counts[passenger] > 2:
return False
if passenger_in_car > 0:
return False
return True
def drivers_within_distance(drivers):
"""Checks drivers drive within distance limit"""
return all([driven_distance(driver) <= MAX_DISTANCE for driver in drivers])
def driven_distance(driver):
points = get_driver_destinations(driver)
return sum([utils.manhattan_distance(o, d) for o, d in zip(points[:-1], points[1:])])
def get_driver_destinations(driver):
return [point for idx, point in driver]
def get_driver_idx_passengers(driver):
return [idx for idx, point in driver]
def get_driver_passengers(driver):
passengers = defaultdict(list)
for passenger in driver[1:-1]:
idx, point = passenger
passengers[idx].append([idx, point])
result = []
for passenger in passengers.values():
result.append(tuple((passenger[0][0], passenger[0][1], passenger[1][1])))
return result
def actual_drivers(answer, D, drivers):
""" Drivers have same origin/destination as in the input file.
if driver idx >= D means it's a user that can not drive"""
return all([equal_driver(ad, drivers[ad[0][0]]) if ad[0][0] < D else False for ad in answer])
def actual_users(answer, D, all_users):
"""All passengers have same origin/destination than the ones defined in the input file
Recall that a passenger can be either a non driving user or a driver"""
for driver in answer:
passengers = get_driver_passengers(driver)
if not all([all_users[passenger[0]] == passenger for passenger in passengers]):
return False
return True
def equal_driver(answer_driver, driver):
idx, ad_origin = answer_driver[0]
idx, ad_dest = answer_driver[-1]
return tuple((idx, ad_origin, ad_dest)) == driver
def users_appear_once_at_most(answer):
"""A driver can only drive once and a passenger can be driven only once"""
user_counts = defaultdict(int)
for driver in answer:
driver_and_passenger_idx = set([driver[idx] for idx in range(len(driver)) if idx % 3 == 0])
for user_idx in driver_and_passenger_idx:
user_counts[user_idx] += 1
if user_counts[user_idx] > 1:
return False
return True
# answer = parse_answer('i_o_files/small_5_2' + '.out')
# N, M, D, U, drivers, users = rif.parse_in('i_o_files/small_5_2' + '.in')
# print('legal: ', legal_answer(answer, D, drivers, users))