2017-05-12 2 views
0

Je travaille sur un solveur de freecell solitaire avec Java et j'ai un problème. Mon solveur semblait fonctionner correctement mais après l'avoir exécuté, je n'ai pas obtenu la réponse que je cherchais. J'ai reprogrammé deux fois de zéro et il semblait que le problème était que certaines cartes disparaissaient en créant de nouveaux états .freecell solitare intelligence artificielle

Ceci est un algorithme Depth First et une carte (ou 2 dans certains cas) ne disparaît que si le dernier état créé (avant celui qui est en cours de création) était de la même profondeur ou plus bas. Je poste ma classe d'état avec une partie de mon algorithme (seulement 2 types de mouvements peuvent être faits: pile à fondation et pile à freecell).

La recherche s'exécute dans le constructeur de l'état "parent". S'il vous plaît aidez si vous le pouvez parce que les cartes qui disparaissent ne peuvent être amusantes que par un magicien qui les exécute devant vous et non par votre ordinateur.

Voici mon code.

import java.util.ArrayList; 

public class State { 

public static ArrayList<State> stateHistory = new ArrayList<State>(); // containing all the states met so far, used to avoid duplicates and endless loops 

public static State bestReached = null; // this state is used to print the best state reached 

// unique elements of the state 
ArrayList<ArrayList<Card>> stackList = new ArrayList<ArrayList<Card>>(); 
ArrayList<ArrayList<Card>> foundationList = new ArrayList<ArrayList<Card>>(); 
ArrayList<Card> freecellList = new ArrayList<Card>(); 
ArrayList<String> previousMoves = new ArrayList<String>(); 
State parent = null; 
int depth; 

// elements used for new state creation 

protected ArrayList<ArrayList<Card>> tempStackList = new ArrayList<ArrayList<Card>>(); 
protected ArrayList<ArrayList<Card>> tempFoundationList = new ArrayList<ArrayList<Card>>(); 
protected ArrayList<Card> tempFreecellList = new ArrayList<Card>(); 
protected Card tempCard; 
protected String tempLastMove = null; 

public State(State s) { 
    this.stackList = s.stackList; 
    this.foundationList = s.foundationList; 
    this.freecellList = s.freecellList; 
} 

public State(ArrayList<ArrayList<Card>> stack, ArrayList<ArrayList<Card>> found, ArrayList<Card> free) { 
    this.stackList = stack; 
    this.foundationList = found; 
    this.freecellList = free; 
    System.out.println("Just created a State successfully!"); 
} 

//the following constructor only works for Depth First search 
public State(ArrayList<ArrayList<Card>> xCardLists, ArrayList<ArrayList<Card>> xFoundationList, ArrayList<Card> xFreecells, ArrayList<String> xPreviousMoves, String xLastMove, State xParent, int xDepth, boolean xIsDepthFirst) { 

    // setting the elements 
    this.stackList = new ArrayList<ArrayList<Card>>(xCardLists); 
    this.foundationList = new ArrayList<ArrayList<Card>>(xFoundationList); 
    this.freecellList = new ArrayList<Card>(xFreecells); 
    if (xPreviousMoves != null) { 
     this.previousMoves = new ArrayList<String>(xPreviousMoves); 
    } 
    if (xLastMove != null) { 
     this.previousMoves.add(xLastMove); 
    } 
    this.parent = xParent; 
    this.depth = xDepth; 

    // checking if it's the best state reached 

    checkIfBestReached(); 

    if (parent != null && parent.totalStateCards() > this.totalStateCards()) { 
     System.out.println(" - ! - WARNING: Cards have been lost! -> Before: " + parent.totalStateCards() + ", Now: " + totalStateCards() + ", Last Move: " + xLastMove); 
    } 

    // delay between state creations for easier error monitoring 

    try { 
     Thread.sleep(2); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    String allPrevious = ""; 

    for (String move : previousMoves) { 
     allPrevious += move + ", "; 
    } 

    // checking the state history and moving on 

    if (shouldHaveChildren() == false) { 
     System.out.println(this.depth + "-> BAD: (total card count: " + totalStateCards() + ", last moves: " + allPrevious + ")"); 
    } else { 

     System.out.println(this.depth + "-> GOOD: (total card count: " + totalStateCards() + ", last moves: " + allPrevious + ")"); 

     // checking for stack to foundation moves 

     for (ArrayList<Card> alc : stackList) { 

      if (alc.isEmpty() == false) { 

       tempCard = alc.get(alc.size()-1); // creating a pointer with the card that is currently being checked 

       if (tempCard.value == GUI.maxN) { 

        // creating the required ArrayLists 
        tempStackList = new ArrayList<ArrayList<Card>>(stackList); 
        tempFoundationList = new ArrayList<ArrayList<Card>>(foundationList); 
        tempFreecellList = new ArrayList<Card>(freecellList); 

        // moving the card 
        tempFoundationList.get(tempCard.type).add(tempCard); 
        tempStackList.get(stackList.indexOf(alc)).remove(tempCard); 

        // creating the last move String 
        tempLastMove = "foundation " + tempCard.fullName; 

        new State(tempStackList, tempFoundationList, tempFreecellList, previousMoves, tempLastMove, this, depth+1, true); 

        // setting all temps to null 

        tempStackList = null; 
        tempFoundationList = null; 
        tempFreecellList = null; 
        tempCard = null; 
        tempLastMove = null; 


       } else { 
        if (foundationList.get(tempCard.type).isEmpty() == false) { 
         if (tempCard.value - foundationList.get(tempCard.type).get(foundationList.get(tempCard.type).size()-1).value == -1) { 

          // creating the required ArrayLists 
          tempStackList = new ArrayList<ArrayList<Card>>(stackList); 
          tempFoundationList = new ArrayList<ArrayList<Card>>(foundationList); 
          tempFreecellList = new ArrayList<Card>(freecellList); 

          // moving the card 
          tempFoundationList.get(tempCard.type).add(tempCard); 
          tempStackList.get(stackList.indexOf(alc)).remove(tempCard); 

          // creating the last move String 
          tempLastMove = "foundation " + tempCard.fullName; 

          new State(tempStackList, tempFoundationList, tempFreecellList, previousMoves, tempLastMove, this, depth+1, true); 

          // setting all temps to null 

          tempStackList = null; 
          tempFoundationList = null; 
          tempFreecellList = null; 
          tempCard = null; 
          tempLastMove = null; 

         } 
        } 
       } 

      } 
     } // here ends the stack to foundation for loop 

     //checking for stack to freecell moves 

     for (ArrayList<Card> alc : stackList) { 

      if (alc.isEmpty() == false) { 

       tempCard = alc.get(alc.size()-1); // creating a pointer with the card that is currently being checked 

       if (freecellList.size() < 4) { 

        // creating the required ArrayLists 
        tempStackList = new ArrayList<ArrayList<Card>>(stackList); 
        tempFoundationList = new ArrayList<ArrayList<Card>>(foundationList); 
        tempFreecellList = new ArrayList<Card>(freecellList); 

        // moving the card 
        tempFreecellList.add(tempCard); 
        tempStackList.get(stackList.indexOf(alc)).remove(tempCard); 

        // creating the last move String 
        tempLastMove = "freecell " + tempCard.fullName; 

        new State(tempStackList, tempFoundationList, tempFreecellList, previousMoves, tempLastMove, this, depth+1, true); 

        // setting all temps to null 

        tempStackList = null; 
        tempFoundationList = null; 
        tempFreecellList = null; 
        tempCard = null; 
        tempLastMove = null; 

       } 

      } 
     } 

    } 

    // setting all temps to null 

    tempStackList = null; 
    tempFoundationList = null; 
    tempFreecellList = null; 
    tempCard = null; 
    tempLastMove = null; 

} 

public boolean shouldHaveChildren() { 

    if (stateHistory.isEmpty() == true) { 
     stateHistory.add(this); 
     return true; 
    } else { 
     for (State state : stateHistory) { 
      if (statesAreEqual(state, this) == true) { 
       return false; 
      } 
     } 
     stateHistory.add(this); 
     return true; 
    } 

} 

public static boolean statesAreEqual(State s1, State s2) { // checks if 2 states are equal or not 

    // checking foundationList equality 

    if (s1.foundationList.size() != s2.foundationList.size()) { 
     return false; 
    } else { 

     for (int i = 0; i < s1.foundationList.size(); i++) { 

      if (s1.foundationList.get(i).size() != s2.foundationList.size()) { 
       return false; 
      } else { 

       for (int j = 0; j < s1.foundationList.get(i).size(); j++) { 

        if (s1.foundationList.get(i).get(j) != s2.foundationList.get(i).get(j)) { 
         return false; 
        } 

       } 

      } 

     } 

    } 

    // checking stackList equality 

    if (s1.stackList.size() != s2.stackList.size()) { 
     return false; 
    } else { 

     for (int i = 0; i < s1.stackList.size(); i++) { 

      if (s1.stackList.get(i).size() != s2.stackList.size()) { 
       return false; 
      } else { 

       for (int j = 0; j < s1.stackList.get(i).size(); j++) { 

        if (s1.stackList.get(i).get(j) != s2.stackList.get(i).get(j)) { 
         return false; 
        } 

       } 

      } 

     } 

    } 

    // checking for freecellList equality 

    if (s1.freecellList.size() != s2.freecellList.size()) { 
     return false; 
    } else { 

     for (Card c : s1.freecellList) { 
      if (s2.freecellList.contains(c) == false) { 
       return false; 
      } 
     } 

    } 

    return true; 
} 

// checks if the current state is the best state reached (most cards in the foundations) 

public void checkIfBestReached() { 

    if (stateHistory.isEmpty()) { 

     bestReached = this; 

    } else { 

     int sum = 0; 

     for (ArrayList<Card> alc : foundationList) { 

      sum += alc.size(); 

     } 

     int sum2 = 0; 

     for (ArrayList<Card> alc : bestReached.foundationList) { 

      sum2 += alc.size(); 

     } 

     if (sum > sum2) { 

      bestReached = this; 

     } 

    } 

} 

public int totalStateCards() { 

    int sum = 0; 

    for (ArrayList<Card> alc : stackList) { 
     sum += alc.size(); 
    } 
    for (ArrayList<Card> alc : foundationList) { 
     sum += alc.size(); 
    } 
    sum += freecellList.size(); 

    return sum; 

} 

} 
+0

Il vous est. Tu es le magicien. –

+0

Sur une note plus sérieuse, veuillez faire un effort pour affiner votre problème. Vous venez de nous jeter quelques centaines de lignes de code sans analyse ni apparence d'effort de votre part. –

+0

ce n'est pas un algorithme compliqué. Un arbre des "états" est en cours de création et en remontant une branche (un état ne peut pas avoir d'enfants) la dernière carte déplacée disparaît simplement. –

