Zum Inhalt springen

MidWar [Midgard Kampfsimulator]


Mav3N

Empfohlene Beiträge

 

Klasse Programm :D

 

Im Normalen Kampf fände ich es übersichtlicher, wenn die Teams unterschiedliche Farben hätten.

 

Du meinst in der grauen Box "Kampfinformationen" sollen die Kämpfer eines Teams farbig markiert werden? Also Team X blau und Team Y rot?

 

Bamba

 

Bei einer grossen Zahl von Teams kann das schnell unübersichtlich werden. Eventuell wäre es besser wenn du jedem Team einen eigenen Kasten spendierst, wobei das natürlich auch wieder unübersichtlich werden kann. Deshalb mag es sein, dass deshalb die einfachste und vergleichsweise übersichtlichste Lösung wäre eine Auswahl anzubieten ob man die Darstellung der Kampfinformation nach Kämpfer ID, Teamzugehörigkeit, Name der Kämpfers etc (verwendete Waffe, Rüstungstyp und was weiss ich nicht was alles) sortieren kann. Dann kann jeder aussuchen wie er es am liebsten hat.

es grüsst

Sayah el Atir al Azif ibn Mullah

Link zu diesem Kommentar
Bei Rüstungen hätte ich noch gerne die Auswahl: Rindenhaut, Marmorhaut und Eisenhaut. Das ist durch die gesparten AP nicht uninteressant.

 

Viele Grüße

hj

 

Ich habe hier keine Midgard Bücher in Reichweite, bitte einmal aufzählen was diese bringen.

 

Rindenhaut: Schützt wie KR 3 LP und wenn abgewehrt, auch 3 AP.

Marmorhaut: wie Rindenhaut nur mit Faktor 4

Eisenhaut: wie Rindenhaut nur mit Faktor 5

 

Modifikationen wie Abzug auf Bewegungsweite, Gewandtheit und Verlust von Angriffs- und Abwehrbonus habe ich jetzt erstmal weggelassen. Das hast Du bei den normalen Rüstungen ja auch noch nicht mit drin. Wenn Du sie mit einbauen willst, sag Bescheid, dann suche ich Dir die Abzüge raus.

 

Neue Funktionen kommen erst wieder in der nächsten Version. Auf meiner Todo Liste steht jetzt:

...

- Man darf nicht mehr als die Hälfte der AP haben, wenn man weniger als die Hälfte aller LP hat

...

 

Bitte beachte, dass bereits bei Hälfte LP auch nur max. die Hälfte AP gilt, nicht erst bei weniger als die Hälfte LP.

 

Gruß

Shadow

Bearbeitet von Shadow
Link zu diesem Kommentar

Neue Funktionen kommen erst wieder in der nächsten Version. Auf meiner Todo Liste steht jetzt:

...

- Man darf nicht mehr als die Hälfte der AP haben, wenn man weniger als die Hälfte aller LP hat

...

 

Bitte beachte, dass bereits bei Hälfte LP auch nur max. die Hälfte AP gilt, nicht erst bei weniger als die Hälfte LP.

 

Gruß

Shadow

Da hat er sich nur verschrieben. Das hatte ich in #52 schon angemerkt und er hatte in #54 das umsetzen wollen. :)
Link zu diesem Kommentar

Hi,

 

ich hab jetzt ein bisschen länger gebraucht, da das ganze nun arg an die Grenze meines Könnens geht. :D

 

Version 1.4 hat zwei neue Funktionen: Man kann einmal eingegebene Kämpfer mit einem Mausklick auf andere Kämpfer übertragen, außerdem gibt es den so genannten Rundenkampf, in dem jede Runde einzeln berechnet wird und man am Ende jeder Runde die Werte ändern kann. Weiter Updates in Kürze.

 

ACHTUNG: Der Link hat sich geändert: http://php-learner.piranho.de/MidWar/home.htm

 

Ich hab mal alle verschiedenen Versionen hochgeladen.

 

Features von V1.4:

 

- Angreifen

- Abwehren

- Abwehren nicht erlaubt wenn Verteidiger 0 AP hat

- Schadenkalkulation

- Kampfunfähig ab 3 LP

- Rüstung

- Nicht unter 0 AP erlaubt

- Minus 2 auf Angriffe bei wenn Angreifer LP/2 hat

- Minus 4 auf Angriffe bei wenn Angreifer 0 AP hat

- Plus 4 auf Angriff, wenn Verteidiger 0 AP hat

- Anzeige wer gestorben / Kampfunfähig ist

- Namensgebung möglich

- Zufällige Gegnerwahl

- Kampfinformationen ausschaltbar

- Rundenanzeige

- Statistikkampf

- Inputüberprüfung

- Standardbelegungen für Kämpfer

- Rundenkampf

 

Bitte fleißig Fehler suchen!

 

Bamba

Link zu diesem Kommentar

Ich weiss nicht ob es ein Fehler ist:

Ich habe einen Kampf genau angesehen und festgestellt, dass die Anzeige, dass eine Figur 0 AP hat erst auftaucht als sie selbst angreifen darf (zwischen Angriff die sie auf 0 AP bringt und eigenen Angriff wurde sie nicht mehr angegriffen). Sprich wann machst du die Statusabfrage wieviele AP eine Figur noch hat? Ich bin verwirrt, weil die Abfrage ob eine Figur noch am Kampf teilnehmen kann machst du direkt nach dem Angriff, was natürlich auch Sinn macht.

