Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Refactored EightPuzzle class #807

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 49 additions & 76 deletions search.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,102 +406,75 @@ def astar_search(problem, h=None):

class EightPuzzle(Problem):

"""The problem of sliding tiles numbered from 1 to 8 on a 3x3 board,
""" The problem of sliding tiles numbered from 1 to 8 on a 3x3 board,
where one of the squares is a blank. A state is represented as a 3x3 list,
where element at index i,j represents the tile number (0 if it's an empty square)."""
where element at index i,j represents the tile number (0 if it's an empty square) """

def __init__(self, initial, goal=None):
if goal:
self.goal = goal
else:
self.goal = [ [0,1,2],
[3,4,5],
[6,7,8] ]
def __init__(self, initial, goal=(1, 2, 3, 4, 5, 6, 7, 8, 0)):
""" Define goal state and initialize a problem """

self.goal = goal
Problem.__init__(self, initial, goal)

def find_blank_square(self, state):
"""Return the index of the blank square in a given state"""
for row in len(state):
for column in len(row):
if state[row][column] == 0:
index_blank_square = (row, column)
return index_blank_square

return state.index(0)

def actions(self, state):
"""Return the actions that can be executed in the given state.
""" Return the actions that can be executed in the given state.
The result would be a list, since there are only four possible actions
in any given state of the environment."""

possible_actions = list()
in any given state of the environment """
possible_actions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
index_blank_square = self.find_blank_square(state)

if index_blank_square(0) == 0:
possible_actions += ['DOWN']
elif index_blank_square(0) == 1:
possible_actions += ['UP', 'DOWN']
elif index_blank_square(0) == 2:
possible_actions += ['UP']

if index_blank_square(1) == 0:
possible_actions += ['RIGHT']
elif index_blank_square(1) == 1:
possible_actions += ['LEFT', 'RIGHT']
elif index_blank_square(1) == 2:
possible_actions += ['LEFT']
if index_blank_square % 3 == 0:
possible_actions.remove('LEFT')
if index_blank_square < 3:
possible_actions.remove('UP')
if index_blank_square % 3 == 2:
possible_actions.remove('RIGHT')
if index_blank_square > 5:
possible_actions.remove('DOWN')

return possible_actions

def result(self, state, action):
"""Given state and action, return a new state that is the result of the action.
Action is assumed to be a valid action in the state."""

blank_square = self.find_blank_square(state)
new_state = [row[:] for row in state]

if action=='UP':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)-1][blank_square(1)]
new_state[blank_square(0)-1][blank_square(1)] = 0
elif action=='LEFT':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)][blank_square(1)-1]
new_state[blank_square(0)][blank_square(1)-1] = 0
elif action=='DOWN':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)+1][blank_square(1)]
new_state[blank_square(0)+1][blank_square(1)] = 0
elif action=='RIGHT':
new_state[blank_square(0)][blank_square(1)] = new_state[blank_square(0)][blank_square(1)+1]
new_state[blank_square(0)][blank_square(1)+1] = 0
else:
print("Invalid Action!")
return new_state
""" Given state and action, return a new state that is the result of the action.
Action is assumed to be a valid action in the state """

# blank is the index of the blank square
blank = self.find_blank_square(state)
new_state = list(state)

delta = {'UP':-3, 'DOWN':3, 'LEFT':-1, 'RIGHT':1}
neighbor = blank + delta[action]
new_state[blank], new_state[neighbor] = new_state[neighbor], new_state[blank]

return tuple(new_state)

def goal_test(self, state):
"""Given a state, return True if state is a goal state or False, otherwise"""
for row in len(state):
for column in len(row):
if state[row][col] != self.goal[row][column]:
return False
return True

def checkSolvability(self, state):
""" Given a state, return True if state is a goal state or False, otherwise """

return state == self.goal

def check_solvability(self, state):
""" Checks if the given state is solvable """

