def AStarSearchBasic(game, cap): ''' Uses the A* algorithm, with the same heuristic function as greedySearchBasic. ''' # For more detailed docstrings, comments, see greedySearch def gameOver(parentState=None): ''' Handles what to do when a game ends. ''' isWon = True if not parentState: print('Game could not be solved :(') toContinue = input('See the best the program could do? (y or n): ') if toContinue is not 'y': return None isWon = False parentState = S.findLowestState(statesToCheck.union\ (statesChecked), S.hFunctionBasic) answerLst = S.constructPath(parentState, parentAndPathDict) totalTime = time() - timeA numOfMoves = len(answerLst) statesEval = counter S.remakeGame(firstState, answerLst) print(f'Number of moves in solution: {numOfMoves}') print(f'Total time: {totalTime} seconds') print(f'States evaluated: {counter}') return answerLst timeA = time() buckets = [set() for i in range(300)] statesToCheck = set() statesChecked = set() parentAndPathDict = {} fScores = {} # states --> fScores = gScores + hScores # hScores are same as those calculated in greedySearch gScores = {} # states --> gScores (number of moves to reach that state) counter = 0 firstState = G.makeImmutableState(game) S.printState(firstState) parentAndPathDict[firstState] = None gScores[firstState] = 0 # since 0 moves to reach first state hVal = S.hFunctionBasic(firstState) fScores[firstState] = hVal # since fScore = gScore + hScore = 0 + hVal buckets[hVal].add(firstState) statesToCheck.add(firstState) while True: try: isStateToCheck = False for i in range(300): if buckets[i]: parentState = buckets[i].pop() isStateToCheck = True break counter += 1 print(counter) if not isStateToCheck: # almost impossible return gameOver() if S.game_is_won(parentState): return gameOver(parentState) if counter == cap: return gameOver() i = counter % 500000 + 160 if i < 300 and counter > 300: for state in buckets[i]: del fScores[state] del gScores[state] del parentAndPathDict[state] statesToCheck.remove(state) buckets[i].clear() statesToCheck.remove(parentState) statesChecked.add(parentState) nodesGenerated = S.findSuccessorsBasic(parentState) for (child, move) in nodesGenerated: if child in statesChecked: continue if child not in statesToCheck: parentAndPathDict[child] = (parentState, move) statesToCheck.add(child) gVal = gScores[parentState] + 1 # Since only 1 extra move gScores[child] = gVal hVal = S.hFunctionBasic(child) fScores[child] = gVal + hVal buckets[gVal + hVal].add(child) except KeyboardInterrupt: print(f'States Evaluated: {counter}') print(f'Time: {time()-timeA} seconds') toQuit = input('Would you like to quit? (y or n): ') if toQuit is not 'y': continue return gameOver()
def greedySearchBasic(game, cap): ''' Another greedySearch algorith using a simpler heuristic function. Only calculates how many cards are in the foundation for a given state, ignoring cycles. ''' # For more detailed docstrings, comments, see greedySearch def gameOver(parentState=None): isWon = True if not parentState: print('Game could not be solved :(') toContinue = input('See the best the program could do? (y or n): ') if toContinue is not 'y': return None isWon = False parentState = S.findLowestState(statesToCheck.union\ (statesChecked), S.hFunctionBasic) answerLst = S.constructPath(parentState, parentAndPathDict) totalTime = time() - timeA numOfMoves = len(answerLst) statesEval = counter S.remakeGame(firstState, answerLst) print(f'Number of moves in solution: {numOfMoves}') print(f'Total time: {totalTime} seconds') print(f'States evaluated: {counter}') return answerLst timeA = time() buckets = [set() for i in range(200)] statesToCheck = set() statesChecked = set() parentAndPathDict = {} # Notice the lack of a cycles dictionary hScores = {} counter = 0 firstState = G.makeImmutableState(game) S.printState(firstState) parentAndPathDict[firstState] = None hVal = S.hFunctionBasic(firstState) # hFunctionBasic only counts # of cards in foundation for a state, # it is much simpler than hFunction used in other algorithms, which has # an additional argument of the set of cycles for a given state. hScores[firstState] = hVal buckets[hVal].add(firstState) statesToCheck.add(firstState) while True: try: isStateToCheck = False for i in range(53): if buckets[i]: parentState = buckets[i].pop() isStateToCheck = True break counter += 1 print(counter) if not isStateToCheck: return gameOver() if S.game_is_won(parentState): return gameOver(parentState) elif counter == cap: return gameOver() i = counter % 500000 + 70 if i < 200 and counter > 200: for state in buckets[i]: del hScores[state] del parentAndPathDict[state] statesToCheck.remove(state) buckets[i].clear() statesToCheck.remove(parentState) statesChecked.add(parentState) nodesGenerated = S.findSuccessorsBasic(parentState) # Again, findSuccessorsBasic is like findSuccessors, but # simpler because there is no cycle information, and therefore # one less argument. Also notice that it returns a list of 2-tuples, # as opposed to 3-tuples. for (child, move) in nodesGenerated: if child in statesChecked: continue if child not in statesToCheck: parentAndPathDict[child] = (parentState, move) statesToCheck.add(child) hVal = S.hFunctionBasic(child) hScores[child] = hVal buckets[hVal].add(child) except KeyboardInterrupt: print(f'States Evaluated: {counter}') print(f'Time: {time()-timeA} seconds') toQuit = input('Would you like to quit? (y or n): ') if toQuit is not 'y': continue return gameOver()