Puzzleteile „mischen“
Da wir jetzt endlich die Puzzleteile zeichnen können, wollen wir nun zu Beginn auch die Reihenfolge der Teile zufällig festlegen. Dazu müssen wir natürlich erstmal klären, wie man überhaupt Zufallszahlen unter Assembler erzeugt, schließlich gibt es bei den Mnemonics kein RND(), wie im C64-BASIC.
Schaut euch bitte den Beitrag Zufallszahlen in Assembler an, bevor ihr hier weiter lest!!
Da ihr nun fit im Erzeugen von Zufallszahlen seid, wenden wir das Gelernte gleich mal bei unserem Puzzlespiel an.
Das Mischen einbauen
Wir werden nun einfach alle acht Puzzleteile auf die neun möglichen Felder verteilen. Dazu verwenden wir die TIMER-Zufallsroutine aus dem eingangs erwähnten Beitrag und fügen die folgenden Zeilen vor showScreen_Title in unser Programm ein.
;******************************************************************************* ;*** Zufallszahl per Timer-Verknüpfungen bilden. ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: Zufallszahl im Akku ;******************************************************************************* ;*** ändert : A, SR ;******************************************************************************* !zone rndTimer rndTimer lda $dc04 ;Low-Byte von Timer A aus dem CIA-1 eor $dc05 ;High-Byte von Timer A aus dem CIA-1 eor $dd04 ;Low-Byte von Timer A aus dem CIA-2 adc $dd05 ;High-Byte von Timer A aus dem CIA-2 eor $dd06 ;Low-Byte von Timer B aus dem CIA-2 eor $dd07 ;High-Byte von Timer B aus dem CIA-2 rts
Jetzt werden wir unsere acht Puzzleteile auf die neun verfügbaren Felder verteilen. Fügt die Funktion direkt vor der von eben ein.
;******************************************************************************* ;*** Die Puzzleteile zufällig verteilen ;******************************************************************************* ;*** Übergabe: - ;******************************************************************************* ;*** Rückgabe: Neue Position der Puzzleteile in der Tabelle tileOrder ;******************************************************************************* ;*** ändert : A, X, Y, SR ;******************************************************************************* !zone shuffleTiles shuffleTiles ldy #$08 ;alle 9 Felder lda #$ff ;als leer markieren .loop sta tileOrder,Y ;$ff in jedes Feld schreiben dey bpl .loop ldx #$07 ;die 8 Puzzleteile platzieren .loop1 jsr rndTimer ;Zufallszahl holen and #%00001111 ;wir brauchen nur 0-8, also unteres Nibble cmp #$09 ;ist die Zufallszahl größer als 8? bcs .loop1 ;wenn ja, eine neue holen tay ;Zufallszahl ins Y-Register (Feld-Pos.) lda tileOrder,Y ;Feld laden bpl .loop1 ;ist es nicht mehr frei ($ff), neue Zahl txa ;sonst aktuelles Teil (X-Reg) -> Akku sta tileOrder,Y ;und bei tileorder: speichern dex ;nächstes Puzzleteil bpl .loop1 ;solange noch eins da ist rts ;zurück
Am Anfang setzten wir erstmal alle Felder auf frei. Ihr erinnert euch? Der Wert $ff steht für das leere Feld. Anschließend benutzen wir das X-Register als Schleifenzähler für unsere 8 Puzzleteile und verteilen diese in der Schleife .loop1 auf die Felder.
Wir holen uns zunächst eine Zufallszahl per jsr rndTimer in den Akku. Diese legt fest, auf welchem Feld das aktuelle Puzzleteil (X-Register) landen soll. Da wir nur Zahlen von 0-8 (unsere Zählung beginnt wie so häufig bei 0!) benötigen, beschränken wir uns aufs untere Nibble. Dann kontrollieren, ob die Zahl kleiner als 9 ist, falls ja machen wir weiter, sonst holen wir uns eine neue Zufallszahl. Sobald wir eine gültige Zufallszahl haben, ab ins Y-Register damit. Nun müssen wir kontrollieren, ob das per Zufallszahl ermittelte Feld noch frei ist. Dazu einfach das Feld in den Akku holen und prüfen, ob der Wert positiv ist ($ff kennzeichnet ja ein freies Feld und dieser Wert ist negativ). Falls es bereits belegt ist, holen wir eine neue Zufallszahl, wenn aber nicht, dann speichern wir unser Puzzleteil aus dem X-Register in diesem Feld ab. Abschließend verringern wir das X-Register fürs nächste Puzzleteil und suchen für dieses ein freies Feld, bis alle Teile platziert sind.
Jetzt müssen wir die Funktion natürlich noch aufrufen. Fügt in puzzleMain vor der Zeile jsr loadSprites, einfach diese Zeile ein:
jsr shuffleTiles ;Das Puzzle mischen
Das war es schon alles.
Jetzt sollten die Puzzleteile bei jedem Start eine andere Position einnehmen.
OK ein / zwei Kleinigkeit fehlen eigentlich noch! Es könnte nun ja passieren, dass das Puzzle auch per Zufallsgenerator gleich gelöst wird, sprich alle Teile sind am richtigen Platz. Wir sollten uns auch noch fragen, ob das Puzzle wirklich immer lösbar ist, wenn wir die Teile reinzufällig setzen? Darum kümmern wir uns ein anderes Mal.
Auf dem D64-Image im Download findet ihr neben der hier entworfenen Version, auch noch ein „LOVE FAST“, das zeigt, wie flott alles läuft, obwohl wir bisher keinen Wert auf optimierte Abläufe gelegt haben. Außerdem gibt es dort ein „LOVE KEY“, das erst nach einem Tastendruck alles erneut durchmischt. Im herunterladbaren Projekt findet ihr am Anfang des Quellkodes, die zwei auskommentierten Konstanten FAST und KEY, mit denen ihr diese Funktionen aktivieren könnt.
Schritt 6 - Puzzle 006
Hier ist leider im zweiten Codebeispiel die falsche Funktion reingerutscht…
Das Problem konnte ich aber gut durch deinen runterladbaren Quelltext beheben, da ja da auch alles drin ist. :0D
Ich hoffe wirklich, dass irgendwann wieder neue Beiträge von dir kommen.. Ich hab schon leicht bammel, ab der Stelle, wo ich neue Sachen durch stundenlanges Suchen im Netz, lernen muss…
Geht zwar auch, aber dein Tutorial ist wirklich gut geschrieben und immer wieder mit richtig guten Erklärungen und Hintergrundinfos gespickt, darauf möchte ich eigentlich nicht verzichten…
Vielen Dank für den Hinweis, ich habe den Text eben angepasst.