package rating; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import alphaBeta.AlphaBetaSearch; import useful.Fingerprint; import useful.MoveGenerator; import useful.SituationWithRating; import util.ChessfigureConstants; import java.util.TreeMap; public class PrimitivKI implements Serializable { /** * */ private static final long serialVersionUID = 1L; private MoveGenerator moveGen = new MoveGenerator(); final int PARALLEL = 2; private PrimitivRating prim; private TreeMap<String, SituationWithFingerprint> situationsWithFingerprintTree; public PrimitivKI() { this.situationsWithFingerprintTree = new TreeMap<String, SituationWithFingerprint>(); prim = new PrimitivRating(); } /* * Über die eingebettete Klasse ist es Moeglich, einem Fingerprint die * moeglichen Zuege zuzuordnen. Dies ist noetig, damit dieses Objekt in eine * Liste gehängt werden kann, welche dann nach Fingerprints durchsucht wird. */ class SituationWithFingerprint implements Serializable { /** * */ private static final long serialVersionUID = 1L; String fingerprint; LinkedList<SituationWithRating> situations; private int depth; public SituationWithFingerprint(String fingerprint, LinkedList<SituationWithRating> situations, int depth) { this.fingerprint = fingerprint; this.situations = situations; this.depth = depth; System.out.println("tiefe " + depth); } public void setNode(String fingerprint, LinkedList<SituationWithRating> situations, int depth) { this.fingerprint = fingerprint; this.situations = situations; this.depth = depth; } public String getFingerprint() { return this.fingerprint; } public LinkedList<SituationWithRating> getSituation() { return this.situations; } public int getDepth() { return this.depth; } } /* * Fuer die Deserialisierung; Auslesen aller gepeicherten Werte */ public TreeMap<String, SituationWithFingerprint> getTree() { return this.situationsWithFingerprintTree; } /* * Es wird eine bestimmte Situation via Fingerprint in den gespeicherten * Werten gesucht. * * @fingerprint Fingerprint des aktuellen Spielfeldes * * @return LinkedList mit Objekten des Typs SituationWithRating oder NULL * wenn keine solche Liste existiert */ public LinkedList<SituationWithRating> getSituations(String fingerprint) { SituationWithFingerprint fp = this.situationsWithFingerprintTree.get(fingerprint); if (fp != null) { return fp.getSituation(); } else { return null; } } public int getDepth(String fingerprint) { System.out.println(fingerprint + " " + situationsWithFingerprintTree.containsKey(fingerprint)); if (this.situationsWithFingerprintTree.containsKey(fingerprint)) { return this.situationsWithFingerprintTree.get(fingerprint).getDepth(); } else { return 0; } } public void concat(String filename) { // Auslesen aus Dateipfad PrimitivKI ki = null; try { FileInputStream file = new FileInputStream(filename); ObjectInputStream o = new ObjectInputStream(file); ki = (PrimitivKI) o.readObject(); o.close(); } catch (IOException e) { System.err.println(e); } catch (ClassNotFoundException e) { System.err.println(e); } if (ki != null) { TreeMap<String, SituationWithFingerprint> tree = ki.getTree(); while (tree.size() > 0) { Map.Entry<String, SituationWithFingerprint> entry = tree.pollFirstEntry(); // Eintrag existiert schon if (this.situationsWithFingerprintTree.containsKey(entry.getKey())) { System.out.println("Eintrag exist"); // Vorhandener Eintrag ist aber schlechter (Suchtiefe) if (this.situationsWithFingerprintTree.get(entry.getKey()).getDepth() < entry.getValue().getDepth()) { System.out.println("Eintrag besser"); this.situationsWithFingerprintTree.remove(entry.getKey()); this.situationsWithFingerprintTree.put(entry.getKey(), entry.getValue()); } } // Eintrag existiert nicht, wird einfach hinzugefuegt else { System.out.println("Eintrag nicht vor. hinzugefuegt"); this.situationsWithFingerprintTree.put(entry.getKey(), entry.getValue()); } } } } /* * Es wird eine Situation berechnet und eingespeichert; Zuvor wird geschaut, * ob Situation schon existiert. Wenn sie bereits existiert, die Suchtiefe * aber geringer ist, so wird dennoch neu berechnet. * * @param map aktuelles Spielfeld als Hashmap * * @param depth Wieviele Halbzuege im Vorraus gerechnet werden soll * * @param Spieler der am Zug ist */ public void teachSituation(HashMap<Integer, Byte> map, int depth, byte player) { HashMap<Integer, Byte> cloneMap = (HashMap<Integer, Byte>) map.clone(); String fp = Fingerprint.getFingerprint(cloneMap); if (this.situationsWithFingerprintTree.containsKey(fp)) { if (this.situationsWithFingerprintTree.get(fp).depth < depth) { this.situationsWithFingerprintTree.remove(fp); calculateSituation(map, depth, player); } } else { calculateSituation(map, depth, player); } } public void setSituation(String fp, LinkedList<SituationWithRating> sit, int depth) { if (this.situationsWithFingerprintTree.containsKey(fp)) { if (this.situationsWithFingerprintTree.get(fp).depth < depth) { this.situationsWithFingerprintTree.remove(fp); this.situationsWithFingerprintTree.put(fp, new SituationWithFingerprint(fp, sit, depth)); } } else { this.situationsWithFingerprintTree.put(fp, new SituationWithFingerprint(fp, sit, depth)); } } /* * Es wird eine Situation berechnet und eingespeichert * * @param map aktuelles Spielfeld als Hashmap * * @param depth Wieviele Halbzuege im Vorraus gerechnet werden soll * * @param Spieler der am Zug ist */ private void calculateSituation(HashMap<Integer, Byte> map, int depth, byte player) { HashMap<Integer, Byte> cloneMap = (HashMap<Integer, Byte>) map.clone(); LinkedList<HashMap<Integer, Byte>> childSit = moveGen.generateMoves(cloneMap, player); LinkedList<SituationWithRating> list = new LinkedList<SituationWithRating>(); while (!childSit.isEmpty()) { list.add(new SituationWithRating(childSit.pollLast(), 0, 0)); } byte changePlayer = (player == ChessfigureConstants.WHITE ? ChessfigureConstants.BLACK : ChessfigureConstants.WHITE); LinkedList<SituationWithRating> ratedList = rateChildSituations(changePlayer, list, depth); prim.primPositionRating(ratedList, player); LinkedList<SituationWithRating> bestMaps = new LinkedList<SituationWithRating>(); int max = findMaxRating(ratedList); SituationWithRating rating; while (ratedList.size() > 0) { rating = ratedList.pollFirst(); if (rating.getFigureRating() == max) { bestMaps.add(rating); } } System.out.println("Listengroesse " + bestMaps.size()); String fp = Fingerprint.getFingerprint(cloneMap); this.situationsWithFingerprintTree.put(fp, new SituationWithFingerprint(fp, bestMaps, depth)); System.out.println(fp + " put"); } /* * Maximal bewertete Situation wird rausgesucht * * @param map Hashmap der Situation * * @return maximale Wert */ private int findMaxRating(LinkedList<SituationWithRating> map) throws NullPointerException { LinkedList<SituationWithRating> cloneMap = (LinkedList<SituationWithRating>) map.clone(); if (cloneMap.size() > 0) { int max = cloneMap.pollFirst().getFigureRating(); int rating; while (cloneMap.size() > 0) { rating = cloneMap.pollFirst().getFigureRating(); if (max < rating) { max = rating; } } return max; } else { throw new NullPointerException("Leere Map uebergeben"); } } /* * Methode in der die Threads initialisiert werden und die AlphaBeta Suche * gestartet wird */ private LinkedList<SituationWithRating> rateChildSituations(byte player, LinkedList<SituationWithRating> list, int depth) { AlphaBetaSearch[] abThreads = new AlphaBetaSearch[list.size()]; for (int i = 0; i < list.size(); i++) { // Thread erstellen mit SituationWithRating,depth,player abThreads[i] = new AlphaBetaSearch(list.get(i), depth, player); abThreads[i].setName("" + i); } // startet eine bestimmte Anzahl an Threads orderedThreadStart(abThreads, PARALLEL); LinkedList<SituationWithRating> helpList = new LinkedList<SituationWithRating>(); for (AlphaBetaSearch ab : abThreads) { helpList.add(ab.getSituationWithRating()); } return helpList; } /* * Es sollten nicht alle Suchen gleichzeitig als seperater Thread gestartet * werden, da das Scheduling ansonsten die Sache extrem verlangsamt. Die * Methode orderedThreadStart achtet darauf, dass immer nur eine zuvor * bestimmte Anzahl an Threads gleichzeitig laufen. Wenn diese beendet * werden, dann startet diese Methode automatisch die naechsten Threads aus * dem Array AlphaBetaSearch. * * @param ab Array von Threads des Typ AlphaBetaSearch * * @param parallelValue Anzahl an gleichzeitig laufenden Threads */ private boolean orderedThreadStart(AlphaBetaSearch[] ab, int parallelValue) { System.out.println("Anzahl an Wurzeln " + ab.length); /* * wenn anzahl der möglichen Threads kleiner ist als maximale Anzahl * gleichzeitiger Threads dann gleich alle starten */ if (parallelValue >= ab.length) { for (int i = 0; i < ab.length; i++) { ab[i].start(); } } else { int counter = ab.length - 1; // solange Zuege da sind while (counter >= 0) { // duerfen noch Threads gestartet werden oder laufen genug // parallel? if (ab[0].getNumberOfThreads() < parallelValue) { ab[counter].start(); counter--; } // ein wenig abwarten, damit schleife nicht komplett cpu // auslastet try { Thread.sleep(1 * parallelValue); } catch (Exception e) { } } } // letzten Threads die noch laufen beenden lassen while (ab[0].getNumberOfThreads() != 0) { try { Thread.sleep(1 * parallelValue); } catch (Exception e) { } } return true; } /* * Schreibt das aktuelle Objekt in eine Datei * * @param filename Datei in welche geschrieben werden soll inkl. Pfad (z.B. * Pfad/datei.ser) */ public void serialize(String filename) { try { FileOutputStream file = new FileOutputStream(filename); ObjectOutputStream o = new ObjectOutputStream(file); o.writeObject(this); o.close(); } catch (IOException e) { System.err.println(e); } } /* * Ueberschreibt das aktuelle Objekt mit dem serialisiertem Objekt * * @param filename Pfad zum serialisiertem Objekt (z.B. Pfad/datei.ser) */ public void deserialize(String filename) { try { FileInputStream file = new FileInputStream(filename); ObjectInputStream o = new ObjectInputStream(file); PrimitivKI ki = (PrimitivKI) o.readObject(); o.close(); this.situationsWithFingerprintTree = ki.getTree(); } catch (IOException e) { System.out.println("Datei " + filename + " angelegt"); this.serialize(filename); } catch (ClassNotFoundException e) { System.err.println(e); } } }