image image


image

Nostalgie pur: Waldbrandsimulation im Terminal (mit Python)

Al Sweigart hat ein Buch geschrieben. Das ist keine wirkliche Meldung, denn Al Sweigart ist ein äußerst umtriebiger Autor, der als Verfasser etlicher Programmierbücher (meist zu Python) bekannt ist, von denen nicht nur viele bei No Starch Press erschienen sind, sondern die auch kostenlos von der Homepage des Autors heruntergeladen werden können. Aber – und das ist die Meldung – eines dieser Bücher heißt »The Big Book of Small Python Projects« und die Programme in diesem Buch sind so konzipiert, daß sie alle im Terminal ausgeführt werden können. Mehr Nostalgie geht eigentlich nicht.

Damit die Programme auch einen Hauch von Interaktivität besitzen und der Leser seine gewohnte GUI nicht allzusehr vermißt, hat Al Sweigart in vielen Beispielen dafür Bext genutzt, ein Python-Moduls, das er auch selber geschrieben hat. Bext ist ein freies (eigene Lizenz), plattformübergreifendes Pyhton-2/3-Modul, um Farbe in sonst langweilige, textbasierte Terminal-Programme zu bringen. Das Modul kann verwendet werden, um den Cursor im Terminalfenster zu bewegen und Text farbig auszugeben, ähnlich wie damals (1978-1983) die VT100-Terminals. Es ist als ein eingedampftes Replacement für das Curses-Modul aus der Python-Standard-Bibliothek gedacht, da dieses zwar unter Linux und macOS, aber (ohne seltsame Klimmzüge) nicht unter Windows funktioniert.

Ich habe aus diesem Buch mal den Waldbrand-Simulator nachprogrammiert (Seite 132-136). Ein ähnliches Programm hatte ich vor Jahren selber auch einmal in Processing.py geschrieben, damals natürlich mit einer graphischen Oberfläche. Al Sweigart hat sich – genau wie ich – zu diesem Programm von Nick Cases Aufsatz »Simulating the World in Emojis« aus dem Jahre 2016 inspirieren lassen. Hier ist der leicht modifizierte Quellcode der Terminal-Fassung von Al Sweigart:

import random, sys, time, bext

# Konstanten-Deklaration
WIDTH = 79
HEIGHT = 22
TREE  = "A"
FIRE  = "W"
EMPTY = " "

# Parameter, mit denen experimentiert werden kann
INITIALER_BAUM_BESTAND = 0.2
WACHSTUMSRATE = 0.01           # Rate, wie oft auf einer leeren Zelle ein Baum wächst
BRANDGEFAHR   = 0.05           # Rate, wie oft ein Brand ausbricht
PAUSE         = 0.5

def main():
    forest = create_new_forest()
    bext.clear()
    
    while True:               # Hauptschleife der Simulation
        display_forest(forest)
        
        # Simulations-Schritte
        next_forest = {"width": forest["width"], "height": forest["height"]}
        for x in range(forest["width"]):
            for y in range(forest["height"]):
                if (x, y) in next_forest:
                    # Wenn der Wert schon in einer vorherigen Iteration
                    # gesetzt wurde, tue nichts
                    continue
                
                if ((forest[(x, y)] == EMPTY) and (random.random() <= WACHSTUMSRATE)):
                    # Neuer Baum
                    next_forest[(x, y)] = TREE
                elif ((forest[(x, y)] == TREE) and (random.random() <= BRANDGEFAHR)):      
                    # Zünde Baum an
                    next_forest[(x, y)] = FIRE
                elif forest[(x, y)] == FIRE:
                    # Wenn der Baum brennt, untersuche die Nachbarfelder …
                    for ix in range(-1, 2):
                        for iy in range(-1, 2):
                            # Wenn Baum, dann anzünden
                            if forest.get((x + ix, y + iy)) == TREE:
                                next_forest[(x + ix, y + iy)] = FIRE
                    # und lösche den brennenden Baum
                    next_forest[(x, y)] = EMPTY
                else:
                    # Kopiere das Feld in die nächste Iteratrion
                    next_forest[(x, y)] = forest[(x, y)]
        
        forest = next_forest
        time.sleep(PAUSE)
        
def create_new_forest():
    forest = {"width": WIDTH, "height": HEIGHT}
    for x in range(WIDTH):
        for y in range(HEIGHT):
            if (random.random()*100) <= INITIALER_BAUM_BESTAND:
                # Pflanze einen Baum
                forest[(x, y)] = TREE
            else:
                forest[(x, y)] = EMPTY
    return(forest)

def display_forest(forest):
    bext.goto(0, 0)
    for y in range(forest["height"]):
        for x in range(forest["width"]):
            if forest[(x, y)] == TREE:
                bext.fg("green")
                print(TREE, end="")
            elif forest[(x, y)] == FIRE:
                bext.fg("red")
                print(FIRE, end="")
            elif forest[(x, y)] == EMPTY:
                print(EMPTY, end="")
        print()
    bext.fg("reset")     # Auf Terminal-Standard-Einstellung zurücksetzen
    print("Wachstumsrate: {}%  ".format(WACHSTUMSRATE*100), end="")
    print("Brandgefahr: {}%  ".format(BRANDGEFAHR*100), end="")
    print("Mit CTRL-C beenden.")
    
if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        sys.exit()

Natürlich muß man das Programm im Terminal laufen lassen, wenn man es in seiner ganzen Pracht genießen will. In Thonny erreicht man das entweder über CMD-T oder das Menü Ausführen -> Aktuelles Skript im Terminal ausführen. Und man sollte während der Ausführung die Größe des Terminal-Fensters nicht mehr verändern, es stellt sich beim Start schon auf die optimale Größe ein.

Natürlich ist das alles Nostalgie pur, aber das ist ja momentan en vogue. So könnte man mit dem Modul beispielsweise das jüngst vorgestellte »AppleSoft BASIC Snake Game« nachprogrammieren, ohne einen Apple II-Emulator zu bemühen oder sich mit BASIC herumumquälen zu müssen. Und Hardcore-Nostalgiker könnten ein Roque-like wie zum Beispiel NetHack mit der klassischen ASCII-Oberfläche nachprogrammieren – mit dem Spieler als @. Wäre doch ziemlich stilecht für mein Projekt »Retrogaming und Künstliche Intelligenz«, oder? Still digging!

Wer jetzt Blut geleckt hat: Bext ist auf PyPI zu finden und kann mit pip install bext installiert werden.


(Kommentieren) 

image image



Über …

Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!

Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.

Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.

Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.


Werbung

Diese Spalte wurde absichtlich leergelassen!


Werbung


image  image  image
image  image  image


image