inversion = 0
for i in range(len(state)):
for j in range(i, len(state)):
if (state[i] > state[j] and state[j] != 0):
inversion += 1
check = True
if inversion%2 != 0:
check = False
print(check)
for j in range(i, len(state)):
if (state[i] > state[j] and state[j] != 0):
inversion += 1

return (inversion % 2 == 0)

def h(self, state):
"""Return the heuristic value for a given state. Heuristic function used is
h(n) = number of misplaced tiles."""
num_misplaced_tiles = 0
for row in len(state):
for column in len(row):
if state[row][col] != self.goal[row][column]:
num_misplaced_tiles += 1
return num_misplaced_tiles
def h(self, node):
""" Return the heuristic value for a given state. Default heuristic function used is
h(n) = number of misplaced tiles """

return sum(s != g for (s, g) in zip(node.state, self.goal))

# ______________________________________________________________________________
# Other search algorithms
Expand Down
59 changes: 59 additions & 0 deletions tests/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)
vacumm_world = GraphProblemStochastic('State_1', ['State_7', 'State_8'], vacumm_world)
LRTA_problem = OnlineSearchProblem('State_3', 'State_5', one_dim_state_space)
eight_puzzle = EightPuzzle((1, 2, 3, 4, 5, 7, 8, 6, 0))
eight_puzzle2 = EightPuzzle((1, 0, 6, 8, 7, 5, 4, 2), (0, 1, 2, 3, 4, 5, 6, 7, 8))

def test_find_min_edge():
assert romania_problem.find_min_edge() == 70
Expand Down Expand Up @@ -64,6 +66,63 @@ def test_bidirectional_search():

def test_astar_search():
assert astar_search(romania_problem).solution() == ['Sibiu', 'Rimnicu', 'Pitesti', 'Bucharest']
assert astar_search(eight_puzzle).solution() == ['LEFT', 'LEFT', 'UP', 'RIGHT', 'RIGHT', 'DOWN', 'LEFT', 'UP', 'LEFT', 'DOWN', 'RIGHT', 'RIGHT']
assert astar_search(EightPuzzle((1, 2, 3, 4, 5, 6, 0, 7, 8))).solution() == ['RIGHT', 'RIGHT']


def test_find_blank_square():
assert eight_puzzle.find_blank_square((0, 1, 2, 3, 4, 5, 6, 7, 8)) == 0
assert eight_puzzle.find_blank_square((6, 3, 5, 1, 8, 4, 2, 0, 7)) == 7
assert eight_puzzle.find_blank_square((3, 4, 1, 7, 6, 0, 2, 8, 5)) == 5
assert eight_puzzle.find_blank_square((1, 8, 4, 7, 2, 6, 3, 0, 5)) == 7
assert eight_puzzle.find_blank_square((4, 8, 1, 6, 0, 2, 3, 5, 7)) == 4
assert eight_puzzle.find_blank_square((1, 0, 6, 8, 7, 5, 4, 2, 3)) == 1
assert eight_puzzle.find_blank_square((1, 2, 3, 4, 5, 6, 7, 8, 0)) == 8


def test_actions():
assert eight_puzzle.actions((0, 1, 2, 3, 4, 5, 6, 7, 8)) == ['DOWN', 'RIGHT']
assert eight_puzzle.actions((6, 3, 5, 1, 8, 4, 2, 0, 7)) == ['UP', 'LEFT', 'RIGHT']
assert eight_puzzle.actions((3, 4, 1, 7, 6, 0, 2, 8, 5)) == ['UP', 'DOWN', 'LEFT']
assert eight_puzzle.actions((1, 8, 4, 7, 2, 6, 3, 0, 5)) == ['UP', 'LEFT', 'RIGHT']
assert eight_puzzle.actions((4, 8, 1, 6, 0, 2, 3, 5, 7)) == ['UP', 'DOWN', 'LEFT', 'RIGHT']
assert eight_puzzle.actions((1, 0, 6, 8, 7, 5, 4, 2, 3)) == ['DOWN', 'LEFT', 'RIGHT']
assert eight_puzzle.actions((1, 2, 3, 4, 5, 6, 7, 8, 0)) == ['UP', 'LEFT']


