let x = 0
let y = 0
let d = 1
let m = 1
while true
while 2 * x * d < m
print(x, y)
x = x + d
while 2 * y * d < m
print(x, y)
y = y + d
d = -1 * d
m = m + 1
Było wiele propozycji rozwiązań tego problemu napisanych w różnych językach programowania, jednak wszystkie wydają się wynikać z tego samego zawiłego podejścia. Rozważę bardziej ogólny problem obliczania spirali, którą można zwięźle wyrazić za pomocą indukcji.
Podstawowy przypadek: zacznij od (0, 0), przejdź do przodu o 1 pole, skręć w lewo, przejdź do przodu o 1 pole, skręć w lewo. Krok indukcyjny: przesuń się do przodu o n + 1 pól, skręć w lewo, przejdź do przodu o n + 1 kwadratów, skręć w lewo.
Matematyczna elegancja wyrażenia tego problemu silnie sugeruje, że powinien istnieć prosty algorytm obliczania rozwiązania. Pamiętając o abstrakcji, zdecydowałem się nie implementować algorytmu w konkretnym języku programowania, ale raczej jako pseudokod.
Najpierw rozważę algorytm obliczający tylko 2 iteracje spirali przy użyciu 4 par pętli while. Struktura każdej pary jest podobna, ale odrębna na swój sposób. Na początku może się to wydawać szalone (niektóre pętle są wykonywane tylko raz), ale krok po kroku będę dokonywać transformacji, aż dojdziemy do 4 identycznych par pętli, które można zastąpić pojedynczą parą umieszczoną w innej pętli. To zapewni nam ogólne rozwiązanie obliczania n iteracji bez używania jakichkolwiek warunków.
let x = 0
let y = 0
//RIGHT, UP
while x < 1
print(x, y)
x = x + 1
while y < 1
print(x, y)
y = y + 1
//LEFT, LEFT, DOWN, DOWN
while x > -1
print(x, y)
x = x - 1
while y > -1
print(x, y)
y = y - 1
//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x < 2
print(x, y)
x = x + 1
while y < 2
print(x, y)
y = y + 1
//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x > -2
print(x, y)
x = x - 1
while y > -2
print(x, y)
y = y - 1
Pierwszą transformacją, której dokonamy, będzie wprowadzenie nowej zmiennej d dla kierunku, która ma wartość +1 lub -1. Kierunek zmienia się po każdej parze pętli. Ponieważ znamy wartość d we wszystkich punktach, możemy pomnożyć przez nią każdą stronę każdej nierówności, odpowiednio dostosować kierunek nierówności i uprościć wszelkie mnożenia d przez stałą do innej stałej. Pozostaje nam to, co następuje.
let x = 0
let y = 0
let d = 1
//RIGHT, UP
while x * d < 1
print(x, y)
x = x + d
while y * d < 1
print(x, y)
y = y + d
d = -1 * d
//LEFT, LEFT, DOWN, DOWN
while x * d < 1
print(x, y)
x = x + d
while y * d < 1
print(x, y)
y = y + d
d = -1 * d
//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < 2
print(x, y)
x = x + d
while y * d < 2
print(x, y)
y = y + d
d = -1 * d
//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < 2
print(x, y)
x = x + d
while y * d < 2
print(x, y)
y = y + d
Teraz zauważamy, że zarówno x * d, jak i RHS są liczbami całkowitymi, więc możemy odjąć dowolną wartość rzeczywistą z zakresu od 0 do 1 od RHS bez wpływu na wynik nierówności. Decydujemy się odjąć 0,5 od nierówności każdej innej pary pętli while, aby uzyskać więcej wzoru.
let x = 0
let y = 0
let d = 1
//RIGHT, UP
while x * d < 0.5
print(x, y)
x = x + d
while y * d < 0.5
print(x, y)
y = y + d
d = -1 * d
//LEFT, LEFT, DOWN, DOWN
while x * d < 1
print(x, y)
x = x + d
while y * d < 1
print(x, y)
y = y + d
d = -1 * d
//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < 1.5
print(x, y)
x = x + d
while y * d < 1.5
print(x, y)
y = y + d
d = -1 * d
//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < 2
print(x, y)
x = x + d
while y * d < 2
print(x, y)
y = y + d
Możemy teraz wprowadzić inną zmienną m dla liczby kroków, które wykonujemy w każdej parze pętli while.
let x = 0
let y = 0
let d = 1
let m = 0.5
//RIGHT, UP
while x * d < m
print(x, y)
x = x + d
while y * d < m
print(x, y)
y = y + d
d = -1 * d
m = m + 0.5
//LEFT, LEFT, DOWN, DOWN
while x * d < m
print(x, y)
x = x + d
while y * d < m
print(x, y)
y = y + d
d = -1 * d
m = m + 0.5
//RIGHT, RIGHT, RIGHT, UP, UP, UP
while x * d < m
print(x, y)
x = x + d
while y * d < m
print(x, y)
y = y + d
d = -1 * d
m = m + 0.5
//LEFT, LEFT, LEFT, LEFT, DOWN, DOWN, DOWN, DOWN
while x * d < m
print(x, y)
x = x + d
while y * d < m
print(x, y)
y = y + d
Wreszcie widzimy, że struktura każdej pary pętli while jest identyczna i można ją zredukować do pojedynczej pętli umieszczonej wewnątrz innej pętli. Ponadto, aby uniknąć używania liczb o wartościach rzeczywistych, pomnożyłem początkową wartość m; wartość m jest zwiększana o; i obie strony każdej nierówności o 2.
Prowadzi to do rozwiązania przedstawionego na początku tej odpowiedzi.