Najprej preberemo podatke. Tu ni nič takšnega, česar ne bi že videli.
import numpy as np
= open("example.txt").read().split("\n\n")
mapping, state = np.array([c == "#" for c in mapping.replace("\n", "")])
mapping = np.array([[c == "#" for c in v.strip()] for v in state.splitlines()]) state
Zdaj je mapping
tabela, ki pove, v kakšno stanje se
preslika posamezna vsota. Če bomo imeli vsote
= np.array([[7, 3, 2],
sums 0, 5, 1]]) [
se bo to preslikalo v
mapping[sums]
array([[ True, False, True],
[False, False, False]])
V zanki bomo počeli tole.
Najprej pripravimo tabelico, ki v sredi vsebuje trenutno stanje, okrog nje pa je dva elementa širok rob, ki vsebuje ničle za sode in enice z lihe korake, saj "neskončna okolica" utripa.
= 0
i
= state.shape
h, w = np.full((h + 4, w + 4), i % 2)
padded 2:-2, 2:-2] = state padded[
Matriko smo sestavili z np.full
, potem pa v sredino
prepisali trenutno stanje.
Nato pripravimo tabelico za vsote. Ta bo za dve polji večja od
trenutnega stanja, saj se "obljudeni" del tabele vsakič poveča za
1
v vsako smer.
= np.zeros((h + 2, w + 2), dtype=int) sums
In zdaj je na vrsti seštevanje. Namesto da bi računali vsoto za vsako
celico posebej, bomo prištevali padded
k vsotam,
takole:
= 256
p for y in range(3):
for x in range(3):
+= p * padded[y:y + h + 2, x:x + w + 2]
sums //= 2 p
y
in x
sta odmik od zgornjega in od desnega
roba, oba gresta od 0 do 1.
padded[y:y + h + 2, x:x + w + 2]
je torej "okno" v
padded
, ki je enakih dimenzij kot sums
in se
pomika prek padded. Prištevamo ga k sums
(kar smemo, saj
sta enakih dimenzij. Ob prvem prištevanju (tistem brez odmikov) ga
množimo z 256
, ob drugem k 128
in tako
naprej.
Kako to deluje - in zakaj deluje - se prepričajte sami.
Predstavljajte si nek element sum
(ne ravno čisto robnega,
naj bo nekje na sredi) in razmislite, kateri elementi
padded
se prištejejo vanj ter s kakšnimi faktorji.
Ko dobimo vsote, jih premapiramo čez mapping
.
mapping[sums]
array([[False, True, True, False, True, True, False],
[ True, False, False, True, False, True, False],
[ True, True, False, True, False, False, True],
[ True, True, True, True, False, False, True],
[False, True, False, False, True, True, False],
[False, False, True, True, False, False, True],
[False, False, False, True, False, True, False]])
To je to. Vse skupaj samo še zložimo v zanko.
import numpy as np
= open("example.txt").read().split("\n\n")
mapping, state = np.array([c == "#" for c in mapping.replace("\n", "")])
mapping = np.array([[c == "#" for c in v.strip()] for v in state.splitlines()])
state
for i in range(50):
= state.shape
h, w = np.full((h + 4, w + 4), i % 2)
padded 2:-2, 2:-2] = state
padded[= np.zeros((h + 2, w + 2), dtype=int)
sums = 256
p for y in range(3):
for x in range(3):
+= p * padded[y:h + 2 + y, x:w + 2 + x]
sums //= 2
p = mapping[sums]
state print(np.sum(state))
5097
Kot sem rekel: nič posebnega, samo kup drobnih zafrkancij.
Temu, kar počnemo v tej nalogi, se sicer reče konvolucija. Uporabljamo jo v procesiranju signalov in obdelavi slik, tudi globoke nevronske mreže pogosto vsebujejo konvolucijski nivo, ki počne nekaj podobnega, kot delamo v tej nalogi. Zato ima modul scipy, ki ga pogosto uporabljamo skupaj z numpyjem, funkcijo scipy.signal.convolve2d, ki počne natančno to, kar delamo znotraj te zanke.