Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

91

22.08.2008, 22:58

natürlich ists schwer... ich hab schon versucht den punkt aufgrund der maximalen geschwindigkeit, die der gegner bis zum ballaufschlag erreicht, zu berechnen, aber das funktioniert auch nicht so wirklich... :/ Also doch beim Alten in die Mitte fahren bleiben

92

23.08.2008, 14:41

Ich hab's schon geschafft, ihn zu berechnen (auf statistischer Basis), da der Gegner jedoch innerhalb zweier Zeiteinheiten in der Lage ist, den Schläger abzubremsen, kommt man mit der Korrektur der eigenen Position nicht so schnell hinterher, weshalb der Aufwand eigentlich soweit recht sinnlos ist.

Also dann doch lieber in Warteposition gehen... Und die kann man problemlos berechnen.

Pinta

1x Contest-Sieger

  • Private Nachricht senden

93

24.08.2008, 22:41

hihi!

Dieser Contest ist wirklich eine gelunge Abwechslung, würd ich einmal meinen! *grats* zur guten Idee! Ich denke solche grundsätzlich einfachen Sachen + competitive Auslegung machen das Ganze sehr interessant!

Ich hab mir Mal ein bisschen Zeit genommen und alles durchgesehen. Eine gute KI ist wohl mehr Aufwand, als man sich im ersten Moment denkt! Aber ich werd wahrscheinlich auch wieder mitmachen.

Ich hoffe nur, dass ich keine Endlosschleife produziere, fall eure KIs solche abnormalen Beschleunigungen in y Richtung vollführen...

Freu mich schon!

lg

94

26.08.2008, 10:36

Also erstmal, die Welt stuerzt nicht mehr ab, da kann meine MaxYSpeedKI machen was sie will. Leider habe ich folgendes festgestellt: Eine KI ausgelegt auf das pure Verteidigen ist schon hart zu knacken und meine Variante hat bis jetzt alles andere geschlagen, was von mir produziert wurde. Leider ist das auch eine zienlich langweilige KI. Zielen klappt auch nicht so gut, da in Abhaengigkeit der Schlaegergeschwindigkeit alles etwas (manchmal ganz schoen) zufaellig wird. Aber sonst waere es ja auch langweilig.

Da ich wahrscheinlich der einzige bin, der unter Linux und X11 das ganze macht, sind vielleicht die Anmerkung hier nur fuer das Protokoll:-). Auf System mit nur einem Kern/Prozessor ruckelt es ganz schoen und bei der Initialisierung (visual_start) bleit es manchmal haengen. Habe dann das do while auskommentiert und in der Threadprozedur ein pthread_yield eingefuegt. Jetzt laeuft es ganz gut. Da Tastendruecke asynchron verarbeitet werden, habe ich aufgegeben ein Interface fuer Menschen zu basteln. Da bevorzuge ich doch eher eine {input update render}-Routine.

Meine KI (oder das KI-Objekt) muss aber ueber die my_pong-Funktion hinaus erhalten bleiben, z.B. als globale Variable. Sonst vergisst sie staendig von update zu update, was sie eigentlich machen wollte. Aber ansonsten: meine KI wird euch alle fertig machen, muhahaha ...

95

26.08.2008, 11:37

Zitat von »"Genion"«


Und nochwas... wenn ich meine Funktion rekursiv aufrufen möchte, kann ich davon ausgehen, dass meine Methode (my_pong) im Test genauso heißt? Ich könnte zwar auch den ganzen Quelltext nochmal kopieren, aber Rekursion würde mir da Tipparbeit ersparen :D

Du koenntest deinen ganzen Code in eine extra Funktion schreiben und diese von my_pong aufrufen und trotzdem Rekursion verwenden. Ich hoffe aber persoenlich, dass deine KI (als auch die aller anderen) nicht allzu rechenintensiv ist, da es sich nur um Pong handelt. Wenn meine jetzigen KIs gegeneinander antreten, dann dauert ein Spiel etwa 400.000 Zeitschritte und etwa 2min auf einem betagten Rechner. Wie soll man das denn auswerten, wenn jeder ne Art Tiefensuche macht und pro Zeitschritt lange braucht?

S.Seegel

2x Contest-Sieger

  • Private Nachricht senden

96

26.08.2008, 13:33

Zitat von »"knivil"«

Da ich wahrscheinlich der einzige bin, der unter Linux und X11 das ganze macht

Bist du nicht. Willkommen im Club ;)
Performance-Probleme wie von dir beschrieben habe ich nicht. Hin und wieder endet die Simulation jedoch mit einem BadWindow X Fehler. Der kommt mutmaßlich daher, dass der Event-Thread beim Beenden immer versucht das Fenster zu unmappen, auch, wenn es bereits zerstört wurde. Ich kenne mich mit X-lowlevel-Details nicht aus, aber ein Verschieben des XWindowUnmap in die Behandlung der ClientMessage sollte das Problem meinem Verständnis nach lösen.

Zitat von »"knivil"«

Da Tastendruecke asynchron verarbeitet werden, habe ich aufgegeben ein Interface fuer Menschen zu basteln. Da bevorzuge ich doch eher eine {input update render}-Routine

