Excel to wspaniałe narzędzie. Możemy w nim robić całkiem zaawansowane rzeczy: modele statystyczne, finansowe, symulacje, nawet średnią z kilku liczb jak się dobrze postaramy. No wypas.
Do rysowania piksel po pikselu Excel nadaje się jak pantograf do wyrabiania masła. Da się, ale co się człowiek przy tym namęczy to jego.
Niemniej jednak na niedawną prośbę jednego ze stałych czytelników blogu oto prezentuję WSWAJDMDRSUWE (Wolny, Słabo Wyglądający, Ale Jednak Działający Moduł Do Rysowania Spirali Ulama W Excelu):
Option Explicit
Public Sub Ulam1(ByVal r As String, ByVal maxn As Long)
' r: adres srodka spirali
' maxn: do ilu liczymy
Dim n As Long ' aktualna liczba (1..maxn)
Dim k As Integer ' dlugosc aktualnej krawedzi
Dim dx As Integer, dy As Integer ' kierunek kolejnego kroku; dx w poziomie, dy w pionie (dodatnie: prawo-gora, ujemne: lewo-dol)
Dim i As Long ' skrypt bez i jest jak ryba bez roweru
Dim sh As Excel.Range ' sh od "snake head" czyli robocza komorka w ktorej aktualnie jestesmy
Set sh = Range(r) ' zaczynamy od srodka
dx = 0 'zaczynamy od ruchu w gore
dy = 1
k = 1 'o jeden krok
ThisWorkbook.ActiveSheet.Cells.Clear
ActiveWindow.Zoom = 10
ThisWorkbook.ActiveSheet.Cells.ColumnWidth = 5
ThisWorkbook.ActiveSheet.Cells.RowHeight = 24
Do While n < = maxn
For i = 1 To k
sh.Value = n
If CzyPierwsza(n) Then
sh.Interior.Color = RGB(0, 0, 0)
sh.Font.Color = RGB(255, 255, 255)
Else
sh.Interior.Color = RGB(255, 255, 255)
sh.Font.Color = RGB(0, 0, 0)
End If
n = n + 1
If n Mod 100 = 0 Then DoEvents
Set sh = sh.Offset(-dy, dx)
Next i
' koniec krawedzi - zakrecamy
If dx = 0 And dy = 1 Then 'gora=>prawo
dx = 1
dy = 0
ElseIf dx = 0 And dy = -1 Then ' dol=>lewo
dx = -1
dy = 0
ElseIf dx = 1 And dy = 0 Then ' prawo=>dol, krawedz + 1
dx = 0
dy = -1
k = k + 1
ElseIf dx = -1 And dy = 0 Then ' lewo=>gora, krwedz + 1
dx = 0
dy = 1
k = k + 1
Else ' cos sie spiertenteges
MsgBox "!", vbOKOnly + vbExclamation
End
End If
Loop
End Sub
Public Function CzyPierwsza(ByVal n As Long) As Boolean
If n < 2 Then
CzyPierwsza = False
ElseIf n = 2 Or n = 3 Then CzyPierwsza = True
ElseIf n Mod 2 = 0 Then
CzyPierwsza = False
ElseIf n Mod 3 = 0 Then
CzyPierwsza = False
ElseIf n Mod 5 = 0 Then
CzyPierwsza = False
ElseIf n Mod 7 = 0 Then
CzyPierwsza = False
ElseIf n Mod 11 = 0 Then
CzyPierwsza = False
ElseIf n Mod 13 = 0 Then
CzyPierwsza = False
ElseIf n Mod 17 = 0 Then
CzyPierwsza = False
ElseIf n Mod 19 = 0 Then
CzyPierwsza = False
ElseIf n Mod 23 = 0 Then
CzyPierwsza = False
ElseIf n Mod 29 = 0 Then
CzyPierwsza = False
ElseIf n Mod 31 = 0 Then
CzyPierwsza = False
ElseIf n Mod 37 = 0 Then
CzyPierwsza = False
ElseIf n Mod 41 = 0 Then
CzyPierwsza = False
ElseIf n Mod 43 = 0 Then
CzyPierwsza = False
ElseIf n Mod 47 = 0 Then
CzyPierwsza = False
Else
Dim p As Integer ' pierwiastek
p = Sqr(n) + 1
Dim i As Integer
For i = 53 To p Step 2
If n Mod i = 0 Then
CzyPierwsza = False
Exit Function
End If
Next i
CzyPierwsza = True
End If
End Function
Ponieważ jestem leniwy, nie będę tu omawiał całego skryptu. Dodam tylko, że nieelegancka jest nie tylko pętla główna, ale również metoda sprawdzania pierwszości liczb (od 2 do 2207 mamy zakodowane na stałe sito Eratostenesa, powyżej tego po prostu sprawdzamy podzielność przez kolejne nieparzyste od 53 w górę aż do pierwiastka ze sprawdzanej liczby). Jednak skrypt jakimś cudem działa, więc chociaż trochę się wstydzę, to jednak go tu prezentuję.
Efekt końcowy (dla 10000 elementów) wygląda tak:
Dla 50000 - tak:
(przeskalowane 50% w dół)
A tu 230000 (więcej zasadniczo nie ma sensu, bo się nie mieści na ekranie):
Dziękuję ślicznie
Jak to odpalić? 🙂
Skopiować cały kod VBA do nowego modułu (drzewko po lewej jak zrobisz alt f11) potem ctrl – g i wpisujesz: ulam1 „AA50”, 1000
Przyznam się nie znałem tego sposobu uruchamiania makra. Dlatego chętnie tu zaglądam bo zawsze się czegoś nauczę 🙂
A teraz przyznam się, że jestem dość leniwy i nie chciało mi się czekać aż napiszesz ten kod i sam sobie napisałem :). Ja zrobiłem to tak, że w pętli sprawdzam czy są wypełnione komórki np. po lewej. Jeżeli coś tam jest to idzie w górę. Jak napotka pustą to sprawdza czy pod nią coś jest – jeżeli jest to idzie w lewo itp. Co do sprawdzania liczb pierwszych to tylko sprawdzam czy dzieli się bez reszty przez liczby od 2 do pierwiastka ze sprawdzanej liczby.
Jeżeli chodzi o samą spiralę to moją uwagę zwróciły te puste (bez liczb pierwszych) kolumny. Najpierw zauważyłem te dwie kolumny w dół taka autostrada. Potem jak się przyjrzałem to zauważyłem że w lewo i do góry również są drogi (po jednej kolumnie/wierszu) i kolejna autostrada w prawo.
Przeprowadziłem nawet eksperyment i z tej autostrady w dół robiłem macierz dodając jedną kolumnę do drugiej i zaznaczyłem na niej liczby pierwsze. Wyszło to:
Hmm nie widać linku w komentarzu powyżej. Wklejam więc jeszcze raz tutaj:
link
Ja z kolei zaobserwowałem, że wystarczy zwiększać długość krawędzi o jeden co dwa zakręty. Pewnie mógłbym też jakoś bardziej elegancko napisać samą zakrętologię, ale mi się nie chciało 😉 Co do sprawdzania pierwszości, liczby są tu na tyle niewielkie, że nie ma sensu jakakolwiek optymalizacja. Twoje podejście jest więc wystarczająco dobre…
Podobną spiralę można też narysować na bazie sześciokąta lub spirali Archimedesa, tylko wtedy wyliczenie kolejnej kropki jest o tyle utrudnione, że trzeba z każdym krokiem wyznaczyć współrzędne na podstawie długości jednostkowej, co pod skosem (lub po krzywej) nie jest całkiem banalne.
Pojawianie się ukośnych „autostrad” liczb pierwszych na spirali Ulama jest dość dobrze opisane na Wiki: https://en.wikipedia.org/wiki/Ulam_spiral#Explanation
Też na to wpadłem (ale już po napisaniu pierwszego makra) i przymierzam się do napisania tego w ten sposób tak dla ćwiczenia. 🙂
Co do autostrad to mnie bardziej ciekawią te bez liczb pierwszych. Te skośne z prajmami można tłumaczyć tym, że są na nich po prostu liczby nieparzyste więc i szansa wystąpienia prajmów większa. Sam fakt, że układają się w większe skupiska jest ciekawy i nie wiem czy można go wytłumaczyć przypadkiem. Z drugiej strony to jak widziałeś na tej mojej macierzy układają się podobnie.
Natomiast te puste mnie bardziej intrygują. Kto wie może tam leży tajemnica liczb pierwszych 🙂
Tam na tej stronie Wikipedii piszą coś o trójmianach i parzystości. Może tędy droga? Jeśli chodzi o rozwiązanie tajemnicy liczb pierwszych za pomocą spirali Ulama to jestem raczej konserwatywnie nastawiony. Nie tacy już próbowali 😉
No właśnie tylu już próbowało i przez tyle lat nic. Wychodzi na to, że nie znamy jeszcze działań matematycznych, które potrafią opisać liczby pierwsze 🙂 . Jeżeli więc nie matematyka to może grafika, i to być może wielowymiarowa. Znaleźć wzór, który będzie się powtarzał? A może poszukać w innych dziadzinach chemii, fizyce, muzyce itp.? Jaja by były jakby się okazało, że z liczb pierwszych można ułożyć niezły kawałek muzyczny 🙂 Taki przebój wszechczasów 🙂
Ciekawostka, uwaga nigdzie jeszcze nie publikowana 😉
Jeżeli spiralę Ulama „złożyć” na pół to pola z liczbami pierwszymi nie pokrywają się. Składać można z góry na dół albo w poprzek.
Zrobiłem makro, które „składa/łamie” spiralę w ten sposób, że gdy pola z liczbami pierwszymi się pokryją to zaznacza je na czerwono. Widać to przy „złożeniu” spirali na 4.
O ile się gdzieś nie rąbnąłem to „złożone” spirale wyglądają tak:
Fajne! Ciekawe czy ma jakieś zastosowanie.
Rzekła dziewica zobaczywszy prącie 🙂
A tak poważniej to ciężko powiedzieć czy jest tego jakieś zastosowanie. Ale chyba pokazuje jasno, że jest jakaś logika w liczbach pierwszych, a skoro jest to można ją znaleźć. Tylko może trzeba spojrzeć pod innym kątem.
Na ukos poskładaj…