Pchełki VBA: rysujemy spiralę Ulama w Excelu

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):

9
Dodaj komentarz

avatar
2 Comment threads
7 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
xpilElandir Recent comment authors
  Subscribe  
Powiadom o
Elandir
Gość
Elandir

Dziękuję ślicznie

Jak to odpalić? 🙂

Elandir
Gość
Elandir

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:

Elandir
Gość
Elandir

Hmm nie widać linku w komentarzu powyżej. Wklejam więc jeszcze raz tutaj:

link