Das andere ist ein Fehler, denke ich: ein kritischer Treffer, gewürfelt 20, wird nur abgewehrt wenn man selbst auch eine 20 würfelt (oder war das eine unserer Hausregeln...?)

das dritte, wenn eine Figur sowohl weniger als LP/2 wie auch 0 AP hat sollte sie einen Malus von -4 bekommen (der grössere Malus zählt). In der Kampfübersicht werden beide erwähnt. Solange sie nicht addiert werden ist alles in Ordnung, denke ich. Ebenfalls in diese Kategorie gehört: zwei Wehrlose greifen sich an, ergibt Bonus +4 weil Gegner wehrlos und Malus -4 weil man selbst wehrlos ist. Ich glaube hier wird addiert (wie im Programm), bin aber nicht sicher.

es grüsst

Sayah el Atir al Azif ibn Mullah

Link zu diesem Kommentar
Ich weiss nicht ob es ein Fehler ist:

Ich habe einen Kampf genau angesehen und festgestellt, dass die Anzeige, dass eine Figur 0 AP hat erst auftaucht als sie selbst angreifen darf (zwischen Angriff die sie auf 0 AP bringt und eigenen Angriff wurde sie nicht mehr angegriffen). Sprich wann machst du die Statusabfrage wieviele AP eine Figur noch hat? Ich bin verwirrt, weil die Abfrage ob eine Figur noch am Kampf teilnehmen kann machst du direkt nach dem Angriff, was natürlich auch Sinn macht.

 

Das ist definitiv KEIN Fehler. Es läuft folgendermaßen ab: Kämpfer a greift Kämpfer x an und bringt die AP von Kämpfer x auf 0, wodurch er wehrlos ist und alle, die Kämpfer X angreifen nun +4 auf den EW:Angriff erhalten. Der Interne Wert im Programm für die AP von Kämpfer X ist nun 0. Jetzt greift Kämpfer B Kämpfer X an. Hierbei erhält er schon +4. Dann wird es auch angezeigt, da es jetzt ja relevant ist, greift keiner Kämpfer X an, steht da auch nicht "...erzählt +4 beim Angriff auf X...", weil es nicht relevant ist. => Kein Fehler!

 

Das andere ist ein Fehler, denke ich: ein kritischer Treffer, gewürfelt 20, wird nur abgewehrt wenn man selbst auch eine 20 würfelt (oder war das eine unserer Hausregeln...?)

 

Hmm, ich hab hier keine Regelbücher, kann mal jemand nachgucken und mir sagen, ob man ne gewürfelte 20 auch nur mit ner gewürfelten 20 abwehren kann? Wenn das so ist, ist das ein Fehler, stimmt. Kann ich aber erst hinzufügen, wenn kritische Erfolge eingeführt werden.

 

das dritte, wenn eine Figur sowohl weniger als LP/2 wie auch 0 AP hat sollte sie einen Malus von -4 bekommen (der grössere Malus zählt). In der Kampfübersicht werden beide erwähnt. Solange sie nicht addiert werden ist alles in Ordnung, denke ich. Ebenfalls in diese Kategorie gehört: zwei Wehrlose greifen sich an, ergibt Bonus +4 weil Gegner wehrlos und Malus -4 weil man selbst wehrlos ist. Ich glaube hier wird addiert (wie im Programm), bin aber nicht sicher.

es grüsst

Sayah el Atir al Azif ibn Mullah

 

Es wird in beiden Fällen addiert, wurde meines Wissens nach doch im Schwampf geklärt? Wenn beides addiert wird, ist das ebenfalls kein Fehler! Falls ich falsch liegen sollte, klärt mich bitte auf.

 

Trotzdem Danke fürs suchen.

 

Bamba

Link zu diesem Kommentar

Das andere ist ein Fehler, denke ich: ein kritischer Treffer, gewürfelt 20, wird nur abgewehrt wenn man selbst auch eine 20 würfelt (oder war das eine unserer Hausregeln...?)

 

Hmm, ich hab hier keine Regelbücher, kann mal jemand nachgucken und mir sagen, ob man ne gewürfelte 20 auch nur mit ner gewürfelten 20 abwehren kann? Wenn das so ist, ist das ein Fehler, stimmt. Kann ich aber erst hinzufügen, wenn kritische Erfolge eingeführt werden.

Ja, ein kritischer Erfolg kann immer nur mit einem kritischen Erfolg beim Widerstandswurf gekontert werden (DFR S. 80) -> Fehler.

 

das dritte, wenn eine Figur sowohl weniger als LP/2 wie auch 0 AP hat sollte sie einen Malus von -4 bekommen (der grössere Malus zählt). In der Kampfübersicht werden beide erwähnt. Solange sie nicht addiert werden ist alles in Ordnung, denke ich. Ebenfalls in diese Kategorie gehört: zwei Wehrlose greifen sich an, ergibt Bonus +4 weil Gegner wehrlos und Malus -4 weil man selbst wehrlos ist. Ich glaube hier wird addiert (wie im Programm), bin aber nicht sicher.

es grüsst

Sayah el Atir al Azif ibn Mullah

 

Es wird in beiden Fällen addiert, wurde meines Wissens nach doch im Schwampf geklärt? Wenn beides addiert wird, ist das ebenfalls kein Fehler! Falls ich falsch liegen sollte, klärt mich bitte auf.