Répondre

0

J'ai trouvé quel était le problème. La façon dont j'ai créé les tableaux temporaires est fausse. Le constructeur

ArrayList<ArrayList<Type>> newArray = ArrayList<ArrayList<Type>>(anotherArray);  

copie les tableaux internes de UnAutreTableau dans le newArray, ce qui signifie à la fois des tableaux-de-tableaux auront les tableaux exacts à l'intérieur d'eux. Donc en supprimant un objet (une carte) d'un tableau, il est supprimé de l'autre. Pour annuler cela se produise, j'ai créé une méthode appelée copyTheDoubleArray:

public void copyTheDoubleArray(ArrayList<ArrayList<Card>> array1, ArrayList<ArrayList<Card>> array2) { 

    for (int i = 0; i < array1.size(); i++) { 
     array2.add(new ArrayList<Card>()); 
     for (int j = 0; j < array1.get(i).size(); j++) { 
      array2.get(i).add(array1.get(i).get(j)); 
     } 
    } 

} 

Cette copie les tableaux-de-gamme et la seule chose que les nouvelles actions de tableau avec l'ancien est les cartes, qui sont les mêmes dans chaque état de toute façon. J'espère que cela aide si quelqu'un a le même problème.

*** La chose importanting de ce post est que vous ne devez pas utiliser le premier constructeur à copier des tableaux-de-gamme, mais seulement des tableaux simples comme

ArrayList<Card> newCardArray = new ArrayList<Card>(oldCardArray);