|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 04.02.2024, 01:21 Titel: Backgammon programmieren |
|
|
Backgammon programmieren
Hallo, ich wage mal einen Thread zu eröffnen, in dem wir alle unsere Backgammon-Gedanken gebündelt sammeln können.
Es wurde an anderen Stellen ja schon etwas diskutiert. (Hier und Hier)
Hier darf es um alle Teil-Aspekte von Backgammon und dessen Umsetzung gehen.
Hier darf über die grafische Umsetzung diskutiert werden, oder die Art der Datenstrukturen, die man besten verwendet. Es darf um Hauptmenüs oder Spielemenüs gehen, oder um die Umsetzung eines (simplen) Computergegners. Vielleicht gibt es Gedanken zum Thema Regelprüfungen oder zu erweiterten Regeln wie Punkteverdopplung...
Es gibt viel zu beachten, wenn man ein Spiel programmieren will.
Um ein allgemeines Verständnis zum Spiel zu haben, lege ich die Regeln, wie sie in der Wikipedia stehen, als Grundlage fest.
Dort steht z.B. klip und klar: "Das Spielbrett besteht aus 24 Dreiecken, Points oder Zungen genannt..."
Das vermeidet hoffentlich unnötige Diskussionen.
https://de.wikipedia.org/wiki/Backgammon#Spielregeln
Happy Coding _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 04.02.2024, 02:12 Titel: Layout |
|
|
Layout
Da ich ein visuell veranlagter Mensch bin, fange ich gerne mit etwas grafischem an. Hier mein Vorschlag einer möglichen Anordnung. Ich achte darauf, möglichst losgelöst von der Auflösung ein Layout zu basteln.
In meinem Beispiel muss ich nur das äußere Rechteck festlegen (obere linke Ecke, sowie Breite und Höhe) und das Spielfeld baut sich automatisch an diesem Rechteck an:
[img]https://gdurl.com/2OM6[/img]
Die Nummern würde ich später rausnehmen. Das ganze würde ich dann noch mit spitzen Dreiecken statt mit Rechtecken ausschmücken. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht.
Zuletzt bearbeitet von SpionAtom am 05.02.2024, 08:47, insgesamt einmal bearbeitet |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 04.02.2024, 16:58 Titel: |
|
|
SpionAtom hat Folgendes geschrieben: | Das ganze würde ich dann noch mit spitzen Dreiecken statt mit Rechtecken ausschmücken. | Hast du denn schon eine Idee, wie du das mit dem Befehlssatz von QBasic bewerkstelligen kannst? Soweit ich weiss, kann QB nur waagerechte und senkrechte Linien zeichnen.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Koala
Anmeldungsdatum: 24.11.2023 Beiträge: 9
|
Verfasst am: 04.02.2024, 17:05 Titel: |
|
|
SpionAtom hat Folgendes geschrieben: | Layout
In meinem Beispiel muss ich nur das äußere Rechteck festlegen (obere linke Ecke, sowie Breite und Höhe) und das Spielfeld baut sich automatisch an diesem Rechteck an:
[img]https://gdurl.com/2OM6[/img]
Die Nummern würde ich später rausnehmen. Das ganze würde ich dann noch mit spitzen Dreiecken statt mit Rechtecken ausschmücken. |
Gemäß den Regeln besteht das Spielbrett aus 24 Dreiecken (nicht Rechtecken) -
insofern ist das keine Ausschmückung, sondern eigentlich erforderlich.
[img]https://gdurl.com/INpA[/img]
https://drive.usercontent.google.com/download?id=1OVZkF-L6UjlrthwCPCoqPrW2Hxo983tF
Das war Dir hier schon sehr gut gelungen, mir gefielen diese Dreiecke.
Wie gesagt, die 5 schwarzen Steine (und auch die 3 schwarzen daneben) müssen ein Feld nach rechts plaziert werden - dann ist's die Ausgangsstellung.
Vor einigen Monaten hat Trevor Slocum ein Freeware-Backgammonprogramm namens tabula geschrieben und das "Design" seines Programms näher beschrieben:
https://code.rocket9labs.com/tslocum/tabula/src/branch/main/DESIGN.md
Der Source Code (in der Sprache Go) steht hier zum Download bereit:
https://code.rocket9labs.com/tslocum/tabula/
Auf seinem Server bgammon.org kann man kostenlos gegen tabula spielen.
Tolles Projekt !
Viel Spaß beim Backgammon(Programmieren) !
Koala |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 05.02.2024, 08:46 Titel: Zacken zeichnen |
|
|
Zacken zeichnen
grindstone hat Folgendes geschrieben: | Hast du denn schon eine Idee, wie du das mit dem Befehlssatz von QBasic bewerkstelligen kannst? Soweit ich weiss, kann QB nur waagerechte und senkrechte Linien zeichnen.
|
Gleichmäßige gefüllte Dreiecke, die gerade nach oben oder unten zeigen, kann man recht simpel mit "geraden" Linien umsetzen.
Es reicht eine simple Prozentrechnung. Beispiel nach oben gezacktes Dreieck:
Man zeichnet das Dreieck Zeile für Zeile, in der obersten Zeile hat das Dreieck die minimale Breite (0% bzw. aufgerundet einen Pixel), in der untersten Zeile die volle Breite (100%) . Generell errechnet sich die Breite in allen Zeilen durch einen Prozentwert von der maximalen Breite: zeilenBreite% = (zeile! / maximalBreite%) * maximalBreite%
Man beachte, dass die Division eine Float-Berechnung sein muss und keine Integer-Ganzzahlen-Berechnung.
Ferner könnte man auch mit dem DRAW-Befehl oder mit PAINT hantieren, um Flächen auszufüllen.
Code: | Sub drawPoint(p as BoardPoint)
Color p.c
If p.d = 1 Then 'Nach unten gezackt
For i = 0 To p.h - 1
r = (1 - (i) / p.h) * p.w / 2
Line (p.x - r, p.y + i)-(p.x + r, p.y + i)
Next
Else
If p.d = -1 Then 'Nach oben gezackt
For i = 0 To p.h - 1
r = (1 - (i) / p.h) * p.w / 2
Line (p.x - r, p.y - i)-(p.x + r, p.y - i)
Next
End If
End if
End Sub |
Es gibt auch Algorithmen für allgemeine Dreiecke. Eine Google-Suche liefert viele Ergebnisse:
http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html
https://gabrielgambetta.com/computer-graphics-from-scratch/07-filled-triangles.html _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 05.02.2024, 16:00 Titel: |
|
|
Wie sieht das denn mit der Ausführungsgeschwindigkeit aus? Denn die SUB rechnet das ja quasi "zu Fuß" aus. Ich habe dazu ein kleines Testprogramm geschrieben Code: | TYPE BoardPoint
c AS INTEGER
x AS INTEGER
y AS INTEGER
d AS INTEGER
w AS INTEGER
h AS INTEGER
END TYPE
DECLARE SUB drawPoint (p AS BoardPoint)
SCREEN 1
DIM test AS BoardPoint
test.c = 1
test.w = 20
test.h = 100
test.x = 20
test.y = 0
test.d = 1
CALL drawPoint(test) | aber ich kann das leider nicht im Original testen, weil ich hier im Interpreter bei SCREEN 1 nur einen schwarzen Bildschirm sehe, aus dem ich nur rauskomme, indem ich den Interpreter im Taskmanager abschieße.
Im FbEdit mit Option QB läuft das Programm, aber da ist es ja kompiliert, so daß ich keine Aussage über die Geschwindigkeit machen kann.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 06.02.2024, 13:48 Titel: |
|
|
Gut reverse engineered
Es geht schon recht fix. Ich hatte bisher im SCREEN 7 gearbeitet, um mir Page-Flipping bzw. Double Buffering offen zu halten.
Da ich jedoch bisher keine augenbetörenden Animationen vorgesehen hatte, bin ich nicht auf eine konstante Framerate angewiesen und die Grafik muss nicht in Echtzeit erzeugt werden.
Die Zacken sind zudem noch sehr repetitiv, so kann man sich überlegen, diese in Sprites zu packen (, was ich auch mit den Spielsteinen gemacht habe, aber dazu später mehr).
Möglicherweise gehe ich für die höhere Auflösung auf SCREEN 12. _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4604 Wohnort: ~/
|
Verfasst am: 06.02.2024, 17:53 Titel: |
|
|
Ein fertig gezeichnetes Spielbrett (ohne Steine) ließe sich dann ja immer noch mit BSAVE / BLOAD sichern bzw. von der Festplatte laden. Dann wäre auch ein (einmaliger) längerer Zeichenprozess unproblematisch. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 06.02.2024, 18:18 Titel: |
|
|
Nur mal, um meine Neugierde zu befriedigen: Ich habe die SUB drawPoint so umgeschrieben, daß sie die Aussenlinien der Zacken mithilfe des Bresenham-Algorithmus berechnet und dann jeweils eine Linie zwischen diesen Punkten zieht.
Code: | SUB drawPoint2 (p AS BoardPoint)
COLOR p.c
IF p.d = 1 THEN 'Nach unten gezackt
w% = p.w/2
a% = p.x - w%
e% = p.x + w%
FOR i% = 0 TO p.h - 1
c% = c% + w%
If c% >= p.h Then
a% = a% + 1
e% = e% - 1
c% = c% - p.h
EndIf
LINE (a%, i%)-(e%, i%)
Next
ELSEIF p.d = -1 THEN 'Nach oben gezackt
w% = p.w/2
a% = p.x - w%
e% = p.x + w%
FOR i% = p.y TO p.y - p.h - 1 Step -1
c% = c% + w%
If c% >= p.h Then
a% = a% + 1
e% = e% - 1
c% = c% - p.h
EndIf
LINE (a%, i%)-(e%, i%)
NEXT
END IF
End Sub |
Hier bei mir hat dieses Verfahren nur einen geringen Geschwindigkeitsvorteil (0,229 zu 0,260 Sekunden für 10000 Aufrufe), aber das Programm ist ja auch kompiliert, und der Compiler optimiert das Ganze von sich aus noch einmal. Außerdem verwendet die so entstandene .exe - Datei die Fliesskommaeinheit des Prozessors, was beim QB-Interpreter wohl nicht der Fall sein dürfte. Daher würde mich interessieren, was der QB-Interpreter zu dieser SUB sagt, da man sich durch den Bresenham-Algorithmus die (Fliesskomma-)Division einschliesslich aller internen Umrechnungen erspart.
Wenn du sie vielleicht einmal für mich testen könntest?
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1215 Wohnort: Ruhrpott
|
Verfasst am: 06.02.2024, 18:28 Titel: |
|
|
nemored hat Folgendes geschrieben: | Ein fertig gezeichnetes Spielbrett (ohne Steine) ließe sich dann ja immer noch mit BSAVE / BLOAD sichern bzw. von der Festplatte laden. Dann wäre auch ein (einmaliger) längerer Zeichenprozess unproblematisch. | Oder auch nur die einzelnen Zacken, es gibt ja nur 4 verschiedene: nach oben und nach unten in jeweils 2 Farben. Da die Dateien auf einem modernen Rechner aus den Cache geladen werden, dürfte das wahrscheinlich die schnellste Methode sein.
Gruß
grindstone
PS:
Oder sogar für jede Zackenvariante eine eigene Datei für jede Anzahl von Steinen, die auf dem Zacken liegt... _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 07.02.2024, 15:44 Titel: |
|
|
Da kann ich auch nur mit der Dosbox dienen für den Interpreter Test. Ich probiere es später aus.
EDIT: @grindstone
Ich testete - wie gesagt in der Dosbox - und habe je 100 Durchläufe gestoppt:
Spion: 2.859375s
Grind: 1.863281s
Nur die erste Nachkommastelle war einigermaßen konstant bei mehreren Tests, sollte aber aussagekräftig genug sein. Am Ende kann man sagen: Bei 100 Dreiecken gewinnt deine optimierte Methode ca. 1 Sekunde _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
SpionAtom
Anmeldungsdatum: 10.01.2005 Beiträge: 339
|
Verfasst am: 15.02.2024, 00:23 Titel: Funktionsbibliothek für Backgammon |
|
|
Funktionsbibliothek für Backgammon
Ich finde es ganz zuträglich, die Spielmechaniken von der Grafik zu trennen.
Das Spiel selber wird in folgenden Variablen festgehalten:
DIM SHARED zungen(24) AS TZunge
DIM SHARED spieler(2) AS TSpieler
DIM SHARED aktuellerSpieler AS INTEGER
zungen ist ein Array, welches speichert, wieviele schwarze oder weiße Steine auf den einzelnen Zungen liegen.
spieler ist ein Array, welches die beiden Spieler festhält, mit Namen, so wie die Anzahl der Steine im Ziel und der Anzahl der Steine, die auf der Bar liegen.
aktuellerSpieler ist eine Variable, die angibt, welcher Spieler an der Reihe ist.
der Funktionsumfang ist noch recht eingeschränkt, und auch noch lange nicht vollständig (so kann man z.B. zwar schon Steine bewegen, und es gibt eine rudimentäre Prüfung, ob der Zug möglich ist. Es ist aber noch nicht möglich Steine ins Zielfeld zu bewegen).
Es fehlen auch noch Funktionen zum Würfeln, oder um Steine aus der Bar zu bekommen.
Ihr könnt das gerne einmal ausprobieren. Ist etwas umständlich mit dem Eingabe-Menü, und auch die Grafik habe ich erstmal komplett ausgeklammert, aber zum Testen reicht es.
Code: | 'BG-CORE.BAS
'Funktionsbibliothek für Backgammon
DEFINT A-Z
DECLARE SUB SpielerWechseln ()
DECLARE SUB bewegeStein (von%, nach%)
DECLARE FUNCTION bewegungMoeglich (von%, nach%)
DECLARE SUB zeigeSpielbrett ()
DECLARE SUB initSpiel ()
CONST TRUE = -1, FALSE = NOT TRUE
CONST WEISS = 1, SCHWARZ = 2
TYPE TZunge
schwarze AS INTEGER
weisse AS INTEGER
nummer AS INTEGER
END TYPE
TYPE TSpieler
nickname AS STRING * 12
farbe AS INTEGER 'kann WEISS oder SCHWARZ sein
ziel AS INTEGER
bar AS INTEGER
END TYPE
DIM SHARED zungen(24) AS TZunge
DIM SHARED spieler(2) AS TSpieler
DIM SHARED aktuellerSpieler AS INTEGER
DIM SHARED infoText$
spieler(WEISS).nickname = "Thomas"
spieler(SCHWARZ).nickname = "Teddy"
initSpiel
DO
COLOR 7, 1
CLS
zeigeSpielbrett
COLOR 7, 1
LOCATE 14, 1: PRINT "1) Spieler wechseln"
LOCATE 15, 1: PRINT "2) Einen Stein bewegen"
LOCATE 16, 1: PRINT "3) Spiel neu starten"
LOCATE 17, 1: PRINT "4) Ende"
INPUT "Aktion: ", aktion%
SELECT CASE aktion%
CASE 1: SpielerWechseln
CASE 2:
INPUT "Von: "; von%
INPUT "Nach: "; nach%
IF bewegungMoeglich(von%, nach%) = TRUE THEN
PRINT infoText$
bewegeStein von%, nach%
ELSE
PRINT infoText$
PRINT "Bewegung nicht m”glich."
INPUT "Taste", taste$
END IF
CASE 3: initSpiel
CASE 4: 'Loop verlassen
END SELECT
LOOP UNTIL aktion% = 4
END
DEFSNG A-Z
SUB bewegeStein (von%, nach%)
IF aktuellerSpieler = WEISS THEN
IF zungen(nach%).schwarze = 1 THEN 'Schwarzer Stein wird gecschlagen
zungen(nach%).schwarze = 0
spieler(SCHWARZ).bar = spieler(SCHWARZ).bar + 1
END IF
zungen(von%).weisse = zungen(von%).weisse - 1
zungen(nach%).weisse = zungen(nach%).weisse + 1
ELSE
IF zungen(nach%).weisse = 1 THEN 'Weiáer Stein wird geschlagen
zungen(nach%).weisse = 0
spieler(WEISS).bar = spieler(WEISS).bar + 1
END IF
zungen(von%).schwarze = zungen(von%).schwarze - 1
zungen(nach%).schwarze = zungen(nach%).schwarze + 1
END IF
END SUB
DEFINT A-Z
FUNCTION bewegungMoeglich (von%, nach%)
IF von% < 1 OR von% > 24 THEN infoText$ = "falscher Parameter von%: " + STR$(von%): bewegungMoeglich = FALSE: EXIT FUNCTION
IF nach% < 1 OR nach% > 24 THEN infoText$ = "falscher Parameter nach%: " + STR$(nach%): bewegungMoeglich = FALSE: EXIT FUNCTION
IF aktuellerSpieler = WEISS THEN
IF von% > nach% THEN infoText$ = "Der Spieler darf nur nach vorne ziehen": bewegunMoeglich = FALSE: EXIT FUNCTION
IF zungen(von%).weisse = 0 THEN infoText$ = "Auf dem von-Feld befindet sich kein Stein von diesem Spieler": bewegungMoeglich = FALSE: EXIT FUNCTION
IF zungen(nach%).schwarze > 1 THEN infoText$ = "Das Ziel ist vom anderen Spieler besetzt": bewegungMoeglich = FALSE: EXIT FUNCTION
ELSE
IF von% < nach% THEN infoText$ = "Der Spieler darf nur nach hinten ziehen": bewegungMoeglich = FALSE: EXIT FUNCTION
IF zungen(von%).schwarze = 0 THEN infoText$ = "Auf dem von-Feld befindet sich kein Stein von diesem Spieler": bewegungMoeglich = FALSE: EXIT FUNCTION
IF zungen(nach%).weisse > 1 THEN infoText$ = "Das Ziel ist vom anderen Spieler besetzt": bewegungMoeglich = FALSE: EXIT FUNCTION
END IF
bewegungMoeglich = TRUE
infoText$ = "Zug kann ausgefhrt werden"
END FUNCTION
DEFSNG A-Z
SUB initSpiel
'Alle Werte der Zungen zurcksetzen
FOR i% = 1 TO 24
zungen(i%).schwarze = 0
zungen(i%).weisse = 0
zungen(i%).nummer = i%
NEXT
'Startformation aufstellen
zungen(1).weisse = 2
zungen(6).schwarze = 5
zungen(8).schwarze = 3
zungen(12).weisse = 5
zungen(13).schwarze = 5
zungen(17).weisse = 3
zungen(19).weisse = 5
zungen(24).schwarze = 2
'Spielerwerte zurcksetzen
spieler(1).ziel = 0
spieler(1).bar = 0
spieler(2).ziel = 0
spieler(2).bar = 0
aktuellerSpieler = 1
END SUB
SUB SpielerWechseln
IF aktuellerSpieler = WEISS THEN
aktuellerSpieler = SCHWARZ
ELSE
aktuellerSpieler = WEISS
END IF
END SUB
SUB zeigeSpielbrett
FOR i% = 1 TO 24
COLOR 7, 1
LOCATE 11, 3 * i%
PRINT i%;
LOCATE 10, 3 * i%
IF zungen(i%).weisse > zungen(i%).schwarze THEN
COLOR 15, 1
PRINT zungen(i%).weisse;
ELSE
IF zungen(i%).schwarze > zungen(i%).weisse THEN
COLOR 0, 1
PRINT zungen(i%).schwarze;
END IF
END IF
NEXT
COLOR 15, 1
LOCATE 1, 1: PRINT spieler(1).nickname;
COLOR 7, 1
LOCATE 2, 1: PRINT "Bar: "; spieler(1).bar;
LOCATE 3, 1: PRINT "Ziel: "; spieler(1).ziel;
IF aktuellerSpieler = 1 THEN LOCATE 4, 1: PRINT "Du bist am Zug!"
COLOR 0, 1
LOCATE 1, 80 - LEN(spieler(2).nickname)
PRINT spieler(2).nickname;
COLOR 7, 1
LOCATE 2, 68: PRINT "Bar: "; spieler(1).bar;
LOCATE 3, 68: PRINT "Ziel: "; spieler(1).ziel;
IF aktuellerSpieler = 2 THEN LOCATE 4, 65: PRINT "Du bist am Zug!"
END SUB
|
Auf eine Verlinkung zu Github oder ähnliches würde ich gerne verzichten, um niemanden zu überfordern. Aber immer länger werdende Quelltexte machen in einem Forum auch nicht so richtig Spaß... ....muss mir noch überlegen, wie ich das demnächst darstellen werde.[/b] _________________ Inzwischen gehöre ich auch zu den BlitzBasicern. Also verzeiht mir, wenn mir mal ein LOCATE 100, 100 oder dergleichen rausrutscht. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|