Da kann ich dir aushelfen. Das Prinzip ist ganz simple:
eine globale Variable, die dekrementierst (inkrementierst) wird, wenn die Pfeil-rauf-Taste gedrückt (losgelassen) wird, und - analog dazu - inkrementiert (dekrementiert) wird, wenn die Pfeil-runter-Taste gedrückt (losgelassen) wird.
Somit enthält diese Variable immer den Beschleunigungsbefehl des Users (-1 wenn nur Up, 0 wenn weder Up noch Down oder aber alle beide, 1 wenn nur Down gedrückt sind).
Diese Variable wird nur vom Event-Thread verändert, vom Simulations-/UI-Upfate-Thread nur gelesen, und muss daher nicht durch ein mutex geschützt werden.

Der "KI" bleibt dann nur noch, den Wert dieser Variablen zurückzugeben.

Das Ganze sieht dann so aus:
In pong.h wird die Deklaration der globalen Variable eingefügt

C-/C++-Quelltext

1
2
// user input

extern int move;


In visualizer_x11.cpp wird die Variable definiert

C-/C++-Quelltext

1
int move = 0;

und die thread_proc() Funktion angepasst, so dass zum einen KeyRelease-Events vom X-Server angefordert werden, und zum anderen KeyPress- und KeyRelease-Events für die Pfeil-hoch bzw. -runter Tasten verarbeitet werden

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void* thread_proc(void* p_arg)

{
    XEvent evt;
    XSelectInput(p_display, window, StructureNotifyMask | KeyPressMask | KeyReleaseMask);  // KeyReleaseMask hinzugefügt

    bool quit = false;

    do
    {
        XNextEvent(p_display, &evt);
        switch(evt.type)
        {
        case DestroyNotify:
            quit = true;
            break;
        case KeyPress:
            if(evt.xkey.keycode == XKeysymToKeycode(p_display, XK_KP_Subtract) && delay < 100) delay += 5;
            else if(evt.xkey.keycode == XKeysymToKeycode(p_display, XK_KP_Add) && delay) delay -= 5;
            else if (evt.xkey.keycode == XKeysymToKeycode(p_display, XK_Up)) --move; // hinzugefügt

            else if (evt.xkey.keycode == XKeysymToKeycode(p_display, XK_Down)) ++move; // hinzugefügt

            break;
        case KeyRelease: // hinzugefügt

            if (evt.xkey.keycode == XKeysymToKeycode(p_display, XK_Up)) ++move; // hinzugefügt

            else if (evt.xkey.keycode == XKeysymToKeycode(p_display, XK_Down)) --move; // hinzugefügt

            break; // hinzugefügt

        case ClientMessage:
            if(evt.xclient.message_type == XInternAtom(p_display, "WM_PROTOCOLS", 0) && evt.xclient.data.l[0] == XInternAtom(p_display, "WM_DELETE_WINDOW", 0))
            {   // BadWindowError Patch

                XUnmapWindow(p_display, window);// BadWindowError Patch

                quit = true;
            }   // BadWindowError Patch

            break;
        }
    }
    while(!quit);

    //XUnmapWindow(p_display, window);  // BadWindowError Patch

    window_open = false;
}


Zu guter Letzt fehlt nur noch die "KI":

C-/C++-Quelltext

1
2
3
4
5
6
// Steuerung durch den User

int human_pong(const GameState& gs,
               uint me)
{
    return move;
}

Ich muss dich aber vorwarnen: die Steuerung über die Beschleunigung ist recht schwierig und schon gegen die Referenz eine Herausforderung. Wenn deine MaxYSpeedKI so spielt, wie es ihr Name andeutet, wirst du gegen die kaum einen Treffer landen können. Trotzdem viel Spaß ;)

Zitat von »"knivil"«

Meine KI (oder das KI-Objekt) muss aber ueber die my_pong-Funktion hinaus erhalten bleiben, z.B. als globale Variable. Sonst vergisst sie staendig von update zu update, was sie eigentlich machen wollte.

Sollte kein Problem sein, schließlich hat David statische Variablen in diesem Contest erlaubt.

Möge die künstlichere Intelligenz gewinnen ! ;)

97

26.08.2008, 13:58

Statische Variablen super :-). Das mit dem HumanPlayer hatte ich auch in etwa so, nur habe ich die Variable direkt auf -1 bzw 1 gesetzt und in der KI-funktion my_pong wieder auf 0 (siehe unten). Leider war die Steuerung trotzdem sehr behaebig und irgendwie ganz und garnicht das Gelbe vom Ei. Da ich mich zu erinnern wage, jeder Wert ungleich -1 oder 1 wird wie 0 behandelt, habe den Code aber gerade nicht hier.

C-/C++-Quelltext

1
2
3
4
5
6
int human_pong(const GameState& gs, uint me)
{
    int tmp = move;
    move = 0;
    return tmp;
}

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

98

26.08.2008, 14:06

Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

99

26.08.2008, 14:09

Gibt es unter Linux kein Äquivalent zu GetAsyncKeyState()?
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

100

26.08.2008, 14:16

Das kommt drauf an, welche Bibliothek fuer dich Ein-/Ausgabe machen soll. Aber hier wurde X11-low-level benutzt, damit kenne ich mich nicht so aus. SDL waere kein Problem :-). Aber es ist schoen auch mal X11 in nativer Form zu sehen.

Werbeanzeige