Die Mali addieren sich (DFR S. 225) -> kein Fehler.

 

Gruß

Pandike

Link zu diesem Kommentar
  • 2 Wochen später...

Nachtrag kritische Ereignisse (ich denke du hast das schon auf der Liste)

gewürfelt 20 ist immer ein Erfolg, gewürfelt 1 immer ein Misserfolg.

In einem Beispiel in dem Kämpfer 1 mit EW 0 und 500 LP nur bei kritischen Treffer erfolgreich sein kann (dann aber tödlich ist) gegen Kämpfer 2 der immer trifft (EW 19) aber nur 1 Schadenspunkt anrichtet entscheiden die AP von Kämpfer 1 ob er gewinnt (1000 AP) oder verliert (1 AP). Das dürfte nicht sein, da Kämpfer 1 genügend kritische Treffer landen sollte, dass er den Kampf immer gewinnt. Wenn Kämpfer 2 keinen Schaden anrichten kann, lässt sich der Kampf nicht mehr berechnen wenn Kämpfer 1 keine AP hat. Auch da müsste Kämpfer 1 per kritischem Erfolg den Kampf innert nützlicher Frist immer gewinnen.

es grüsst

Sayah el Atir al Azif ibn Mullah

Link zu diesem Kommentar

Hmmm. Dann hab ich vielleicht wieder einmal die Regeln falsch im Kopf. Ich dachte gewürfelte 20 sei kritischer Erfolg, egal was auch immer. Hat jemand ein Regelwerk zu Hand und kann schnell :read: ? Wie ist es umgekehrt? gewürfelt 1 bei EW +19 müsste trotz der erreichten 20 ein kritischer Fehler sein, richtig?

es grüsst

Sayah el Atir al Azif ibn Mullah

Link zu diesem Kommentar
Du meinst vermutlich folgenden Sachverhalt: Sind die Abzüge höher als der Erfolgswert, glückt der EW:Angriff bei einer gewürfelten 20 dennoch, richtet aber nur kritischen Schaden an, wenn der WW:Abwehr misslingt, ansonsten normalen schweren Schaden (DFR S. 242).

 

Gruß

Pandike

 

Das kann sein :lol: (ist jedoch leider nicht auf einen EW von +0 anwendbar)

Danke Pandike :thumbs:

Link zu diesem Kommentar
Du meinst vermutlich folgenden Sachverhalt: Sind die Abzüge höher als der Erfolgswert, glückt der EW:Angriff bei einer gewürfelten 20 dennoch, richtet aber nur kritischen Schaden an, wenn der WW:Abwehr misslingt, ansonsten normalen schweren Schaden (DFR S. 242).

 

Gruß

Pandike

Ah so, danke. Wieder etwas gelernt.

es grüsst

Sayah el Atir al Azif ibn Mullah

Link zu diesem Kommentar
  • 2 Monate später...

Hallo,

 

ich hatte die letzten Wochen mit meinem Umzug nach Köln zutun und bin nicht zuviel gekommen. Da das ganze jetzt aber abgeschlossen ist, hatte ich Zeit mich die letzten Tage mal ausführlich mit dem A*-Algorithmus auseinander zusetzen.

 

Ich habe es jetzt geschafft den A*-Algorithmus in PHP zu implementieren, was bedeutet, dass die automatisierte Wegfindung (Welche Optimal ist (Existiert ein Weg, wird er gefunden) - das ist mathematisch bewiesen) bereits funktioniert. Wenn ich mein astar.php also nun mit dem bisherigen Kampfsimulator zusammenschmeiße, kämpfen die Figuren nach den bisher umgesetzten Regeln und bewegen sich gleichzeitig realistisch auf einem Schachbrett.

 

Hört sich erstmal gut an, oder?

 

Bevor ich das zusammenfüge, werde ich aber meine astar.php erstmal ausführlich auf Fehler aller Art testen - schließlich bin ich nur Hobbyprogrammierer und bei mir kommt es öfter mal vor, dass sich ein Fehler einschleicht. Ich poste den PHP Quellcode hier einfach mal, da es hier einige gibt, die sich damit auskennen (Solwac war das glaube ich) und vllt. mit nach Fehlern suchen können. Erst wenn wir uns alle sicher sind, dass meine astar.php Fehlerfrei ist, füge ich sie mit dem bisherigen Kampfsimulator zusammen.

 

Bamba

 

Quellcode von astar.php:

