├── 8-puzzle-problem
├── 8-puzzle-problem.py
├── gridworld.py
├── gridworld.pyc
└── n-puzzle-problem.py
├── README.md
├── dijkstra
├── README.md
└── dijkstra.py
├── images
├── a_star_visual.png
├── bfs_visual.png
├── dfs_visual.png
├── dp_visual.png
└── one.png
├── search-algorithms
├── README.md
├── a-star.py
├── breadth-first-search.py
├── depth-first-search.py
├── dynamic-programming.py
├── gridworld.py
└── gridworld.pyc
└── water-jug-problem
├── README.md
└── water-jug-problem-bfs.py
/8-puzzle-problem/8-puzzle-problem.py:
--------------------------------------------------------------------------------
1 | '''
2 | 8 puzzle problem using A Star search-
3 |
4 | initial state is a 3x3 grid:
5 | 2 8 3
6 | 1 6 4
7 | 7 5
8 |
9 | goal state is also a 3x3 grid:
10 | 1 2 3
11 | 8 4
12 | 7 6 5
13 |
14 | There is exactly one blank cell in the grid.
15 | Our aim is to move the cells such that we reach
16 | the goal state in minimum number of steps.
17 |
18 | '''
19 |
20 | from gridworld import GridWorld
21 | from copy import deepcopy
22 | import time
23 |
24 | screen_size = 500
25 | cell_width = 45
26 | cell_height = 45
27 | cell_margin = 5
28 |
29 | grid = [[0 for col in range(3)] for row in range(3)]
30 |
31 | init = deepcopy(grid)
32 | init[0][0] = 2
33 | init[0][1] = 8
34 | init[0][2] = 3
35 | init[1][0] = 1
36 | init[1][1] = 6
37 | init[1][2] = 4
38 | init[2][0] = 7
39 | init[2][2] = 5
40 |
41 | goal = deepcopy(grid)
42 | goal[0][0] = 1
43 | goal[0][1] = 2
44 | goal[0][2] = 3
45 | goal[1][0] = 8
46 | goal[1][2] = 4
47 | goal[2][0] = 7
48 | goal[2][1] = 6
49 | goal[2][2] = 5
50 |
51 | gridworld = GridWorld(screen_size,cell_width, cell_height, cell_margin,init, goal, init)
52 |
53 | delta = [[-1, 0], # go up
54 | [ 0,-1], # go left
55 | [ 1, 0], # go down
56 | [ 0, 1]] # go right
57 |
58 | def calc_heuristic(grid, goal):
59 | count = 0
60 | for i in range(len(grid)):
61 | for j in range(len(grid[0])):
62 | if grid[i][j] != goal[i][j]:
63 | count += 1
64 |
65 | return count
66 |
67 | def is_valid(cell):
68 | if cell[0] >= 0 and cell[0] < len(grid) and cell[1] >= 0 and cell[1] < len(grid[0]):
69 | return True
70 | else:
71 | return False
72 |
73 | def draw_state(state):
74 | for i in range(len(grid)):
75 | for j in range(len(grid[0])):
76 | gridworld.draw_cell([state[i][j], [i, j]]) # [number_on_cell, [x, y]]
77 |
78 | def run_a_star(init, goal, cost=1):
79 | opened = []
80 | visited = []
81 |
82 | f = calc_heuristic(init, goal) # evaluation function
83 | g = 0 # cost so far
84 |
85 | opened.append([f, g, init])
86 |
87 | next = opened.pop()
88 | visited.append(next)
89 | print "next state is :", next
90 | while next[2] != goal:
91 |
92 | g = next[1]
93 | f = next[0]
94 | # explore the neighborhood!
95 | for i in range(len(next[2])):
96 | for j in range(len(next[2][0])):
97 | # go up, left, down, right
98 | for a in range(len(delta)):
99 | x = i + delta[a][0]
100 | y = j + delta[a][1]
101 |
102 | # check if this cell--> x, y is a valid cell
103 | if is_valid([x, y]):
104 | # now check if this new cell is a zero cell
105 | if next[2][x][y] == 0:
106 | next_copy = []
107 | next_copy = deepcopy(next[2])
108 | # swap
109 | next_copy[x][y] = deepcopy(next_copy[i][j])
110 | next_copy[i][j] = 0
111 |
112 | # check if this new state (entire new_copy grid) is in visited
113 | if next_copy not in visited:
114 | g2 = g + cost
115 | f2 = g2 + calc_heuristic(next_copy, goal)
116 | opened.append([f2, g2, next_copy])
117 | visited.append(next_copy)
118 | opened.sort()
119 | opened.reverse()
120 |
121 | if len(opened) > 0:
122 | next = opened.pop()
123 | print "next state is :",next[2]
124 | # draw this state on pygame screen
125 | draw_state(next[2])
126 | gridworld.update()
127 | time.sleep(1)
128 |
129 |
130 | # initial state
131 | draw_state(init)
132 |
133 | gridworld.update()
134 | time.sleep(1)
135 |
136 | run_a_star(init, goal)
137 |
138 |
--------------------------------------------------------------------------------
/8-puzzle-problem/gridworld.py:
--------------------------------------------------------------------------------
1 | import pygame
2 | import time
3 | from copy import deepcopy
4 |
5 | class GridWorld:
6 |
7 | def __init__(self, screen_size,cell_width,
8 | cell_height, cell_margin,init, goal, grid):
9 |
10 | # define colors
11 | self.BLACK = (0, 0, 0)
12 | self.WHITE = (255, 255, 255)
13 | self.GREEN = (0, 255, 0)
14 | self.RED = (255, 0, 0)
15 | self.BLUE = (0, 0, 255)
16 | self.YELLOW = (255, 255, 0)
17 |
18 | # cell dimensions
19 | self.WIDTH = cell_width
20 | self.HEIGHT = cell_height
21 | self.MARGIN = cell_margin
22 | self.color = self.WHITE
23 |
24 | # adjust the grid in the center of screen
25 | # self.adjust_margin = 75
26 |
27 |
28 | pygame.init()
29 | pygame.font.init()
30 |
31 | # set the width and height of the screen (width , height)
32 | self.size = (screen_size, screen_size)
33 | self.screen = pygame.display.set_mode(self.size)
34 |
35 | self.font = pygame.font.SysFont('arial', 20)
36 |
37 | pygame.display.set_caption("Grid world")
38 |
39 | self.clock = pygame.time.Clock()
40 |
41 | self.init = init
42 | self.goal = goal
43 | self.grid = grid
44 |
45 |
46 | self.screen.fill(self.BLACK)
47 |
48 | for row in range(len(grid)):
49 | for col in range(len(grid[0])):
50 | if self.init[row][col] != 0:
51 | self.color = self.RED
52 | else:
53 | self.color = self.WHITE
54 |
55 | pygame.draw.rect(self.screen,
56 | self.color,
57 | [(self.MARGIN + self.WIDTH )*col+self.MARGIN,
58 | (self.MARGIN + self.HEIGHT )*row+self.MARGIN,
59 | self.WIDTH,
60 | self.HEIGHT])
61 |
62 | def text_objects(self, text, font):
63 | textSurface = font.render(text, True, self.BLACK)
64 | return textSurface, textSurface.get_rect()
65 |
66 | def draw_cell(self, cell):
67 |
68 | row = cell[1][0]
69 | column = cell[1][1]
70 | number = cell[0]
71 | if number != 0:
72 | rect = pygame.draw.rect(self.screen,
73 | self.RED,
74 | [(self.MARGIN + self.WIDTH)*column+self.MARGIN,
75 | (self.MARGIN + self.HEIGHT)*row+self.MARGIN,
76 | self.WIDTH,
77 | self.HEIGHT])
78 | TextSurf, TextRect = self.text_objects(str(number), self.font)
79 | TextRect.center = ((self.MARGIN + self.WIDTH)*column + 4*self.MARGIN,
80 | (self.MARGIN + self.HEIGHT)*row + 4*self.MARGIN)
81 | self.screen.blit(TextSurf, TextRect)
82 | else:
83 | rect = pygame.draw.rect(self.screen,
84 | self.WHITE,
85 | [(self.MARGIN + self.WIDTH)*column+self.MARGIN,
86 | (self.MARGIN + self.HEIGHT)*row+self.MARGIN,
87 | self.WIDTH,
88 | self.HEIGHT])
89 |
90 | def update(self):
91 | pygame.display.update()
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/8-puzzle-problem/gridworld.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/8-puzzle-problem/gridworld.pyc
--------------------------------------------------------------------------------
/8-puzzle-problem/n-puzzle-problem.py:
--------------------------------------------------------------------------------
1 | '''
2 | N puzzle problem using A Star search-
3 |
4 | initial state is a NxN grid.
5 |
6 | goal state is also a NxN grid.
7 |
8 | There is exactly one blank cell in the grid.
9 | Our aim is to move the cells such that we reach
10 | the goal state in minimum number of steps.
11 |
12 | '''
13 |
14 | from gridworld import GridWorld
15 | from copy import deepcopy
16 | import time
17 | import random
18 | import pygame
19 |
20 |
21 | screen_size = 500
22 | cell_width = 45
23 | cell_height = 45
24 | cell_margin = 5
25 |
26 | grid = [[0 for col in range(4)] for row in range(4)]
27 |
28 | # add numbers from 0 to 99 to a list and then shuffle it
29 | numbers_list = [i for i in range(len(grid)*len(grid[0]))]
30 |
31 | random.shuffle(numbers_list)
32 |
33 | init = deepcopy(grid)
34 | k = 0
35 | for i in range(len(grid)):
36 | for j in range(len(grid[0])):
37 | print k
38 | init[i][j] = numbers_list[k]
39 | k += 1
40 |
41 | # shuffle again to generate goal state
42 | random.shuffle(numbers_list)
43 |
44 | goal = deepcopy(grid)
45 | k = 0
46 | for i in range(len(grid)):
47 | for j in range(len(grid[0])):
48 | goal[i][j] = numbers_list[k]
49 | k += 1
50 |
51 | gridworld = GridWorld(screen_size,cell_width, cell_height, cell_margin,init, goal, init)
52 |
53 | delta = [[-1, 0], # go up
54 | [ 0,-1], # go left
55 | [ 1, 0], # go down
56 | [ 0, 1]] # go right
57 |
58 | def calc_heuristic(grid, goal):
59 | count = 0
60 | for i in range(len(grid)):
61 | for j in range(len(grid[0])):
62 | if grid[i][j] != goal[i][j]:
63 | count += 1
64 |
65 | return count
66 |
67 | def is_valid(cell):
68 | if cell[0] >= 0 and cell[0] < len(grid) and cell[1] >= 0 and cell[1] < len(grid[0]):
69 | return True
70 | else:
71 | return False
72 |
73 | def draw_state(state):
74 | for i in range(len(grid)):
75 | for j in range(len(grid[0])):
76 | gridworld.draw_cell([state[i][j], [i, j]]) # [number_on_cell, [x, y]]
77 |
78 |
79 | def run_a_star(init, goal,cost=1):
80 | opened = []
81 | visited = []
82 |
83 | f = calc_heuristic(init, goal) # evaluation function
84 | g = 0 # cost so far
85 |
86 | opened.append([f, g, init])
87 |
88 | next = opened.pop()
89 | visited.append(next)
90 | print "next state is :", next
91 | while next[2] != goal:
92 |
93 | g = next[1]
94 | f = next[0]
95 | # explore the neighborhood!
96 | for i in range(len(next[2])):
97 | for j in range(len(next[2][0])):
98 | # go up, left, down, right
99 | for a in range(len(delta)):
100 | x = i + delta[a][0]
101 | y = j + delta[a][1]
102 |
103 | # check if this cell--> x, y is a valid cell
104 | if is_valid([x, y]):
105 | # now check if this new cell is a zero cell
106 | if next[2][x][y] == 0:
107 | next_copy = []
108 | next_copy = deepcopy(next[2])
109 | # swap
110 | next_copy[x][y] = (next_copy[i][j])
111 | next_copy[i][j] = 0
112 |
113 | # check if this new state (entire new_copy grid) is in visited
114 | if next_copy not in visited:
115 | g2 = g + cost
116 | f2 = g2 + calc_heuristic(next_copy, goal)
117 | opened.append([f2, g2, next_copy])
118 | visited.append(next_copy)
119 | opened.sort()
120 | opened.reverse()
121 |
122 | if len(opened) > 0:
123 | next = opened.pop()
124 | print "next state is :",next[2]
125 | # draw this state on pygame screen
126 | draw_state(next[2])
127 | gridworld.update()
128 | time.sleep(3)
129 |
130 | # initial state
131 | draw_state(init)
132 |
133 | gridworld.update()
134 |
135 | run_a_star(init, goal)
136 |
137 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cce-ai-2017
2 | CCE-AI Class codes
3 |
--------------------------------------------------------------------------------
/dijkstra/README.md:
--------------------------------------------------------------------------------
1 | ## Shortest distance path using Dijkstra's Algorithm
2 |
3 | 
4 |
5 | ### Algorithm
6 |
7 | * Set the costs of all the nodes to a large number eg. 10000.
8 | * Also initialize a `cost_matrix` with 10000 as the costs.
9 | * Start at the source node.Call it `parent_node`.
10 | * Assign a 0 cost to this node.
11 | * Update `cost_matrix`
12 | * Consider this node as visited.
13 | * Find the child nodes directly connected to the `parent_node` node.
14 | * Find the cost of each child node as follows -
15 |
16 | ```py
17 | if Cost(parent_node) + weight < Cost(child_node):
18 | # update
19 | Cost(child_node) = Cost(parent_node) + weight
20 | else:
21 | Cost(child_node)
22 | ```
23 |
24 | * Also update the `cost_matrix` with the new cost values of the child nodes.
25 | * Find the child node with the minimum cost and update the `parent_node` as this node.
26 | * Continue like this (steps 6 to 10) till all the nodes are visited.
27 | * *Backtracking* - Start from the last row and column of the `cost_matrix` and add it to the path.
28 | * Then move to the row above, same column.If the cost changes, add the corresponding *visited* node
29 | in the path.If the entry is 10000, change the column to `column -1`.
30 | * Continue till the source node is reached.
31 |
32 |
--------------------------------------------------------------------------------
/dijkstra/dijkstra.py:
--------------------------------------------------------------------------------
1 | '''
2 | Dijkstra's Algorithm for finding the shortest distance.
3 | '''
4 | import copy
5 |
6 | # backtracking
7 | def findpath(visited,matrix, size, end):
8 | path = [end]
9 | # start from the last row
10 | j = size-1
11 | for i in range(size-1,0, -1):
12 | # compare the cost of the node just above the current node
13 | # if there is a change, append the corresponding visited node
14 | # to the path
15 | if (matrix[i][j] != matrix[i-1][j]):
16 | path.append(visited[i-1])
17 | # if the cost of the node just above the current node is 10000 (infinity),
18 | # move to the left column for the next iteration
19 | if matrix[i-1][j] == 10000:
20 | j -= 1
21 | return path
22 |
23 | def return_index(unseen_nodes,letter):
24 | i = 0
25 | for key in unseen_nodes:
26 | if key == letter:
27 | return i
28 | i += 1
29 |
30 | def return_index_value(letter):
31 | return ord(letter) - 65
32 |
33 | def return_letter(index):
34 | return chr(int_index+65)
35 |
36 | #graph, start, destination and number of points
37 | def dijkstra(graph, start, end, size):
38 | print "Original graph :",graph
39 | # cost matrix ; set all the costs to a large number
40 | # currently has just one row
41 | matrix = [[10000 for x in range(size)]]
42 | matrix_row_counter = 0
43 | # save start node
44 | start_temp = start
45 | # this dictionary will contain key : cost pair
46 | graph_temp = {}
47 |
48 | # initially all the nodes are unseen
49 | # the node keys will be popped from unseen_nodes
50 | # and added in visited_list
51 | unseen_nodes = graph.keys()
52 | visited = []
53 |
54 | # all nodes are at really long distances initially
55 | # so the node values are all set to large number
56 | for node in unseen_nodes:
57 | graph_temp.update({node : 10000})
58 |
59 | # start at 'start' node and assign 0 to it
60 | graph_temp.update({start : 0})
61 |
62 | # first row first column in the cost matrix set to 0
63 | # eg. [[0, 10000, 10000, 10000]]
64 | matrix[0][0] = 0
65 | # add the start node to the visited list
66 | visited.append(start)
67 | # remove the source node from the unseen_nodes
68 | unseen_nodes.pop(return_index(unseen_nodes,start))
69 |
70 | while len(unseen_nodes) > 0:
71 |
72 | # a temporary row copies the entries from the previous row of
73 | # the cost matrix
74 | temp_row = copy.copy(matrix[matrix_row_counter])
75 |
76 | # child_nodes directly connected to the current node
77 | # are temporarily added in keys_temp
78 | keys_temp = []
79 | for keys, values in zip(graph[start].keys(), graph[start].values()):
80 | # if child_node is not visited, then only consider
81 | if keys not in visited:
82 | # check if source value + path weight < current node value or cost
83 | if graph_temp[start] + values < graph_temp[keys]:
84 | # update
85 | graph_temp.update({keys : graph_temp[start] + values})
86 | # add the child_nodes
87 | keys_temp.append(keys)
88 | # also update the temp_row with the update values
89 | int_index = return_index_value(keys)
90 | temp_row[int_index] = graph_temp[keys]
91 |
92 | # assume that the first child has smallest cost
93 | min_key = keys_temp[0]
94 |
95 | # go through each child node to see which has smaller cost
96 | # visit the one with minimum cost
97 | for keys in keys_temp:
98 | if graph_temp[keys] < graph_temp[min_key]:
99 | min_key = keys
100 |
101 | visited.append(min_key)
102 |
103 | # add the temp_row to the cost matrix
104 | matrix.append(temp_row)
105 | matrix_row_counter += 1
106 |
107 | # remove the minimum cost node from unseen_nodes
108 | unseen_nodes.pop(return_index(unseen_nodes,min_key))
109 |
110 | # set start to the minimum cost node
111 | start = min_key
112 |
113 | print "Shortest path is :",findpath(visited,matrix, size, end)
114 |
115 | # example graphs
116 | '''
117 | graph = {
118 | 'A' : {'B': 5, 'C': 10},
119 | 'B' : {'A': 5, 'C': 4, 'D': 11},
120 | 'C' : {'A': 10, 'B': 4, 'D': 5},
121 | 'D' : {'B': 11, 'C': 5}
122 | }
123 |
124 | '''
125 |
126 | '''
127 | graph = {
128 | 'A' : {'B': 4, 'D': 8},
129 | 'B' : {'A': 4, 'C': 3},
130 | 'C' : {'B': 3, 'D': 4},
131 | 'D' : {'C': 4, 'A': 8, 'E': 7},
132 | 'E' : {'D': 7}
133 | }
134 | '''
135 |
136 | graph = {
137 | 'A' : {'B': 10, 'C': 5},
138 | 'B' : {'A': 10, 'C': 8, 'E': 6, 'D': 12},
139 | 'C' : {'A': 5, 'B': 8, 'E': 12},
140 | 'D' : {'B': 12, 'E': 5, 'F': 4},
141 | 'E' : {'C': 12, 'B': 6, 'D': 5, 'F': 6},
142 | 'F' : {'D': 4, 'E': 6}
143 | }
144 |
145 | dijkstra(graph, 'A', 'F',6)
146 |
147 |
148 |
149 |
--------------------------------------------------------------------------------
/images/a_star_visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/images/a_star_visual.png
--------------------------------------------------------------------------------
/images/bfs_visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/images/bfs_visual.png
--------------------------------------------------------------------------------
/images/dfs_visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/images/dfs_visual.png
--------------------------------------------------------------------------------
/images/dp_visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/images/dp_visual.png
--------------------------------------------------------------------------------
/images/one.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/images/one.png
--------------------------------------------------------------------------------
/search-algorithms/README.md:
--------------------------------------------------------------------------------
1 | # Search algorithms
2 |
3 | ## Breadth First Search Algorithm
4 |
5 | 
6 |
7 | ## Depth First Search Algorithm
8 |
9 | 
10 |
11 | ## A-star Search Algorithm
12 |
13 | 
14 |
15 | ## Dynamic programming search
16 |
17 | 
18 |
--------------------------------------------------------------------------------
/search-algorithms/a-star.py:
--------------------------------------------------------------------------------
1 | # A visual demonstration of A* search algorithm
2 |
3 | from gridworld import GridWorld
4 | import time
5 | from math import *
6 |
7 | # build grid structure
8 | grid = [[0 for col in range(10)] for row in range(10)]
9 | grid[0][1] = 1 # obstacle
10 | # grid[1][1] = 1 # obstacle
11 | # grid[2][1] = 1 # obstacle
12 | # grid[3][1] = 1 # obstacle
13 | # grid[4][4] = 1 # obstacle
14 | # grid[5][4] = 1 # obstacle
15 | # grid[5][4] = 1 # obstacle
16 | # grid[6][4] = 1
17 | # grid[7][4] = 1
18 | # grid[8][4] = 1
19 | # grid[9][4] = 1
20 |
21 | init = [0, 0]
22 | goal = [9, 9]
23 |
24 | # build heuristics grid
25 | heuristics = [[0 for col in range(len(grid[0]))] for row in range(len(grid))]
26 | k = len(grid[0]) - 1
27 | for i in range(len(grid)-1, -1, -1):
28 | num = (len(grid[0])-1) - k
29 | for j in range(len(grid[0])-1, -1, -1):
30 | heuristics[i][j] = num
31 | num += 1
32 | k -= 1
33 |
34 | screen_size = 500
35 | cell_width = 45
36 | cell_height = 45
37 | cell_margin = 5
38 |
39 | gridworld = GridWorld(screen_size,cell_width, cell_height, cell_margin,init, goal, grid)
40 |
41 | def check_valid(node, grid):
42 | if node[0] >= 0 and node[0] < len(grid) and node[1] >= 0 and node[1] < len(grid[0]) and (grid[node[0]][node[1]] == 0):
43 | return True
44 | else:
45 | return False
46 |
47 | def heuristic(a, b):
48 | # return (abs(a[0] - b[0]) + abs(a[1] - b[1]))
49 | return sqrt((a[0] - b[0])**2 + (a[1]-b[1])**2)
50 |
51 | def run_a_star(grid, heuristics, init, goal, cost):
52 | delta = [[ 0, -1], # go left
53 | [ 1, 0 ], # go down
54 | [ 0, 1], # go right
55 | [-1, 0 ]] # go up
56 |
57 | delta_name = ['^', '<', 'v', '>']
58 | action = [[-1 for row in range(len(grid[0]))] for col in range(len(grid))]
59 | policy = [[' ' for row in range(len(grid[0]))] for col in range(len(grid))]
60 | expanded = [[-1 for row in range(len(grid[0]))] for col in range(len(grid))]
61 |
62 | visited = []
63 | opened = []
64 |
65 | # [f, g, [x, y]]
66 | # f = g + heuristics[x][y]
67 | # opened.append([0+heuristics[init[0]][init[1]], 0, init[0], init[1]])
68 | opened.append([heuristic(goal, init), 0, init[0], init[1]])
69 |
70 | visited.append([init[0], init[1]])
71 | next = opened.pop()
72 | count = 0
73 |
74 | while [next[2],next[3]] != goal:
75 |
76 | if len(opened) > 0:
77 | opened.sort()
78 | print opened
79 | opened.reverse()
80 | next = opened.pop()
81 |
82 | x = next[2]
83 | y = next[3]
84 | g = next[1]
85 | f = next[0]
86 | gridworld.draw_cell([[f, [x, y]]])
87 | gridworld.show()
88 | # time.sleep(0.5)
89 | expanded[next[2]][next[3]] = count
90 | count += 1
91 | for a in range(len(delta)):
92 | x2 = x + delta[a][0]
93 | y2 = y + delta[a][1]
94 |
95 | if check_valid([x2, y2], grid):
96 | g2 = g + cost
97 | if [x2, y2] not in visited:
98 | #f = g2 + heuristics[x2][y2]
99 | f = g2 + heuristic(goal, [x2, y2])
100 | opened.append([f,g2,x2, y2])
101 | visited.append([x2, y2])
102 | action[x2][y2] = a
103 |
104 | print expanded
105 | # policy search
106 | x = goal[0]
107 | y = goal[1]
108 | policy[x][y] = '*'
109 | path = []
110 | path.append([x, y])
111 | while([x, y] != init):
112 | x1 = x - delta[action[x][y]][0]
113 | y1 = y - delta[action[x][y]][1]
114 | policy[x1][y1] = delta_name[action[x][y]]
115 | x = x1
116 | y = y1
117 | path.append([x, y])
118 | print policy
119 | path.reverse()
120 | print path
121 | smooth_path = gridworld.smooth_path(path)
122 | gridworld.draw_path(smooth_path)
123 | gridworld.show()
124 |
125 | run_a_star(grid, heuristics, init, goal, cost=1)
126 |
127 | while True:
128 | pass
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/search-algorithms/breadth-first-search.py:
--------------------------------------------------------------------------------
1 | '''
2 | A visual demonstration of Breadth First Search Algorithm
3 | using Pygame.
4 | '''
5 | import time
6 | from copy import deepcopy
7 | from gridworld import GridWorld
8 |
9 | grid = [[0 for col in range(10)] for row in range(10)]
10 | init = [0, 0]
11 | goal = [9, 9]
12 | cell_width = 45
13 | cell_height = 45
14 | screen_size = 500
15 | cell_margin = 5
16 |
17 | grid_world = GridWorld(screen_size,cell_width,cell_height, cell_margin, init, goal, grid)
18 |
19 | def check_valid(node):
20 | if node[0] >= 0 and node[0] < len(grid) and node[1] >= 0 and node[1] < len(grid[0]) and (grid[node[0]][node[1]] == 0 or grid[node[0]][node[1]] == 10):
21 | return True
22 | else:
23 | return False
24 |
25 | def run_bfs(init, goal, grid,cost, find_path):
26 | delta = [[-1, 0 ], # go up
27 | [ 0, -1], # go left
28 | [ 0, 1 ], # go down
29 | [ 1, 0]] # go right
30 | delta_name = ['^', '<', 'v', '>']
31 | action = [[-1 for row in range(len(grid[0]))] for col in range(len(grid))]
32 | policy = [[' ' for row in range(len(grid[0]))] for col in range(len(grid))]
33 |
34 | next = None
35 | visited = []
36 | opened = []
37 | opened.append([0, init])
38 | visited.append(init)
39 | opened.sort()
40 | opened.reverse()
41 | next = opened.pop()
42 | came_from = []
43 | while next[1]!= goal:
44 | temp = []
45 | # print "expanding node :",next[1]
46 | # print "neighboring nodes: "
47 | for d in range(len(delta)):
48 | x = next[1][0] + delta[d][0]
49 | y = next[1][1] + delta[d][1]
50 |
51 | if check_valid([x, y]):
52 | if [x, y] not in visited:
53 | opened.append([next[0]+cost, [x, y]])
54 | visited.append([x, y])
55 | temp.append([next[0]+cost, [x, y]])
56 | action[x][y] = d
57 |
58 | # print temp
59 | grid_world.draw_cell(temp)
60 | grid_world.show()
61 | time.sleep(0.1)
62 | if(len(opened)>0):
63 | next = opened.pop(0)
64 |
65 | # policy search
66 | x = goal[0]
67 | y = goal[1]
68 | policy[x][y] = '*'
69 | path = []
70 | path.append([x, y])
71 | while([x, y] != init):
72 | x1 = x - delta[action[x][y]][0]
73 | y1 = y - delta[action[x][y]][1]
74 | policy[x1][y1] = delta_name[action[x][y]]
75 | x = x1
76 | y = y1
77 | path.append([x, y])
78 | print policy
79 | path.reverse()
80 |
81 | if find_path:
82 | # newpath = deepcopy(path)
83 | smooth_path = grid_world.smooth_path(path)
84 | grid_world.draw_path(smooth_path)
85 | grid_world.show()
86 |
87 |
88 | run_bfs(init, goal, grid, cost=1, find_path=True)
89 |
90 |
--------------------------------------------------------------------------------
/search-algorithms/depth-first-search.py:
--------------------------------------------------------------------------------
1 | '''
2 | A visual demonstration of Depth First Search Algorithm
3 | using Pygame.
4 | '''
5 | import time
6 | from copy import deepcopy
7 | from gridworld import GridWorld
8 |
9 | grid = [[0 for col in range(10)] for row in range(10)]
10 | grid[0][5] = 1 # obstacle
11 | grid[1][5] = 1 # obstacle
12 | grid[2][5] = 1 # obstacle
13 | grid[3][5] = 1 # obstacle
14 |
15 | init = [0, 0]
16 | goal = [4, 9]
17 | cell_width = 45
18 | cell_height = 45
19 | screen_size = 500
20 | cell_margin = 5
21 |
22 | grid_world = GridWorld(screen_size,cell_width,cell_height, cell_margin, init, goal, grid)
23 |
24 | def check_valid(node):
25 | if node[0] >= 0 and node[0] < len(grid) and node[1] >= 0 and node[1] < len(grid[0]) and (grid[node[0]][node[1]] == 0 or grid[node[0]][node[1]] == 10):
26 | return True
27 | else:
28 | return False
29 |
30 | def run_dfs(init, goal, grid,cost, find_path):
31 | delta = [[-1, 0 ], # go up
32 | [ 0, -1], # go left
33 | [ 0, 1 ], # go down
34 | [ 1, 0]] # go right
35 | delta_name = ['^', '<', 'v', '>']
36 | action = [[-1 for row in range(len(grid[0]))] for col in range(len(grid))]
37 | policy = [[' ' for row in range(len(grid[0]))] for col in range(len(grid))]
38 |
39 | next = None
40 | visited = []
41 | opened = []
42 | opened.append([0, init])
43 | visited.append(init)
44 | opened.sort()
45 | opened.reverse()
46 | next = opened.pop()
47 | came_from = []
48 | while next[1]!= goal:
49 | grid_world.draw_cell([[next[0], next[1]]])
50 | grid_world.show()
51 | time.sleep(0.1)
52 | temp = []
53 | # print "expanding node :",next[1]
54 | # print "neighboring nodes: "
55 | for d in range(len(delta)):
56 | x = next[1][0] + delta[d][0]
57 | y = next[1][1] + delta[d][1]
58 |
59 | if check_valid([x, y]):
60 | if [x, y] not in visited:
61 | opened.append([next[0]+cost, [x, y]])
62 | visited.append([x, y])
63 | temp.append([next[0]+cost, [x, y]])
64 | action[x][y] = d
65 |
66 | # print temp
67 | # grid_world.draw_cell(temp)
68 | # grid_world.show()
69 | # time.sleep(0.1)
70 | if(len(opened)>0):
71 | next = opened.pop()
72 |
73 | # policy search
74 | x = goal[0]
75 | y = goal[1]
76 | policy[x][y] = '*'
77 | path = []
78 | path.append([x, y])
79 | while([x, y] != init):
80 | x1 = x - delta[action[x][y]][0]
81 | y1 = y - delta[action[x][y]][1]
82 | policy[x1][y1] = delta_name[action[x][y]]
83 | x = x1
84 | y = y1
85 | path.append([x, y])
86 | print policy
87 | path.reverse()
88 |
89 | if find_path:
90 | # newpath = deepcopy(path)
91 | smooth_path = grid_world.smooth_path(path)
92 | grid_world.draw_path(smooth_path)
93 | grid_world.show()
94 |
95 |
96 | run_dfs(init, goal, grid, cost=1, find_path=True)
97 |
98 | while True:
99 | pass
100 |
--------------------------------------------------------------------------------
/search-algorithms/dynamic-programming.py:
--------------------------------------------------------------------------------
1 | from gridworld import GridWorld
2 | import time
3 |
4 | def compute_value(grid,value,policy, goal,cost):
5 | action = [[-1 for col in range(len(grid[0]))] for row in range(len(grid))]
6 | change = True
7 | while change:
8 | change = False
9 |
10 | for x in range(len(grid)):
11 | for y in range(len(grid[0])):
12 |
13 | if goal[0] == x and goal[1] == y:
14 | if value[x][y] > 0:
15 | value[x][y] = 0
16 | change = True
17 |
18 | elif grid[x][y] == 0:
19 | temp = []
20 | for a in range(len(delta)):
21 | x2 = x + delta[a][0]
22 | y2 = y + delta[a][1]
23 |
24 | if x2 >= 0 and x2 < len(grid) and y2 >= 0 and y2 < len(grid[0]) and grid[x2][y2]==0:
25 | v2 = value[x2][y2] + cost_step
26 |
27 | if v2 < value[x][y]:
28 | change = True
29 | value[x][y] = v2
30 | temp.append([str(v2)+" "+str(delta_name[a])+"", [x, y]])
31 | gridworld.draw_cell(temp)
32 | gridworld.show()
33 | time.sleep(0.5)
34 | policy[x][y] = delta_name[a]
35 |
36 | return policy
37 |
38 | grid = [[0, 0, 1, 0, 0, 0],
39 | [0, 0, 1, 0, 0, 0],
40 | [0, 0, 1, 0, 1, 0],
41 | [0, 0, 1, 0, 1, 0],
42 | [0, 0, 0, 0, 1, 0]]
43 | value = [[99 for col in range(len(grid[0]))] for row in range(len(grid))]
44 | policy = [[' ' for col in range(len(grid[0]))] for row in range(len(grid))]
45 | policy[len(grid)-1][len(grid[0]) - 1] = '*'
46 | goal = [len(grid)-1, len(grid[0])-1]
47 | cost = 1 # the cost associated with moving from a cell to an adjacent one
48 |
49 | init = [0, 0]
50 |
51 | delta = [[-1, 0 ], # go up
52 | [ 0, -1], # go left
53 | [ 1, 0 ], # go down
54 | [ 0, 1 ]] # go right
55 |
56 | delta_name = ['^', '<', 'v', '>']
57 |
58 | cost_step = 1
59 |
60 | screen_size = 500
61 | cell_width = 45
62 | cell_height = 45
63 | cell_margin = 5
64 |
65 | gridworld = GridWorld(screen_size,cell_width, cell_height, cell_margin,init, goal, grid)
66 |
67 | print compute_value(grid,value,policy, goal, cost=1)
68 | while True:
69 | pass
70 |
--------------------------------------------------------------------------------
/search-algorithms/gridworld.py:
--------------------------------------------------------------------------------
1 | import pygame
2 | import time
3 | from copy import deepcopy
4 |
5 | class GridWorld:
6 |
7 | def __init__(self, screen_size,cell_width,
8 | cell_height, cell_margin,init, goal, grid):
9 |
10 | # define colors
11 | self.BLACK = (0, 0, 0)
12 | self.WHITE = (255, 255, 255)
13 | self.GREEN = (0, 255, 0)
14 | self.RED = (255, 0, 0)
15 | self.BLUE = (0, 0, 255)
16 | self.YELLOW = (255, 255, 0)
17 |
18 | # cell dimensions
19 | self.WIDTH = cell_width
20 | self.HEIGHT = cell_height
21 | self.MARGIN = cell_margin
22 | self.color = self.WHITE
23 |
24 |
25 | pygame.init()
26 | pygame.font.init()
27 |
28 | # set the width and height of the screen (width , height)
29 | self.size = (screen_size, screen_size)
30 | self.screen = pygame.display.set_mode(self.size)
31 |
32 | self.font = pygame.font.SysFont('arial', 20)
33 |
34 | pygame.display.set_caption("Grid world")
35 |
36 | self.clock = pygame.time.Clock()
37 |
38 | self.init = init
39 | self.goal = goal
40 | self.grid = grid
41 |
42 |
43 | self.screen.fill(self.BLACK)
44 |
45 | for row in range(len(grid)):
46 | for col in range(len(grid[0])):
47 | if [row, col] == self.init:
48 | self.color = self.GREEN
49 | elif [row, col] == self.goal:
50 | self.color = self.RED
51 | elif grid[row][col] == 1:
52 | self.color = self.BLACK
53 | else:
54 | self.color = self.WHITE
55 | pygame.draw.rect(self.screen,
56 | self.color,
57 | [(self.MARGIN + self.WIDTH)*col+self.MARGIN,
58 | (self.MARGIN + self.HEIGHT)*row+self.MARGIN,
59 | self.WIDTH,
60 | self.HEIGHT])
61 |
62 | def text_objects(self, text, font):
63 | textSurface = font.render(text, True, self.BLACK)
64 | return textSurface, textSurface.get_rect()
65 |
66 | def draw_cell(self, nodes):
67 | for node in nodes:
68 | row = node[1][0]
69 | column = node[1][1]
70 | value = node[0]
71 | rect = pygame.draw.rect(self.screen,
72 | self.BLUE,
73 | [(self.MARGIN + self.WIDTH)*column+self.MARGIN,
74 | (self.MARGIN + self.HEIGHT)*row+self.MARGIN,
75 | self.WIDTH,
76 | self.HEIGHT])
77 | TextSurf, TextRect = self.text_objects(str(value), self.font)
78 | TextRect.center = ((self.MARGIN + self.WIDTH)*column + 4*self.MARGIN,
79 | (self.MARGIN + self.HEIGHT)*row + 4*self.MARGIN)
80 | self.screen.blit(TextSurf, TextRect)
81 |
82 |
83 | def draw_path(self, path):
84 | origin = [0+1*self.MARGIN+22.5,0+1*self.MARGIN+22.5]
85 | col = self.MARGIN + self.WIDTH
86 | row = self.MARGIN + self.HEIGHT
87 | pygame.draw.lines(self.screen, self.GREEN, False, [(origin[0]+col*i[1], origin[1]+row*i[0]) for i in path], 4)
88 |
89 | # smoothen the path
90 | def smooth_path(self,path,weight_data = 0.5, weight_smooth = 0.1, tolerance = 0.000001):
91 | #newpath = return_path
92 | newpath = deepcopy(path)
93 | change = tolerance
94 | while change >= tolerance:
95 | change = 0
96 | for i in range(1, len(path) - 1):
97 | for j in range(len(path[0])):
98 | d1 = weight_data*(path[i][j] - newpath[i][j])
99 | d2 = weight_smooth*(newpath[i-1][j] + newpath[i+1][j] - 2*newpath[i][j])
100 | change += abs(d1 + d2)
101 | newpath[i][j] += d1 + d2
102 |
103 | return newpath
104 |
105 | def show(self):
106 | self.clock.tick(500)
107 | pygame.display.flip()
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/search-algorithms/gridworld.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ioarun/cce-ai-2017/ec0b4991d9688b99138edd550cf3d8e9fa26145b/search-algorithms/gridworld.pyc
--------------------------------------------------------------------------------
/water-jug-problem/README.md:
--------------------------------------------------------------------------------
1 | # Water-Jug problem using BFS
2 | ## Production Rules:
3 | * (x, y) -> (a, y) if x < a
4 | * (x, y) -> (x, b) if y < b
5 | * (x, y) -> (0, y) if x > 0
6 | * (x, y) -> (x, 0) if y > 0
7 | * (x, y) -> (min(x+y, a), max(0, x+y - a)) if y > 0
8 | * (x, y) -> (max(0, x+y - b), min(x+y, b)) if x > 0
9 |
10 | These production rules are used to find the neighbouring states from the current states.
11 |
12 | The Algorithm goes like this:
13 |
14 | 0. Create an empty `path` list.
15 | 1. Add start state to the `front` queue.
16 | 2. Mark it visited by adding it in `visited` list.
17 | 3. While `front` is not empty, follow the steps(4 - 6) below.
18 | 4. Pop out a state from `front` and call it `current`.Add `current` to `path` list.
19 | 5. Expand all it's neighbours following the production rules.
20 | 6. If the neighbours are not in `visited` , then add them to `visited` list and also add them to the `front` queue.
21 | 7. return `path`.
22 |
23 |
--------------------------------------------------------------------------------
/water-jug-problem/water-jug-problem-bfs.py:
--------------------------------------------------------------------------------
1 | '''
2 | Water-Jug solution using Breadth First Search Algorithm
3 | '''
4 |
5 | print "Solution for water jug problem"
6 | x_capacity = input("Enter Jug 1 capacity:")
7 | y_capacity = input("Enter Jug 2 capacity:")
8 | end = input("Enter target volume:")
9 |
10 | def bfs(start, end, x_capacity, y_capacity):
11 | path = []
12 | front = []
13 | front.append(start)
14 | visited = []
15 | #visited.append(start)
16 | while(not (not front)):
17 | current = front.pop()
18 | x = current[0]
19 | y = current[1]
20 | path.append(current)
21 | if x == end or y == end:
22 | print "Found!"
23 | return path
24 | # rule 1
25 | if current[0] < x_capacity and ([x_capacity, current[1]] not in visited):
26 | front.append([x_capacity, current[1]])
27 | visited.append([x_capacity, current[1]])
28 |
29 | # rule 2
30 | if current[1] < y_capacity and ([current[0], y_capacity] not in visited):
31 | front.append([current[0], y_capacity])
32 | visited.append([current[0], y_capacity])
33 |
34 | # rule 3
35 | if current[0] > x_capacity and ([0, current[1]] not in visited):
36 | front.append([0, current[1]])
37 | visited.append([0, current[1]])
38 |
39 | # rule 4
40 | if current[1] > y_capacity and ([x_capacity, 0] not in visited):
41 | front.append([x_capacity, 0])
42 | visited.append([x_capacity, 0])
43 |
44 | # rule 5
45 | #(x, y) -> (min(x + y, x_capacity), max(0, x + y - x_capacity)) if y > 0
46 | if current[1] > 0 and ([min(x + y, x_capacity), max(0, x + y - x_capacity)] not in visited):
47 | front.append([min(x + y, x_capacity), max(0, x + y - x_capacity)])
48 | visited.append([min(x + y, x_capacity), max(0, x + y - x_capacity)])
49 |
50 | # rule 6
51 | # (x, y) -> (max(0, x + y - y_capacity), min(x + y, y_capacity)) if x > 0
52 | if current[0] > 0 and ([max(0, x + y - y_capacity), min(x + y, y_capacity)] not in visited):
53 | front.append([max(0, x + y - y_capacity), min(x + y, y_capacity)])
54 | visited.append([max(0, x + y - y_capacity), min(x + y, y_capacity)])
55 |
56 | return "Not found"
57 |
58 | def gcd(a, b):
59 | if a == 0:
60 | return b
61 | return gcd(b%a, a)
62 |
63 | # start state: x = 0 , y = 0
64 | start = [0, 0]
65 | #end = 2
66 | #x_capacity = 4
67 | #y_capacity = 3
68 |
69 | # condition for getting a solution:
70 | # the target volume 'end' should be a multiple of gcd(a,b)
71 |
72 | if end % gcd(x_capacity,y_capacity) == 0:
73 | print bfs(start, end, x_capacity, y_capacity)
74 | else:
75 | print "No solution possible for this combination."
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------