def test_result():
assert eight_puzzle.result((0, 1, 2, 3, 4, 5, 6, 7, 8), 'DOWN') == (3, 1, 2, 0, 4, 5, 6, 7, 8)
assert eight_puzzle.result((6, 3, 5, 1, 8, 4, 2, 0, 7), 'LEFT') == (6, 3, 5, 1, 8, 4, 0, 2, 7)
assert eight_puzzle.result((3, 4, 1, 7, 6, 0, 2, 8, 5), 'UP') == (3, 4, 0, 7, 6, 1, 2, 8, 5)
assert eight_puzzle.result((1, 8, 4, 7, 2, 6, 3, 0, 5), 'RIGHT') == (1, 8, 4, 7, 2, 6, 3, 5, 0)
assert eight_puzzle.result((4, 8, 1, 6, 0, 2, 3, 5, 7), 'LEFT') == (4, 8, 1, 0, 6, 2, 3, 5, 7)
assert eight_puzzle.result((1, 0, 6, 8, 7, 5, 4, 2, 3), 'DOWN') == (1, 7, 6, 8, 0, 5, 4, 2, 3)
assert eight_puzzle.result((1, 2, 3, 4, 5, 6, 7, 8, 0), 'UP') == (1, 2, 3, 4, 5, 0, 7, 8, 6)
assert eight_puzzle.result((4, 8, 1, 6, 0, 2, 3, 5, 7), 'RIGHT') == (4, 8, 1, 6, 2, 0, 3, 5, 7)


def test_goal_test():
assert eight_puzzle.goal_test((0, 1, 2, 3, 4, 5, 6, 7, 8)) == False
assert eight_puzzle.goal_test((6, 3, 5, 1, 8, 4, 2, 0, 7)) == False
assert eight_puzzle.goal_test((3, 4, 1, 7, 6, 0, 2, 8, 5)) == False
assert eight_puzzle.goal_test((1, 2, 3, 4, 5, 6, 7, 8, 0)) == True
assert eight_puzzle2.goal_test((4, 8, 1, 6, 0, 2, 3, 5, 7)) == False
assert eight_puzzle2.goal_test((3, 4, 1, 7, 6, 0, 2, 8, 5)) == False
assert eight_puzzle2.goal_test((1, 2, 3, 4, 5, 6, 7, 8, 0)) == False
assert eight_puzzle2.goal_test((0, 1, 2, 3, 4, 5, 6, 7, 8)) == True


def test_check_solvability():
assert eight_puzzle.check_solvability((0, 1, 2, 3, 4, 5, 6, 7, 8)) == True
assert eight_puzzle.check_solvability((6, 3, 5, 1, 8, 4, 2, 0, 7)) == True
assert eight_puzzle.check_solvability((3, 4, 1, 7, 6, 0, 2, 8, 5)) == True
assert eight_puzzle.check_solvability((1, 8, 4, 7, 2, 6, 3, 0, 5)) == True
assert eight_puzzle.check_solvability((4, 8, 1, 6, 0, 2, 3, 5, 7)) == True
assert eight_puzzle.check_solvability((1, 0, 6, 8, 7, 5, 4, 2, 3)) == True
assert eight_puzzle.check_solvability((1, 2, 3, 4, 5, 6, 7, 8, 0)) == True
assert eight_puzzle.check_solvability((1, 2, 3, 4, 5, 6, 8, 7, 0)) == False
assert eight_puzzle.check_solvability((1, 0, 3, 2, 4, 5, 6, 7, 8)) == False
assert eight_puzzle.check_solvability((7, 0, 2, 8, 5, 3, 6, 4, 1)) == False


def test_recursive_best_first_search():
Expand Down