(Bitte bedenkt, dass das ganze noch nicht ausgereift ist, ich werde noch 'ne Menge ändern. Professionelle Programmierer würden von einer Beta-Version sprechen) :D

 

<?php

error_reporting(E_ALL);

class astar {
 private $x;
 private $y;
 private $openlist = array();
 private $closedlist = array();
 private $tx;
 private $ty;

 public function __construct($x,$y) {
   // Zu übergebende Werte: $x = Anzahl Felder auf der X-Achse,
   // $y = Anzahl Felder auf der Y-Achse, Hindernisse
   // WICHTIG: IRGENDWIE NOCH DIE HINDERNISSE IN DIE CONSTRUCT FUNC EINBAUEN
   $this->x = $x;
   $this->y = $y;      
   // Hier Hindernisse manuell einfügen, solange das noch nicht über die Construct Funktion geregelt wird
   array_push($this->closedlist,array("X" => 1, "Y" => 2));
   array_push($this->closedlist,array("X" => 1, "Y" => 3));
   array_push($this->closedlist,array("X" => 2, "Y" => 2));
   array_push($this->closedlist,array("X" => 3, "Y" => 2));
 }
 public function main($x,$y,$tx,$ty) {
   // Berechnet den Weg vom Start zum Zielnode
   // X = X-Koordinate, Y = Y-Koordinate
   // G = Bisherige Wegkosten
   // C = Kosten Vorgängernode -> currentNode
   // H = Geschätzte Restkosten (Luftlinien Heuristik)
   // F = Gesamtkosten

   // Vorbelegungen
   $Start = array();
   $Start["X"] = $x; $Start["Y"] = $y; $Start["G"] = 0; $Start["VX"] = -1;  $Start["VY"] = -1;
   $this->tx = $tx; $this->ty = $ty;

   // Ganz zu Anfang des Skriptes den Startnode in die Openlist einfügen
   array_push($this->openlist,$Start);

   do {
     // Die Openlist nach dem niedrigstem F-Wert sortieren
     usort($this->openlist,'Compare');

     // Wenn der Aktuelle Node gleich dem Zielnode ist -> Weg gefunden
     $ActualNode = array("X" => $this->openlist[0]["X"],"Y" => $this->openlist[0]["Y"],"VX" => $this->openlist[0]["VX"],"VY" => $this->openlist[0]["VY"]);
     if($ActualNode["X"] == $this->tx && $ActualNode["Y"] == $this->ty) {
       array_push($this->closedlist,$ActualNode);
       $this->getWay();
       die("PATHFOUND");
     }
     else {
       // Wenn nicht, wird vom Punkt mit dem niedrigstem F-Wert weitergesucht
       $this->expandNode($ActualNode["X"],$ActualNode["Y"]);
       // Den fertig untersuchen Node auf die Closedlist setzen und aus der Openlist löschen
       array_push($this->closedlist,$ActualNode);
       unset($this->openlist[0]);
     }
   }
   // Bis die Openlist leer ist
   while(!empty($this->openlist));
   // Ist die Openlist leer und es wurde nicht abgebrochen, existiert kein Weg
   die("ES GIBT KEINEN WEG");
 }
 private function expandNode($x,$y) {
   // Expandiert den Node
   $i=0;
   $Successor = array();
   $Successors = $this->getSuccessors($x,$y);

   foreach($Successors as $Index => $Current) {
     // Geht jeden Nachfolgenode einzeln durch 
     array_push($Successor,$Current);

     if($i%2 != 0) {
       // Tritt nur jedes zweite mal in Kraft da immer erst BEIDE 
       // Werte (X und Y Koordinate) $Successor hinzugefügt werden müssen
       // Überprüft, ob $Successor in der Closedlist ist
       $Inside = $this->inClosedList($Successor);
       if($Inside == TRUE) {
         // Wenn $Successor innerhalb der Closedlist ist, mache nichts  außer $Successor zu leeren
         $Successor = array();
         $i++;
         continue;
       }
       else {
         // F Wert von $Successor berechnen
         $g = 0;
         foreach($this->openlist as $Key) {
           // Holt den G Wert vom aktuellen Node
           if($x == $Key["X"] && $y == $Key["Y"]) {
             $g = $Key["G"];
             break;
           }
         }
         switch($Index) {
           // Berechnet den C Wert zwischen aktuellem Node und Successor
           case "ol_y": 
             $c = sqrt(2);
             break;
           case "om_y": 
             $c = 1;
             break;
           case "or_y": 
             $c = sqrt(2);
             break;
           case "ml_y": 
             $c = 1;
             break;
           case "mr_y": 
             $c = 1;
             break;
           case "ul_y": 
             $c = sqrt(2);
             break;
           case "um_y": 
             $c = 1;
             break;
           case "ur_y": 
             $c = sqrt(2);
             break;
         }
         // Berechnet H Wert des Successors
         $XDifference = $Successor[0] - $this->tx;
         if($XDifference < 0) {
           $XDifference *= -1;
         }
         $YDifference = $Successor[1] - $this->ty;
         if($YDifference < 0) {
           $YDifference *= -1;
         }
         $h = sqrt($XDifference * $XDifference + $YDifference * $YDifference);
         // G, C und H Wert werden zum F Wert addiert
         $f = $g + $c + $h;

         $Exit = FALSE;
         for($n=0;$n<count($this->openlist);$n++) {
           if($Successor[0] == $this->openlist[$n]["X"] && $Successor[1] == $this->openlist[$n]["Y"]) {
             if($f > $this->openlist[$n]["F"]) {
               // Wenn Successor in der Openlist ist und der neue F Wert größer als 
               // der alte F Wert ist, tue nichts
               $Exit = TRUE;  
             }
             else {
               // Wenn Successor in der Openlist ist und der neue F Wert nicht größer als der
               // alte ist, den F Wert in der Openlist aktualisieren
               $this->openlist[$n]["F"] = $f;
               $Exit = TRUE;
             }
             break;
           }
         }
         if($Exit) {
           // Wenn der Successor bereits in der Openlist war und der F Wert falls nötig
           // aktualisiert wurde, $Successor leeren, $i inkrementieren und den Rest
           // des Schleifendurclaufes überspringen
           $Successor = array();
           $i++;
           continue;                                                      
         }
         // War der Successor garnicht in der Openlist, füge ihn hinzu
         $NewNode = array("X" => $Successor[0],"Y" => $Successor[1],"F" => $f,"G" => ($g + $c),"VX" => $x,"VY" => $y);
         array_push($this->openlist,$NewNode);
       }

       // $Successor leeren, damit sich keine Werte überschneiden
       $Successor = array();
     }
     $i++;
   }
 }  
 private function getSuccessors($x,$y) {
   // Bestimmt alle Umgebungsnodes von $x,$y

   $Successors = array();
   if(($x - 1 >= 0) && ($y + 1 <= $this->y)) {
     $Successors["ol_x"] = $x - 1; $Successors["ol_y"] = $y + 1;
   }
   if($y + 1 <= $this->y) {
     $Successors["om_x"] = $x; $Successors["om_y"] = $y + 1;
   }
   if(($x + 1 <= $this->x) && ($y + 1 <= $this->y)) {
     $Successors["or_x"] = $x + 1; $Successors["or_y"] = $y + 1;
   }
   if($x - 1 >= 0) {
     $Successors["ml_x"] = $x - 1; $Successors["ml_y"] = $y;
   }
   if($x + 1 <= $this->x) {
     $Successors["mr_x"] = $x + 1; $Successors["mr_y"] = $y;
   }
   if(($x - 1 >= 0) && ($y - 1 >= 0)) {
     $Successors["ul_x"] = $x - 1; $Successors["ul_y"] = $y - 1;
   }
   if($y - 1 >= 0) {
     $Successors["um_x"] = $x; $Successors["um_y"] = $y - 1;
   }
   if(($x + 1 <= $this->x) && ($y - 1 >= 0)) {
     $Successors["ur_x"] = $x + 1; $Successors["ur_y"] = $y - 1;
   }

   return $Successors;
 }
 private function inClosedlist($Successor) {
   // Überprüft, ob $Successor in der Closedlist vertreten ist
   $Inside = FALSE;
   for($j=0;$j<count($this->closedlist);$j++) {
     if($Successor[0] == $this->closedlist[$j]["X"] && $Successor[1] == $this->closedlist[$j]["Y"]) {
       $Inside = TRUE;
     }
   }
   return $Inside;
 }
 private function getWay() {
   // Berechnet aus $Closedlist den wirklichen Weg
   $Way = array();
   array_push($Way,end($this->closedlist));
   $Last = end($Way);
   do {
     foreach($this->closedlist as $Key) {
       if($Key["X"] == $Last["VX"] && $Key["Y"] == $Last["VY"]) {
         array_push($Way,$Key);
         break;
       }
     }
     $Last = end($Way);
   }
   while($Last["VX"] != -1 && $Last["VY"] != -1);
   $Way = array_reverse($Way);
   for($i=0;$i<count($Way);$i++) {
     echo "Feld $i: " . $Way[$i]["X"] . "," . $Way[$i]["Y"] . "<br>";
   }
   return $Way;
 }
}        

function Compare($first, $second) { 
       if($first['F'] < $second['F']) 
               return -1; 
       else if($first['F'] > $second['F']) 
               return 1; 
       else 
               return 0; 
}  
$map = new astar(4,9);
$map->main(1,0,2,3)

?>

  • Like 1
Link zu diesem Kommentar

Bevor ich das zusammenfüge, werde ich aber meine astar.php erstmal ausführlich auf Fehler aller Art testen - schließlich bin ich nur Hobbyprogrammierer und bei mir kommt es öfter mal vor, dass sich ein Fehler einschleicht. Ich poste den PHP Quellcode hier einfach mal, da es hier einige gibt, die sich damit auskennen (Solwac war das glaube ich) und vllt. mit nach Fehlern suchen können. Erst wenn wir uns alle sicher sind, dass meine astar.php Fehlerfrei ist, füge ich sie mit dem bisherigen Kampfsimulator zusammen.

Von mir erst mal ein paar kurze Anmerkungen... (Ist das die Portierung einer C-Version des Algorithmus? ;))

 

