/// <summary> /// Μέθοδος που επιστρέφει το μέτωπο ταξινομημένο. Με χρήση της ευρετικής συνάρτησης, /// το μέτωπο αναζήτησης ταξινομείται ώστε να γίνει επίσκεψη πρώτα στον κατάλληλο κόμβο ( βάση αλγορίθμου). /// </summary> /// <param name="method"> αλγόριθμος </param> /// <returns> το μέτωπο </returns> public Frontier SortedFrontier(Αuxiliary.methodEnum method) { Frontier resultFrontier = new Frontier(); switch (method) { case Αuxiliary.methodEnum.Breadth: resultFrontier = this; break; case Αuxiliary.methodEnum.Depth: resultFrontier = this; break; case Αuxiliary.methodEnum.Best: var test = from state in this orderby state.h select state; foreach (State s in test) { resultFrontier.AddLast(s); } break; case Αuxiliary.methodEnum.AStar: test = from state in this orderby state.f select state; foreach (State s in test) { resultFrontier.AddLast(s); } break; } return(resultFrontier); }
/// <summary> /// Εδώ εξετάζεται εάν η μέθοδος είναι αλγόριθμος που χρησιμοποιεί ευρετική συνάρτηση. /// </summary> /// <param name="method"> αλγόριθμος </param> public void Calc(Αuxiliary.methodEnum method) { switch (method) { case Αuxiliary.methodEnum.Best: h = CalcH(); break; case Αuxiliary.methodEnum.AStar: h = CalcH(); f = g + h; break; default: break; } }
} // solveProblem method /// <summary> /// Μέθοδος που επιστρέφει τον επιλεγμένο αλγόριθμο αναζήτησης. /// </summary> /// <returns> τον αλγόριθμο αναζήτησης. </returns> public static Αuxiliary.methodEnum getMethod() { Αuxiliary.methodEnum resultMethod = Αuxiliary.methodEnum.Empty; if (sMethod.Equals("breadth")) { resultMethod = Αuxiliary.methodEnum.Breadth; } else if (sMethod.Equals("depth")) { resultMethod = Αuxiliary.methodEnum.Depth; } else if (sMethod.Equals("best")) { resultMethod = Αuxiliary.methodEnum.Best; } else if (sMethod.Equals("astar")) { resultMethod = Αuxiliary.methodEnum.AStar; } return(resultMethod); }
/// <summary> /// Προσθέτει μια κατάσταση στο μέτωπο αναζήτησης. /// </summary> /// <param name="s"> η κατάσταση που θα προστεθεί.</param> /// <param name="method"> αλγόριθμος </param> public void AddState(State s, Αuxiliary.methodEnum method) { s.Calc(method); this.AddLast(s); }
/// <summary> /// Μέθοδος που βρίσκει τα παιδιά της τρέχουσας κατάστασης και τα επιστρέφει. /// </summary> /// <param name="method"> όνομα μεθόδου για αναζήτηση. </param> /// <returns> τα παιδιά τύπου Frontier </returns> public Frontier GetChildrenStates(Αuxiliary.methodEnum method) { Frontier children = new Frontier(); bool EmptyFreeCellExamined = false; #region loop freecells for (int j = 0; j < Αuxiliary.freeCellCount; j++) { Card freeCellCard = freeCell[j]; if (freeCellCard != null) { #region from freecell to foundation switch (freeCellCard.Symbol) { case SymbolEnum.Clubs: if (freeCellCard.FoundationRule(ClubsFoundation)) { State childState = this.Clone(); childState.ClubsFoundation++; childState.freeCell[j] = null; childState.Parent = this; childState.Move = freeCellCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Diamonds: if (freeCellCard.FoundationRule(DiamondsFoundation)) { State childState = this.Clone(); childState.DiamondsFoundation++; childState.freeCell[j] = null; childState.Parent = this; childState.Move = freeCellCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Hearts: if (freeCellCard.FoundationRule(HeartsFoundation)) { State childState = this.Clone(); childState.HeartsFoundation++; childState.freeCell[j] = null; childState.Parent = this; childState.Move = freeCellCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Spades: if (freeCellCard.FoundationRule(SpadesFoundation)) { State childState = this.Clone(); childState.SpadesFoundation++; childState.freeCell[j] = null; childState.Parent = this; childState.Move = freeCellCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; } #endregion from freecell to foundation #region from freecell to stack for (int i = 0; i < Αuxiliary.stacksCount; i++) { if (this.stacks[i] != null && this.stacks[i].Count > 0) { Card sCard = this.stacks[i].Last(); if (((sCard != null) & (freeCellCard.StacksRule(sCard) == StacksRuleEnum.RuleBefore)) || //stack αντίθετου χρώματος και μεγαλύτερης κατά 1 τιμής (sCard == null)) //Άδειο stack { { State childState = this.Clone(); childState.stacks[i].AddLast(freeCellCard); childState.freeCell[j] = null; if (!childState.AlreadyInHistory()) { childState.Parent = this; childState.Move = freeCellCard.ToString(); childState.MoveType = MoveEnum.moveEmtpyStack; children.AddState(childState, method); } //freeCellCard.Show(); } } } } // for #endregion from freecell to stack } else { #region from stack to freecell if (!EmptyFreeCellExamined) //μόνο για ένα freecell να γίνει, όλα τα freecells είναι ισοδύναμα { for (int i = 0; i < Αuxiliary.stacksCount; i++) { if (this.stacks[i] != null && this.stacks[i].Count > 0) { if (this.stacks[i].Last != null) { State childState = this.Clone(); childState.freeCell[j] = childState.stacks[i].Pop(); if (!childState.AlreadyInHistory()) { childState.Parent = this; childState.Move = childState.freeCell[j].ToString(); childState.MoveType = MoveEnum.moveFreecell; children.AddState(childState, method); } } } } // for EmptyFreeCellExamined = true; } #endregion from stack to freecell } } #endregion loop freecells #region loop stacks for (int i = 0; i < Αuxiliary.stacksCount; i++) { Card aCard; if ((this.stacks[i] == null) || (this.stacks[i].Count == 0)) { aCard = null; } else { aCard = this.stacks[i].Last(); #region from stack to foundation switch (aCard.Symbol) { case SymbolEnum.Clubs: if (aCard.FoundationRule(ClubsFoundation)) { State childState = this.Clone(); childState.ClubsFoundation++; childState.stacks[i].RemoveLast(); childState.Parent = this; childState.Move = aCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Diamonds: if (aCard.FoundationRule(DiamondsFoundation)) { State childState = this.Clone(); childState.DiamondsFoundation++; childState.stacks[i].RemoveLast(); childState.Parent = this; childState.Move = aCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Hearts: if (aCard.FoundationRule(HeartsFoundation)) { State childState = this.Clone(); childState.HeartsFoundation++; childState.stacks[i].RemoveLast(); childState.Parent = this; childState.Move = aCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; case SymbolEnum.Spades: if (aCard.FoundationRule(SpadesFoundation)) { State childState = this.Clone(); childState.SpadesFoundation++; childState.stacks[i].RemoveLast(); childState.Parent = this; childState.Move = aCard.ToString(); childState.MoveType = MoveEnum.moveFoundation; children.AddState(childState, method); } break; } #endregion from stack to foundation } #region from stack to another stack for (int j = Convert.ToByte(i + 1); j < Αuxiliary.stacksCount; j++) { Card bCard; if ((this.stacks[j] == null) || (this.stacks[j].Count == 0)) { bCard = null; } else { bCard = this.stacks[j].Last(); } int SourceStackId = 100; int TargetStackId = 100; if ((aCard == null) & (bCard == null)) //Αν και τα δύο stacks είναι κενά { continue; } else if ((aCard == null) && (bCard != null)) //Αν το 1ο είναι κενό ενώ το 2ο όχι { if (this.stacks[j].Count == 1) { continue; } else { SourceStackId = j; TargetStackId = i; } } //θέλουμε να βρούμε και την περίπτωση όπου ένα stack έχει μόνο μια κάρτα και ένα άλλο είναι κενό //Σε αυτή την περίπτωση δε θέλουμε μετακίνηση else if ((aCard != null) && (bCard == null)) //Αν το 2ο είναι κενό ενώ το 1ο όχι { if (this.stacks[i].Count == 1) { continue; } else { SourceStackId = i; TargetStackId = j; } } else //Αν κανένα δεν είναι κενό { switch (aCard.StacksRule(bCard)) { case StacksRuleEnum.RuleBefore: SourceStackId = j; TargetStackId = i; break; case StacksRuleEnum.RuleAfter: SourceStackId = i; TargetStackId = j; break; default: continue; break; } } State childState = this.Clone(); Card PreviousTargetCard = null; if (childState.stacks[TargetStackId] == null) { childState.stacks[TargetStackId] = new Stacks(); } if (childState.stacks[TargetStackId].Count > 0) { PreviousTargetCard = childState.stacks[TargetStackId].Last(); } childState.stacks[TargetStackId].AddLast(this.stacks[SourceStackId].Last()); childState.stacks[SourceStackId].RemoveLast(); if (!childState.AlreadyInHistory()) { childState.Parent = this; if (childState.stacks[TargetStackId].Count == 1) //new Stack { childState.Move = childState.stacks[TargetStackId].Last().ToString(); childState.MoveType = MoveEnum.moveEmtpyStack; } else { childState.Move = childState.stacks[TargetStackId].Last().ToString() + " " + PreviousTargetCard.ToString(); childState.MoveType = MoveEnum.moveCascade; } children.AddState(childState, method); } } #endregion from stack to another stack } #endregion loop stacks return(children); }
/// <summary> /// Η μέθοδος αυτή εξετάζει τους κόμβους στο μέτωπο αναζήτησης μέχρι να βρει λύση στο παιχνίδι ή να φτάσει σε timeout. /// </summary> private static void solveProblem() { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); // ξεκινάει η χρονομέτρηση. Frontier gameFrontier = new Frontier(); Αuxiliary.gameHistory = new Frontier(); int step = 0; gameFrontier.AddLast(initialState); method = getMethod(); // Επανάληψη που εξετάζει όλους τους κόμβους (καταστάσεις) που υπάρχουν στο μέτωπο αναζήτησης. while (gameFrontier.Count > 0) { State currentState = gameFrontier.Pop(); Αuxiliary.gameHistory.AddLast(currentState); step++; if (step % 100 == 0) { System.Console.WriteLine("Step " + step); } // αν έχει βρεθεί λύση. if (currentState.Status() == State.stateStatusEnum.SolutionFound) { System.Console.WriteLine("Βρέθηκε λύση σε " + Convert.ToString(stopWatch.ElapsedMilliseconds / 1000) + " δευτερόλεπτα"); State lastState = currentState; State t = lastState.Parent; int totalSteps = 0; while (t.Parent != initialState) { t.SolutionChild = lastState; lastState = t; t = lastState.Parent; totalSteps++; } System.Console.WriteLine("Βήματα από την αρχική κατάσταση εως τη λύση " + Convert.ToString(totalSteps)); System.Console.WriteLine("Κόμβοι που εξετάστηκαν: " + Convert.ToString(step)); t.SolutionChild = lastState; string solutionText = totalSteps.ToString() + Environment.NewLine; // μαζεύω τα βήματα μέχρι την λύση. while (t.SolutionChild != null) { //Stopwatch s = new Stopwatch(); //s.Start(); solutionText = solutionText + t.TotalMove() + Environment.NewLine; t = t.SolutionChild; } // εξαγωγή σε αρχείο. solutionText = solutionText + t.TotalMove() + Environment.NewLine; System.IO.File.WriteAllText(outputFileName, solutionText); System.Diagnostics.Process.Start(outputFileName); return; } // if // αν δεν βρέθηκε λύση εξετάζω τα παιδιά του κόμβου ανάλογα με τον αλγόριθμο πάντα. Frontier childrenFrontier = currentState.GetChildrenStates(method); switch (method) { case Αuxiliary.methodEnum.Breadth: // αν έχει επιλεγεί πρώτα σε πλάτος, τότε προσθέτω στην αρχή (εξετάζεται στο τέλος) του μετώπου το State εκείνο. foreach (State state in childrenFrontier) { gameFrontier.AddFirst(state); } break; case Αuxiliary.methodEnum.Depth: // αν έχει επιλεγεί πρώτα σε βάθος, τότε βάζω το State στο τέλος (άρα θα είναι το επόμενο που θα εξεταστεί). foreach (State state in childrenFrontier) { gameFrontier.AddLast(state); } break; case Αuxiliary.methodEnum.AStar: // Για ευρετικούς αλγορίθμους προσθέτω το Stat στο τέλος και μετά ταξινομώ με βάση την ευρετική συνάρτηση. foreach (State state in childrenFrontier) { gameFrontier.AddLast(state); } gameFrontier = gameFrontier.SortedFrontier(method); break; case Αuxiliary.methodEnum.Best: // Για ευρετικούς αλγορίθμους προσθέτω το State στο τέλος και μετά ταξινομώ με βάση την ευρετική συνάρτηση. foreach (State state in childrenFrontier) { gameFrontier.AddLast(state); } gameFrontier = gameFrontier.SortedFrontier(method); break; case Αuxiliary.methodEnum.Empty: break; } if (stopWatch.ElapsedMilliseconds > Αuxiliary.TIMEOUT * 1000) { System.Console.WriteLine("Δεν ήταν δυνατή η επίλυση του προβλήματος σε " + Convert.ToString(Αuxiliary.TIMEOUT) + " δευτερόλεπτα"); return; } } // while } // solveProblem method