// Demo of A* algorithm import ai.pathfinder.*; //pathfinder-bibliothek --> dort wird der pfad und so berechnet Pathfinder astar; //reservation eines typs pathfinder mit dem namen "astar" ArrayList path = new ArrayList(); //array des pfades ArrayList snake = new ArrayList(); //array für snake --> teil von path int w = 20; //anzahl felder in der breite int h = 20; //anzahl felder in der höhe int spacing; //variable für abstand PFont font; //schrift boolean pause = true; //fürs anhalten Node a; //startpunkt Node b; //endpunkt int position = 0; //position von snake auf path boolean end = false; //"futter"erreicht int jump = 0; //fürs einziehen int runCounter = 0; //zählt durchgänge --> nach z.b. 10 macht er neue schwarze felder void setup(){ size(300, 300); //fenstergrösse: breite, höhe spacing = width / w; //abstand smooth(); //weichzeichner rectMode(CENTER); //rechtecke von der mitte auszeichnen --> mitte = node! astar = new Pathfinder(); //definiert astar astar.wrap = true; //true = pfad sollte über kante hinausgehen, zus. mit manhattan-methode; aber geht irgendwie nur wenn zielpunkt genau am rand ist... könnte ein fehler in pathfinder sein astar.corners = false; //true = pfad kann schräg gehen; false = nur horizontal und vertikal astar.manhattan = true; // true = manhattan-methode --> weiss nicht genau was das bewirkt, es half auf jedenfall im programmier-prozess ;-) astar.offsetX = spacing/2; //für pathfinder astar.offsetY = spacing/2; //für pathfinder astar.setCuboidNodes(w, h, spacing); // definiert ein netz aus knotenpunkten --> mittelpunkte der quadrate, pfad geht jeweils von node zu node setNonWalkableNodes(); // verteilt zufällig schwarze felder astar.radialDisconnectUnwalkables(); //kappt verbindung zu unbegehbaren felder } void setNonWalkableNodes(){ // verteilt zufällig schwarze felder for(int i = 0; i < astar.nodes.size(); i++){ ((Node)astar.nodes.get(i)).walkable = true; //zuerst alle weiss/begehbar } /* for(int j = 9*w; j < 10*w; j++){ //setzt eine ganze zeile schwarze felder Node temp = (Node)astar.nodes.get(j); temp.walkable = false; } for(int j = 0; j < h; j++){ //setzt eine ganze spalte schwarze felder Node temp = (Node)astar.nodes.get(j*w+10); //der summand bestimmt welche spalte temp.walkable = false; }*/ for(int i = 0; i < 150; i++){ //setzt zufällig X schwarze felder Node temp = getRandomNode(); temp.walkable = false; } } void draw() { frameRate(12); Node targetNode = null; //zielpunkt; noch leer if(end) { //wenn zielpunkt erreicht delay(450); //wartet kurz beim "futter" end = false; //end wieder freigeben /* if(runCounter == 10){ //nach dem X.ten durchlauf werden hier neue schwarze felder gesetzt --> andere bewohner wollen snake (nicht) //setzt alles zurück --> neustart setNonWalkableNodes(); a = (Node)path.get(path.size() - 1); println(a.x + " " + a.y); path.clear(); snake.clear(); runCounter = 0; jump = 0; } else { //zählt durchgänge runCounter++; } */ } else{ //verzögerung beim zeichnen von snake, damit es nicht zu schnell wird delay(5); } if(jump != 0){ //wenn kein pfad möglich zieht sich snake ein und soll an einer späteren stelle wieder rauskommen jump--; //zähtl variable jump runter snake.remove(jump); //löscht das letzte glied von snake --> sieht wie einziehen aus targetNode = (Node)path.get(path.size() - 1); //speichert den letzten punkt von path doDraw(targetNode); //neuzeichnen mit dem letzten punkt als eingabe if(jump != snake.size()) { //sicherung, es gab manchmal so komische fehler jump = snake.size(); } return; //zurück } if(path.size() == 0 || position == (path.size() - 1)) { //am anfang(pfad ist leer) oder snake am ende boolean pathSize = false; if(path.size() != 0) { // targetNode = (Node)path.get(path.size() - 1); //speichert den letzten punkt von path } else { pathSize = true; } if(b == null) { b = getRandomNode(); } else{ end = true; } a = b; while(b == a){ b = getRandomNode(); } ArrayList previousPath = (ArrayList)path.clone(); //kopiert pfad --> zwischenspeicherung path.clear(); //löscht den pfad path = astar.aStar(b, a); //rechnet neuen pfad aus if(previousPath.size() != 0 && (((Node)previousPath.get(previousPath.size() - 1)) != ((Node)path.get(0)))) { path.add(0, previousPath.get(previousPath.size() - 1)); jump = snake.size(); } position = 0; if(pathSize){ targetNode = (Node)path.get(path.size() - 1); } } if(path.size() <= position){ //sicherung; löscht pfad path.clear(); return; } if(targetNode == null) { //sicherung targetNode = (Node)path.get(path.size() - 1); } if(snake.size() == 0) { //snake beginn snake.add(0, path.get(position)); //setzt ersten punkt von path position++; //zählt rauf if(path.size() <= position){ //sicherung path.clear(); return; } } snake.add(0, path.get(position)); position++; //wenn snake über kante geht --> einziehen und wieder ausfahren /* if(!checkNebendran(path, position)) { snake.remove(0); jump = snake.size()-1; return; } */ if(snake.size() > 10){ //grösse/länge von snake --> löscht jeweils das letzte snake.remove(10); } doDraw(targetNode); } void doDraw(Node targetNode){ background(80); drawNodes(); drawTargetNode(targetNode); drawSnake(); if (snake.size() != 0){ drawSnakeHead(); //schlangenkopf - geht irgendwie nicht immer wenn snake über die kante kann } // uncomment the line below to see the Connectors // drawConnectors(); } boolean checkNebendran(ArrayList path, int position){ //sollte checken, ob der vorherige mehr als spacing entfernt ist --> pfad über die kante if(position > 0){ // println("X: "+abs(((Node)snake.get(0)).x - ((Node)snake.get(1)).x)+"="+((Node)snake.get(0)).x+"-"+((Node)snake.get(1)).x); // println("Y: "+abs(((Node)snake.get(0)).y - ((Node)snake.get(1)).y)+"\n"); if(abs(((Node)snake.get(0)).x - ((Node)snake.get(1)).x) > spacing){ // println("ABS: "+abs(((Node)snake.get(0)).x - ((Node)snake.get(1)).x)); //x-differenz return false; } else if(abs(((Node)snake.get(0)).y - ((Node)snake.get(1)).y) > spacing){ //y-differenz println("ABS: "+abs(((Node)snake.get(0)).y - ((Node)snake.get(1)).y)); return false; } else { return true; } } else { return true; } } void mousePressed(){ //reagiert auf mausklick if(pause){ // pause = false; // loop(); // } else{ pause = true; // noLoop(); // } } Node getRandomNode(){ //holt sich zufallspunkt Node n = null; while(true){ n = (Node)astar.nodes.get((int)random(astar.nodes.size())); if(n.walkable) break; } return n; } void drawNodes(){ //zeichnet nodes stroke(230); //randfarbe fill(255); //füllfarbe weiss strokeWeight(1); //randstärke for(int i = 0; i < astar.nodes.size(); i++){ //geht alle nodes durch Node temp = (Node)astar.nodes.get(i); //speichert node in temp zwischen if(temp.walkable){ //wenn begehbar rect(temp.x, temp.y, spacing, spacing); //zeichne rechteck --> von mitte aus } } } void drawTargetNode(Node target){ //zeichnet zielpunkt stroke(255); fill(255,0,0 ); strokeWeight(1); rect(target.x, target.y, spacing, spacing); } void drawSnake(){ //zeichnet snake strokeWeight(2); fill(40, 230, 40,150); stroke(255); if(snake != null){ // beginShape(); for(int i = 0; i < snake.size(); i++){ Node temp = (Node)snake.get(i); rect(temp.x, temp.y, spacing, spacing); //vertex(temp.x, temp.y); } // endShape(); } } void drawSnakeHead(){ //zeichnet kopf von snake strokeWeight(2); fill(50,50,255,150); stroke(255); if(snake != null){ // beginShape(); Node temp = (Node)snake.get(0); rect(temp.x, temp.y, spacing, spacing); // vertex(temp.x, temp.y); // endShape(); } } void drawConnectors(){ //zeichnet verbindungen strokeWeight(1); stroke(50,50,250); for(int i = 0; i < astar.nodes.size(); i++){ Node n = (Node)astar.nodes.get(i); if(n.walkable){ for(int j = 0; j < n.links.size(); j++){ Connector c = (Connector)n.links.get(j); line(n.x, n.y, c.n.x, c.n.y); } } } }