Die Methode inClosedList() durchsucht manuell das Array. Einer der wenigen Gründe, in PHP zu programmieren, ist der Wust von Array-Such- und Manipulationsfunktionen. Nimm lieber die, die sollten auch deutlich besser performen, wenn man nicht gerade einen Bytecodecompiler installiert hat. :D

 

Natürlich muss dann die Datenstruktur ein wenig angepasst werden. :schweiss:

Dazu passend der Konstruktor... besser wäre eine eigene Klasse, die das Spielfeld behandelt, dann kann man da auch über setter drauf zugreifen und muss dieses Gefummel mit array_push nicht weiter verfolgen.

 

Ausserdem kann man dann auch gleich durch Anpassung der Spielfeldklasse das Problem mit den Kontrollbereichen erschlagen...

:rueckzug:

 

Nein, ernsthaft: Strikt OOP-technisch kommst Du mit einer einzelnen Klasse wohl nicht aus.

Link zu diesem Kommentar

Bevor ich das zusammenfüge, werde ich aber meine astar.php erstmal ausführlich auf Fehler aller Art testen - schließlich bin ich nur Hobbyprogrammierer und bei mir kommt es öfter mal vor, dass sich ein Fehler einschleicht. Ich poste den PHP Quellcode hier einfach mal, da es hier einige gibt, die sich damit auskennen (Solwac war das glaube ich) und vllt. mit nach Fehlern suchen können. Erst wenn wir uns alle sicher sind, dass meine astar.php Fehlerfrei ist, füge ich sie mit dem bisherigen Kampfsimulator zusammen.

