-
Notifications
You must be signed in to change notification settings - Fork 4
/
grid.jou
112 lines (88 loc) · 3.43 KB
/
grid.jou
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
# This file contains a utility class for AoC solutions.
# It is not in the standard library because it feels too AoC-specific to me.
import "stdlib/ascii.jou"
import "stdlib/str.jou"
import "stdlib/mem.jou"
import "stdlib/io.jou"
class Grid:
width: int
height: int
data: byte*
def is_in_bounds(self, point: int[2]) -> bool:
x = point[0]
y = point[1]
return 0 <= x and x < self->width and 0 <= y and y < self->height
def get(self, point: int[2]) -> byte:
assert self->is_in_bounds(point)
x = point[0]
y = point[1]
return self->data[(self->width + 1)*y + x]
def set(self, point: int[2], value: byte) -> None:
assert self->is_in_bounds(point)
x = point[0]
y = point[1]
self->data[(self->width + 1)*y + x] = value
def swap(self, a: int[2], b: int[2]) -> None:
old_a = self->get(a)
self->set(a, self->get(b))
self->set(b, old_a)
def copy(self) -> Grid:
return Grid{width = self->width, height = self->height, data = strdup(self->data)}
def transpose(self) -> None:
old = self->copy()
self->width = old.height
self->height = old.width
self->data = realloc(self->data, (self->width + 1)*self->height + 1)
assert self->data != NULL
for y = 0; y < self->height; y++:
for x = 0; x < self->width; x++:
self->set([x, y], old.get([y, x]))
self->data[(self->width + 1)*y + self->width] = '\n'
free(old.data)
self->data[(self->width + 1)*self->height] = '\0'
# returned array is terminated by [-1, -1]
def find_all(self, b: byte) -> int[2]*:
result: int[2]* = malloc(sizeof(result[0]) * (self->width * self->height + 1))
result_len = 0
for y = 0; y < self->height; y++:
for x = 0; x < self->width; x++:
if self->get([x, y]) == b:
result[result_len++] = [x, y]
result = realloc(result, sizeof(result[0]) * (result_len + 1))
result[result_len] = [-1, -1]
return result
def find_first(self, b: byte) -> int[2]:
for y = 0; y < self->height; y++:
for x = 0; x < self->width; x++:
if self->get([x, y]) == b:
return [x, y]
assert False
def count(self, b: byte) -> int:
n = 0
for y = 0; y < self->height; y++:
for x = 0; x < self->width; x++:
if self->get([x, y]) == b:
n++
return n
# Reading stops on end of file or newline, so you can call this repeatedly
# to read multiple blank-line separated grids.
def read_grid_from_file(f: FILE*) -> Grid:
line: byte[5000]
max_size = 10000000 # 10 MB
result = Grid{data = malloc(max_size)}
result.data[0] = '\0'
while fgets(line, sizeof(line) as int, f) != NULL:
trim_ascii_whitespace(line)
if line[0] == '\0':
break
if result.height == 0: # set width on first round
result.width = strlen(line) as int
assert result.width == strlen(line)
result.height++
assert result.width * result.height < max_size
strcat(result.data, line)
strcat(result.data, "\n")
assert result.width != 0 and result.height != 0
assert strlen(result.data) == (result.width + 1)*result.height
result.data = realloc(result.data, strlen(result.data) + 1)
return result