This repository has been archived by the owner on Jan 24, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
/
instance.py
98 lines (75 loc) · 2.65 KB
/
instance.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
from __future__ import annotations
import dataclasses
from typing import Iterable, Iterator, List, TYPE_CHECKING
import parse
from point import Point
from svg import SVGGraphic
if TYPE_CHECKING:
from visualize import VisualizationConfig
def _next_int(lines: Iterator[str]):
value = next(lines)
return int(value)
@dataclasses.dataclass
class Instance:
grid_side_length: int
coverage_radius: int
penalty_radius: int
cities: List[Point]
@property
def N(self):
return len(self.cities)
@property
def R_s(self):
return self.coverage_radius
@property
def R_p(self):
return self.penalty_radius
@property
def D(self):
return self.grid_side_length
def valid(self):
"""Determines whether the problem instance is valid.
A problem instance is valid if all cities are in bounds and there
are no duplicate cities.
"""
for city in self.cities:
if not 0 <= city.x < self.grid_side_length:
return False
if not 0 <= city.y < self.grid_side_length:
return False
return len(set(self.cities)) == len(self.cities)
@staticmethod
def parse(lines: Iterable[str]) -> Instance:
lines_iter = parse.remove_comments(lines)
num_cities = _next_int(lines_iter)
grid_side_length = _next_int(lines_iter)
coverage_radius = _next_int(lines_iter)
penalty_radius = _next_int(lines_iter)
cities = [Point.parse(line) for line in lines_iter]
assert num_cities == len(cities)
instance = Instance(
grid_side_length=grid_side_length,
coverage_radius=coverage_radius,
penalty_radius=penalty_radius,
cities=cities,
)
assert instance.valid()
return instance
def serialize(self, out) -> None:
print(len(self.cities), file=out)
print(self.grid_side_length, file=out)
print(self.coverage_radius, file=out)
print(self.penalty_radius, file=out)
for city in self.cities:
city.serialize(out)
def serialize_to_string(self) -> str:
return parse.serialize_to_string_impl(self.serialize, self)
def visualize_as_svg(self, config: VisualizationConfig) -> SVGGraphic:
out = SVGGraphic(config.size, config.size)
out.draw_rect(0, 0, config.size, config.size, 0, "rgb(255, 255, 255)")
def _rescale(x):
return x / self.grid_side_length * config.size
for city in self.cities:
out.draw_circle(_rescale(city.x), _rescale(
city.y), 2, 0, config.city_color)
return out