Von mir erst mal ein paar kurze Anmerkungen... (Ist das die Portierung einer C-Version des Algorithmus? ;))

 

Die Methode inClosedList() durchsucht manuell das Array. Einer der wenigen Gründe, in PHP zu programmieren, ist der Wust von Array-Such- und Manipulationsfunktionen. Nimm lieber die, die sollten auch deutlich besser performen, wenn man nicht gerade einen Bytecodecompiler installiert hat. :D

 

Natürlich muss dann die Datenstruktur ein wenig angepasst werden. :schweiss:

Dazu passend der Konstruktor... besser wäre eine eigene Klasse, die das Spielfeld behandelt, dann kann man da auch über setter drauf zugreifen und muss dieses Gefummel mit array_push nicht weiter verfolgen.

 

Ausserdem kann man dann auch gleich durch Anpassung der Spielfeldklasse das Problem mit den Kontrollbereichen erschlagen...

:rueckzug:

 

Nein, ernsthaft: Strikt OOP-technisch kommst Du mit einer einzelnen Klasse wohl nicht aus.

 

Hi,

 

NEIN das ist keine Portierung einer C-Version, ich habe mir http://de.wikipedia.org/wiki/A*-Algorithmus genommen und das ganze in 2 Tagen frei runter programmiert. Funktioniert soweit ich das sehe relativ gut, ich will bloß sicher sein, dass es eine 100% Implementierung ist (An der Funktionstüchtigkeit nicht an der Geschwindigkeit gemessen).

 

Vielen Dank für deine Anregungen, ich werde mal schauen was ich da noch drehen kann... :D Aber ich bin halt ein Hobbyprogrammierer und sonst nichts. :P

Link zu diesem Kommentar

So, ich habe mich mal durch das PHP durchgekämpft. :schweiss:

 

Ich empfinde es nicht als gut lesbar. Es wäre wirklich sinnvoll, weitere Klassen zu verwenden und einige Funktionen zu kapseln. Als Kandidaten sehe ich Punkte (x,y), Graphen (um die möglichen Wege mit Backtracking abzuschreiten) und das Spielfeld (dabei können dann Hindernisse, Kontrollbereiche usw. erschlagen werden).

 

Die eigentliche Implementation scheint mir aber korrekt zu sein. Zumindest ist die Heuristic-Funktion brauchbar und erfüllt alle Bedingungen. h ist monoton und somit sollte immer ein Optimum gefunden werden.

 

Warum verwendest Du A*? Ich habe nicht die Erfahrung mit umfangreichen Rechenaufgaben in PHP, aber ich stelle mir den Speicheraufwand bei größeren Feldern als nicht zu unterschätzenden Nachteil vor. Außerdem findet der Algorithmus nur einen kürzesten Weg. Für eine Kampfsimulation könnte es sinnvoller sein, wenn alle möglichsten kürzesten Wege ermittelt werden um dann für mehrere Figuren das Optimum zu finden. Bellman-Ford wäre dann eine Alternative.

 

Sollte die Laufzeit irgendwann beim Einsatz zu sehr anwachsen, dann wäre D* vielleicht besser. Das habe ich aber noch nie programmiert. :lookaround:

 

Solwac

Link zu diesem Kommentar
So, ich habe mich mal durch das PHP durchgekämpft. :schweiss:

 

Ich empfinde es nicht als gut lesbar. Es wäre wirklich sinnvoll, weitere Klassen zu verwenden und einige Funktionen zu kapseln. Als Kandidaten sehe ich Punkte (x,y), Graphen (um die möglichen Wege mit Backtracking abzuschreiten) und das Spielfeld (dabei können dann Hindernisse, Kontrollbereiche usw. erschlagen werden).

 

Ich mal gerade den anderen Quellcode des Kampfsimulators angeguckt und mir überlegt wie man das ganze aufteilen könnte. Das heißt ich werde das ganze jetzt in kleinere Klassen aufteilen und besser verteilen.

 

Die eigentliche Implementation scheint mir aber korrekt zu sein. Zumindest ist die Heuristic-Funktion brauchbar und erfüllt alle Bedingungen. h ist monoton und somit sollte immer ein Optimum gefunden werden.

 

Dachte ich auch, aber starte mal mein Skript mit:

 

$map = new astar(4,9);
$map->main(4,0,0,2)

 

und den Hindernissen:

 

array_push($this->closedlist,array("X" => 1, "Y" => 2));
   array_push($this->closedlist,array("X" => 1, "Y" => 3));
   array_push($this->closedlist,array("X" => 2, "Y" => 2));
   array_push($this->closedlist,array("X" => 3, "Y" => 2));
   array_push($this->closedlist,array("X" => 2, "Y" => 0));
   array_push($this->closedlist,array("X" => 2, "Y" => 1));

 

Normalerweise sollte er um diese Mauer rumgehen, allerdings läuft er direkt am Anfang einmal Zickzack, nämlich:

 

Feld 0: 4,0

Feld 1: 3,1

Feld 2: 4,2

Feld 3: 3,3

Feld 4: 2,3

Feld 5: 1,4

Feld 6: 0,3

Feld 7: 0,2

 

(Debug Output von meinem astar.php). Schau dir die ersten 3 Felder an. Wäre er optimal müsste es doch 4,0 - 4,1 - 4,2 heißen und nicht 3,1. Kann mir das jemand erklären? :worried:

 

