Tole imamo še od prej.
import numpy as np
import re
= np.array([[line.startswith("on")] +
instr int(x) for x in re.findall("-?\d+", line)]
[for line in open("example2.txt")])
2, 4, 6]] += 1 instr[:, [
Zdaj zberimo vse možne koordinate x
, vse možne
koordinate y
in vse možne koordinate z
.
Koordinate x
najdemo v stolpcih 1 in 2. Vzemimo takšno
matriko, sploščimo jo in sestavimo množico njenih elementov. Podobno za
y
in z
.
= set(instr[:, 1:3].flatten())
xs = set(instr[:, 3:5].flatten())
ys = set(instr[:, 5:7].flatten()) zs
Os x
bo razrezana na vseh številkah, ki se pojavijo v
xs
. Uredimo te meje in jih zložimo v tabele. Da so v
tabelah, nam bo prišlo prav malo kasneje.
= np.array(sorted(xs))
xa = np.array(sorted(ys))
ya = np.array(sorted(zs)) za
Zdaj pa pripravimo slovarje, s katerimi bomo za vsako mejo izvedeli njihovo zaporedno številko.
= {x: i for i, x in enumerate(xa)}
xs = {x: i for i, x in enumerate(ya)}
ys = {x: i for i, x in enumerate(za)} zs
Dimenzije tabele, ki predstavlja stanje reaktorja bodo enake številu
blokov. 1
nam ni potrebno prišteti, ker zadnje število
vedno predstavlja le gornjo mejo; bloka s to številko nikoli ne bomo
prižgali ali ugasnili.
= np.zeros((len(xs), len(ys), len(zs)), dtype=bool) reactor
Zdaj pa gremo čez navodila ter prižigamo in ugašamo bloke v podanih intervalih (številk).
for on, x0, x1, y0, y1, z0, z1 in instr:
= on reactor[xs[x0]:xs[x1], ys[y0]:ys[y1], zs[z0]:zs[z1]]
Koordinate iz navodil preslikujemo v številke blokov prek slovarjev
xs
, ys
in zs
.
Stanje reaktorja zdaj poznamo: vemo, kateri bloki so prižgani. Da ugotovimo število prižganih celic, pa potrebujemo število celic v vsakem bloku. To dobimo takole:
= \
volumes 1:] - xa[:-1])[:, None, None] \
(xa[* (ya[1:] - ya[:-1])[:, None] \
* (za[1:] - za[:-1])
xa[1:] - xa[:-1]
so razmiki med zaporednimi koordinatami
v xs
- to so širine blokov po smeri x
. Podobno
za ostale dimenzije. Dimenziji x
dodamo še dve osi,
y
še eno in to zmnožimo skupaj. Zdaj bo
volumes[n][m][k]
dimenzija bloka, ki se začne na
n
-ti koordinati x
, m
-ti
koordinati y
in k
-ti koordinati
z
. Torej tistega bloka, katerega stanje opisuje
reactor[n][m][k]
. Prostornine vseh prižganih blokov dobimo
z volumes[reactor[:-1, :-1, :-1]]
. -1
moramo
odšteti zaradi gornjih mej (spet!). Očitno je
xa[1:] - xa[:-1]
, kolikor je dolg volumes
za 1
krajši od len(xs)
, kolikor je dolg reaktor.
Rezultat, ki ga iščemo, je torej
sum(volumes[reactor[:-1, :-1, :-1]]) np.
2758514936282235
Za preglednost in občutek je tu še celotna rešitev.
= set(instr[:, 1:3].flatten())
xs = set(instr[:, 3:5].flatten())
ys = set(instr[:, 5:7].flatten())
zs
= np.array(sorted(xs))
xa = np.array(sorted(ys))
ya = np.array(sorted(zs))
za
= {x: i for i, x in enumerate(xa)}
xs = {x: i for i, x in enumerate(ya)}
ys = {x: i for i, x in enumerate(za)}
zs
= np.zeros((len(xs), len(ys), len(zs)), dtype=bool)
reactor for on, x0, x1, y0, y1, z0, z1 in instr:
= on
reactor[xs[x0]:xs[x1], ys[y0]:ys[y1], zs[z0]:zs[z1]]
= \
volumes 1:] - xa[:-1])[:, None, None] \
(xa[* (ya[1:] - ya[:-1])[:, None] \
* (za[1:] - za[:-1])
sum(volumes[reactor[:-1, :-1, :-1]]) np.
2758514936282235
Razen imenitnega zaključka z računanjem prostornin je to bolj vaja iz
razmišljanja in Pythona kot iz numpy
-ja.