Warum verwendest Du A*? Ich habe nicht die Erfahrung mit umfangreichen Rechenaufgaben in PHP, aber ich stelle mir den Speicheraufwand bei größeren Feldern als nicht zu unterschätzenden Nachteil vor. Außerdem findet der Algorithmus nur einen kürzesten Weg. Für eine Kampfsimulation könnte es sinnvoller sein, wenn alle möglichsten kürzesten Wege ermittelt werden um dann für mehrere Figuren das Optimum zu finden. Bellman-Ford wäre dann eine Alternative.

 

Ich verwende A*, weil es ganz einfach derjenige war, den ich kannte. Eine zeitlang hab ich sogar einen eigenen Algorithmus hierfür entwickelt das ganze dann aber wieder verworfen. Ich denke das ist der bekannteste Algorithmus für soetwas und dann war es halt Zufall, dass ich ihn benutzt habe. Speicheraufwand? Hm, ja, das wird ein Problem aber ich glaube kaum, dass wir in Feldern mit 10.000 x 20.000 kämpfen werden. Also dürfte das noch machbar sein, wenn ich mir zum Debug die Openlist ausgeben lasse, ist sie bei 4 x 9 auch nicht so arg groß und bei 20x100, ist es auch noch überschaubar.

 

Er findet nur einen kürzesten Weg? Na das macht doch nichts. Wie oben erwähnt werde ich das ganze in mehrere Klassen aufteilen die oberste Klasse wird dann die feindliche Kämpferliste durchgehen und für jeden den Weg berechnen von aktuelle Spielerfigur -> Feind, so dass ich eine Liste mit möglichen Wegen erhalten, deren kürzesten ich einfach nehme. So dürfte ja jeder Kämpfer in Echt in einer Schlacht auch denken. Problem gelöst. :P

 

Sollte die Laufzeit irgendwann beim Einsatz zu sehr anwachsen, dann wäre D* vielleicht besser. Das habe ich aber noch nie programmiert. :lookaround:

 

Solwac

 

D* ist nicht optimal und wenn ich eines hasse, dann unzählige Exeptions festzulegen. Daher werde ich nicht auf D* ausweichen. Er ist nur suboptimal. Will heißen ich bleibe bei meinem derzeitigen Astar, werde das ganze noch in mehrere Klassen zwecks Übersichtlichkeit und Handling aufteilen und dann mit meinem bisherigen Simulator verschmelzen.

 

Die Methode inClosedList() durchsucht manuell das Array. Einer der wenigen Gründe, in PHP zu programmieren, ist der Wust von Array-Such- und Manipulationsfunktionen. Nimm lieber die, die sollten auch deutlich besser performen, wenn man nicht gerade einen Bytecodecompiler installiert hat. :D

 

Natürlich muss dann die Datenstruktur ein wenig angepasst werden. :schweiss:

 

Nun, ich habe mir diesen Aufbau der Openlist und der Closedlist aus mehreren Gründen so überlegt. Und ich habe eigentlich keine Lust das ganze Script umzubasteln, nur um dann eine kleine derartige Funktion inClosedlist() einzusparen und eine PHP-Standardfunktion verwenden zu können. Daher belasse ich es dabei. Es hätte bessere Wege gegeben aber was solls. Ich bin schließlich kein Profi.

 

Dazu passend der Konstruktor... besser wäre eine eigene Klasse, die das Spielfeld behandelt, dann kann man da auch über setter drauf zugreifen und muss dieses Gefummel mit array_push nicht weiter verfolgen.

 

Ausserdem kann man dann auch gleich durch Anpassung der Spielfeldklasse das Problem mit den Kontrollbereichen erschlagen...

 

Wie oben erwähnt: Ich teile das ganze in mehrere Klassen auf und dann hat sich die Sache.

 

Ich mache dann jetzt sofort weiter, nur kann mir bitte einer erklären was mit der Situation da oben ist, die nur suboptimal rechnet und warum und wie man das behebt? Kann ja sein, dass ich mich da gerade irre, aber ich glaube irgendwo müsste mir ein Fehler unterlaufen sein, sonst dürfte er einen derartigen Zickzackkurs nicht ausrechnen. Solwac schau doch noch mal. :D

 

Bamba, der vorhat sämtliche M4 Regeln umzusetzen :uhoh:

Link zu diesem Kommentar
(Debug Output von meinem astar.php). Schau dir die ersten 3 Felder an. Wäre er optimal müsste es doch 4,0 - 4,1 - 4,2 heißen und nicht 3,1. Kann mir das jemand erklären? :worried:
Du solltest die Ausgabe im Debugmodus etwas mehr erzählen lassen. Wie lang ist der Weg laut Programm und wie lang sind die Alternativen?

 

Ergänzend wäre eine Ausgabe von Open und Closed List mit den Werten für f und h.

 

Solwac

Link zu diesem Kommentar
(Debug Output von meinem astar.php). Schau dir die ersten 3 Felder an. Wäre er optimal müsste es doch 4,0 - 4,1 - 4,2 heißen und nicht 3,1. Kann mir das jemand erklären? :worried:
Du solltest die Ausgabe im Debugmodus etwas mehr erzählen lassen. Wie lang ist der Weg laut Programm und wie lang sind die Alternativen?

 

Ergänzend wäre eine Ausgabe von Open und Closed List mit den Werten für f und h.

 

Solwac

 

Also wenn ich mir die closedlist in der getWay() Funktion ausgeben lasse, sieht das so aus:

 

array(19) { [0]=> array(2) { ["X"]=> int(1) ["Y"]=> int(2) } [1]=> array(2) { ["X"]=> int(1) ["Y"]=> int(3) } [2]=> array(2) { ["X"]=> int(2) ["Y"]=> int(2) } [3]=> array(2) { ["X"]=> int(3) ["Y"]=> int(2) } [4]=> array(2) { ["X"]=> int(2) ["Y"]=> int(0) } [5]=> array(2) { ["X"]=> int(2) ["Y"]=> int(1) } [6]=> array(4) { ["X"]=> int(4) ["Y"]=> int(0) ["VX"]=> int(-1) ["VY"]=> int(-1) } [7]=> array(4) { ["X"]=> int(3) ["Y"]=> int(1) ["VX"]=> int(4) ["VY"]=> int(0) } [8]=> array(4) { ["X"]=> int(3) ["Y"]=> int(0) ["VX"]=> int(4) ["VY"]=> int(0) } [9]=> array(4) { ["X"]=> int(4) ["Y"]=> int(1) ["VX"]=> int(4) ["VY"]=> int(0) } [10]=> array(4) { ["X"]=> int(4) ["Y"]=> int(2) ["VX"]=> int(3) ["VY"]=> int(1) } [11]=> array(4) { ["X"]=> int(3) ["Y"]=> int(3) ["VX"]=> int(4) ["VY"]=> int(2) } [12]=> array(4) { ["X"]=> int(2) ["Y"]=> int(3) ["VX"]=> int(3) ["VY"]=> int(3) } [13]=> array(4) { ["X"]=> int(4) ["Y"]=> int(3) ["VX"]=> int(4) ["VY"]=> int(2) } [14]=> array(4) { ["X"]=> int(2) ["Y"]=> int(4) ["VX"]=> int(3) ["VY"]=> int(3) } [15]=> array(4) { ["X"]=> int(3) ["Y"]=> int(4) ["VX"]=> int(3) ["VY"]=> int(3) } [16]=> array(4) { ["X"]=> int(1) ["Y"]=> int(4) ["VX"]=> int(2) ["VY"]=> int(3) } [17]=> array(4) { ["X"]=> int(0) ["Y"]=> int(3) ["VX"]=> int(1) ["VY"]=> int(4) } [18]=> array(4) { ["X"]=> int(0) ["Y"]=> int(2) ["VX"]=> int(0) ["VY"]=> int(3) } }

 

Und die Openlist:

 

array(8) { [0]=> array(6) { ["X"]=> int(0) ["Y"]=> int(2) ["F"]=> float(9.0710678118655) ["G"]=> float(9.0710678118655) ["VX"]=> int(0) ["VY"]=> int(3) } [1]=> array(6) { ["X"]=> int(4) ["Y"]=> int(4) ["F"]=> float(9.3005630797458) ["G"]=> float(5.6568542494924) ["VX"]=> int(3) ["VY"]=> int(3) } [2]=> array(6) { ["X"]=> int(0) ["Y"]=> int(4) ["F"]=> float(9.6568542494924) ["G"]=> float(7.6568542494924) ["VX"]=> int(1) ["VY"]=> int(4) } [3]=> array(6) { ["X"]=> int(1) ["Y"]=> int(5) ["F"]=> float(10.233345472034) ["G"]=> float(7.0710678118655) ["VX"]=> int(2) ["VY"]=> int(4) } [4]=> array(6) { ["X"]=> int(2) ["Y"]=> int(5) ["F"]=> float(10.262405524956) ["G"]=> float(6.6568542494924) ["VX"]=> int(2) ["VY"]=> int(4) } [5]=> array(6) { ["X"]=> int(3) ["Y"]=> int(5) ["F"]=> float(10.485281374239) ["G"]=> float(7.0710678118655) ["VX"]=> int(2) ["VY"]=> int(4) } [6]=> array(6) { ["X"]=> int(0) ["Y"]=> int(5) ["F"]=> float(11.071067811865) ["G"]=> float(8.0710678118655) ["VX"]=> int(1) ["VY"]=> int(4) } [7]=> array(6) { ["X"]=> int(4) ["Y"]=> int(5) ["F"]=> float(11.656854249492) ["G"]=> float(6.6568542494924) ["VX"]=> int(3) ["VY"]=> int(4) } }

 

Zur Erklärung: Die jenigen in der Closedlist, die nur 2 Einträge besitzen nämlich X und Y sind die Hindernisse die anderen sind die Felder die möglicherweise begangen werden könnten. Hier steht mit VX und VY jeweils der Vorgänger mit den X und Y Koordinaten. Ich fange einfach beim Ziel an und verfolge die Liste zurück, bis ich beim Start bin und habe den Weg.

 

Hier nochmal das ganze für dich aufgemalt:

 

http://www.5load.de/img_67932_koh.gif

 

Und irgendwie kann das einfach nicht sein - wo mache ich den Fehler, denn das ist wirklich nur suboptimal.

 

Bamba

Link zu diesem Kommentar

Erstelle ein Benutzerkonto oder melde Dich an, um zu kommentieren

Du musst ein Benutzerkonto haben, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen. Es ist einfach!

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde Dich hier an.

Jetzt anmelden
×
×
  • Neu erstellen...