Skip to content

Commit

Permalink
Update: Lab 5 Final
Browse files Browse the repository at this point in the history
  • Loading branch information
syntnc committed Aug 15, 2018
1 parent 60239ea commit 6d936f5
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 34 deletions.
87 changes: 87 additions & 0 deletions IIIT-A Lab (IAIN532C)/Lab 5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Lab 5
## Searching

<img src="https://img.shields.io/badge/language-Python3-brightgreen.svg"/>
<img src="https://img.shields.io/badge/VS Code-1.10.2-blue.svg"/>

### Contents
* [Gem Finding](#gem)
* [Sliding Board](#slide)
___


## Gem Finding
Consider a grid map of size `m × n`.

The origin (0, 0) is taken as the top-left corner. The X axis is the vertical axis, the Y axis is the horizontal axis. A cell 0 denotes obstacle-free region, -1 denotes obstacles, and 1 denotes a gem.

*Given a source, the aim of the agent is to go to the gem.*

The step cost is the time. The agent moves 1 block distance per second (or √2 time for diagonal moves). The order of preference of actions is: E, SE, S, SW, W, NW, N, NE, where N, E, S, W stand for North, East, South and West respectively.

The priority queue should be implemented such that, in case of a tie, a node that is inserted first should be removed first. Print the path from the source to the gem.

Print only -1 if no path exists.

### Input:
The input is `t`, the number of test cases, followed by (for every test case) `m` and `n`.

The next `m` lines of `n` integers each denote the grid map. The next line contains the source indicated by two integers `Sx` `Sy`.

### Output:
The output is the path.

### Problems:
1. Solve the problem using a flat `m x n` map.
```
python find_gem.py < input/Q1_input.txt
```

2. Solve (1) with the difference that the map is circular in both X and Y axis, and moving right of the last column places the robot on the 1st column, and similarly with the rows.
```
python find_gem_circular.py < input/Q2_input.txt
```

3. Solve (1) with the constraint that the robot can only move in the direction in which it is facing. If the robot wants to change its direction, it must invoke the action turn, which turns the robot by 45 degrees clockwise or anticlockwise. <br>The turning action has a cost of 5. <br>The robot is initially facing positive the Y axis (looking E).
```
python find_gem_turn.py < input/Q3_input.txt
```

4. Solve (1) to find the path to the gem using iterative lengthening.
```
python find_gem_iterative.py < input/Q4_input.txt
```
___

## Sliding Board
Consider a `n × n` size board (1 ≤ `n` ≤ 10), wherein every cell has a number written on it.

The rows and columns are cyclic. So you can slide any row/column any number of blocks or any number of times.

As an example in the board given below, we slide the middle row one block each repeatedly, and the results are given in the following figures.

| Initial | Move 1 | Move 2 | Move 3 |
|-|-|-|-|
| <pre>4 8 5<br>2 6 13<br>1 10 18</pre> | <pre>4 8 5<br>13 2 6<br>1 10 18</pre> | <pre>4 8 5<br>6 13 2<br>1 10 18</pre> | <pre>4 8 5<br>2 6 13<br>1 10 18</pre> |

A unit move in this game is sliding any 1 row (or 1 one column) any number of times. So the motions made above is one single move of the game.

Given a source configuration and a goal configuration, print the moves that result in the goal configuration from a source configuration using Iterative Deepening.

* **Primary criterion:** Moving rows is preferred to moving columns
* **Secondary criterion:** An earlier row/column is preferred to a later one
* **Tertiary criterion:** Sliding lesser rightward/downward is preferred to sliding more

### Input:
The first line of input is `t`, the number of test cases.

For every test case, the first line of input is `n`, the size of the game. <br>The next `n` lines with `n` integers each is the source configuration. <br>The next `n` lines with `n` integers each is the goal configuration.

### Output:
The output is variable number of lines, each line indicating the board configuration of a move printed in a row major format.

```
python sliding_board.py < input/Q5_input.txt
```

**Note:** *Compare each output with the corresponding output files in `output` directory.*
29 changes: 23 additions & 6 deletions IIIT-A Lab (IAIN532C)/Lab 5/find_gem.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from copy import deepcopy
from functools import total_ordering
from math import sqrt
from queue import PriorityQueue

DIRECTIONS = ['E', 'SE', 'S', 'SW', 'W', 'NW', 'N', 'NE']
MOVES = {'NE':[-1, 1], 'N':[-1, 0], 'NW':[-1, -1], 'W':[0, -1], 'E':[0, 1], 'SE':[1, 1], 'S':[1, 0], 'SW':[1, -1]}
Expand All @@ -9,6 +11,7 @@

@total_ordering
class Node(object):
"""State class"""
def __init__(self, cost, time, coordinate, path):
self.cost = cost
self.time = time
Expand All @@ -22,8 +25,13 @@ def __lt__(self, other):
return (self.cost, self.time) < (other.cost, other.time)

def move_next(node, current_path):
'''GETS NEXT VALID MOVES IN ALL EIGHT DIRECTIONS FROM CURRENT COORDINATE'''
from math import sqrt
"""Gets next valid moves in all eight directions from current coordinate
:param node: Current state object
:param current_path: List of coordinates already visited in the current path
:returns: List of valid moves in all directions from current state
"""
global TIME
next_moves = []
for direction in DIRECTIONS:
Expand All @@ -38,12 +46,21 @@ def move_next(node, current_path):
return next_moves

def is_goal(coordinate):
'''CHECKS IF GEM IS PRESENT AT THE CURRENT COORDINATE'''
"""Checks if gem is present at the current coordinate
:param coordinate: Tuple of x and y coordinates
:returns: Boolean whther the gem is present at the given coordinate
"""
return GRID[coordinate['x']][coordinate['y']] == 1

def search(source):
'''BREADTH-FIRST SEARCH FROM SOURCE TO GOAL'''
from queue import PriorityQueue
"""Breadth-first search from source to goal
:param source: Tuple of x and y coordinates of the initial position
:returns: Path traversed from source to goal position
"""
queue = PriorityQueue()
queue.put(Node(0, TIME, source, []))
path = None
Expand All @@ -60,7 +77,7 @@ def search(source):
return path

def main():
'''MAIN FUNCTION'''
"""Main method"""
global M, N, GRID
t = int(input())
for _ in range(t):
Expand Down
32 changes: 24 additions & 8 deletions IIIT-A Lab (IAIN532C)/Lab 5/find_gem_circular.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from copy import deepcopy
from functools import total_ordering
from math import sqrt
from queue import PriorityQueue

INFINITY = 10 ** 9
DIRECTIONS = ['E', 'SE', 'S', 'SW', 'W', 'NW', 'N', 'NE']
Expand All @@ -10,6 +12,7 @@

@total_ordering
class Node(object):
"""State class"""
def __init__(self, cost, coordinate, path, parent):
self.cost = cost
self.coordinate = coordinate
Expand All @@ -23,8 +26,13 @@ def __lt__(self, other):
return self.cost < other.cost

def move_next(node, current_path):
'''GETS NEXT VALID MOVES IN ALL EIGHT DIRECTIONS FROM CURRENT COORDINATE'''
from math import sqrt
"""Gets next valid moves in all eight directions from current coordinate
:param node: Current state object
:param current_path: List of coordinates already visited in the current path
:returns: List of valid moves in all directions from current state
"""
global TIME
next_moves = []
for direction in DIRECTIONS:
Expand All @@ -38,21 +46,29 @@ def move_next(node, current_path):
return next_moves

def is_goal(coordinate):
'''CHECKS IF GEM IS PRESENT AT THE CURRENT COORDINATE'''
"""Checks if gem is present at the current coordinate
:param coordinate: Tuple of x and y coordinates
:returns: Boolean whther the gem is present at the given coordinate
"""
return GRID[coordinate[0]][coordinate[1]] == 1

def search(source):
'''SEARCH FROM SOURCE TO GOAL'''
from queue import PriorityQueue
"""Search from source to goal
:param source: Tuple of x and y coordinates of the initial position
:returns: Path traversed from source to goal position
"""
queue, visited = PriorityQueue(), {}
queue.put(Node((0, TIME), source, [], None))
distance = {}
distance[source] = (0, 0)
path = None
while not queue.empty():
node = queue.get()

print(node.coordinate)

if node.coordinate in visited:
continue

Expand All @@ -75,7 +91,7 @@ def search(source):
return path

def main():
'''MAIN FUNCTION'''
"""Main method"""
global M, N, GRID
t = int(input())
for _ in range(t):
Expand Down
38 changes: 31 additions & 7 deletions IIIT-A Lab (IAIN532C)/Lab 5/find_gem_iterative.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
from math import sqrt

DIRECTIONS = ['E', 'SE', 'S', 'SW', 'W', 'NW', 'N', 'NE']
MOVES = {'NE':[-1, 1], 'N':[-1, 0], 'NW':[-1, -1], 'W':[0, -1], 'E':[0, 1], 'SE':[1, 1], 'S':[1, 0], 'SW':[1, -1]}
M, N = 0, 0
GRID = None
STACK = None

class Node(object):
"""State class"""
def __init__(self, cost, coordinate):
self.cost = cost
self.coordinate = coordinate

def move_next(node):
'''GETS NEXT VALID MOVES IN ALL EIGHT DIRECTIONS FROM CURRENT COORDINATE'''
from math import sqrt
"""Gets next valid moves in all eight directions from current coordinate
:param node: Current state object
:param current_path: List of coordinates already visited in the current path
:returns: List of valid moves in all directions from current state
"""
next_moves = []
for direction in DIRECTIONS:
step_cost = 1 if direction in {'N', 'E', 'W', 'S'} else sqrt(2)
Expand All @@ -23,11 +31,22 @@ def move_next(node):
return next_moves

def is_goal(coordinate):
'''CHECKS IF GEM IS PRESENT AT THE CURRENT COORDINATE'''
"""Checks if gem is present at the current coordinate
:param coordinate: Tuple of x and y coordinates
:returns: Boolean whther the gem is present at the given coordinate
"""
return GRID[coordinate['x']][coordinate['y']] == 1

def dls(node, depth):
'''DEPTH-LIMITED SEARCH FROM SOURCE TO GOAL'''
"""Depth-limited search from source to goal
:param node: State object
:param depth: Depth limit for searching
:returns: Boolean whether goal state is found
"""
global STACK
if depth < 0:
return False
Expand All @@ -41,14 +60,19 @@ def dls(node, depth):
return False

def iterative_deepening(source):
'''ITERATIVE DEEPENING SEARCH'''
"""Iterative deepening search from source to goal
:param source: State object of current position
:returns: Boolean whether iterative deepening search finds goal position
"""
for depth in range(100):
if dls(source, depth):
return True
return False

def main():
'''MAIN FUNCTION'''
"""Main method"""
global M, N, GRID, STACK
t = int(input())
for _ in range(t):
Expand All @@ -66,4 +90,4 @@ def main():
print(-1)

if __name__ == '__main__':
main()
main()
29 changes: 23 additions & 6 deletions IIIT-A Lab (IAIN532C)/Lab 5/find_gem_turn.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from copy import deepcopy
from functools import total_ordering
from math import sqrt
from queue import PriorityQueue

DIRECTIONS = ['E', 'SE', 'S', 'SW', 'W', 'NW', 'N', 'NE']
MOVES = {'NE':[-1, 1, 7], 'N':[-1, 0, 6], 'NW':[-1, -1, 5], 'W':[0, -1, 4], 'E':[0, 1, 0], 'SE':[1, 1, 1], 'S':[1, 0, 2], 'SW':[1, -1, 3]}
Expand All @@ -9,6 +11,7 @@

@total_ordering
class Node(object):
"""State class"""
def __init__(self, cost, time, coordinate, parent, face):
self.cost = cost
self.time = time
Expand All @@ -26,8 +29,13 @@ def __lt__(self, other):
return (self.cost, self.time) < (other.cost, other.time)

def move_next(node):
'''GETS NEXT VALID MOVES IN ALL EIGHT DIRECTIONS FROM CURRENT COORDINATE'''
from math import sqrt
"""Gets next valid moves in all eight directions from current coordinate
:param node: Current state object
:param current_path: List of coordinates already visited in the current path
:returns: List of valid moves in all directions from current state
"""
global TIME
next_moves = []
for direction in DIRECTIONS:
Expand All @@ -43,12 +51,21 @@ def move_next(node):
return next_moves

def is_goal(coordinate):
'''CHECKS IF GEM IS PRESENT AT THE CURRENT COORDINATE'''
"""Checks if gem is present at the current coordinate
:param coordinate: Tuple of x and y coordinates
:returns: Boolean whther the gem is present at the given coordinate
"""
return GRID[coordinate['x']][coordinate['y']] == 1

def search(source):
'''DIJKSTRA SEARCH FROM SOURCE TO GOAL'''
from queue import PriorityQueue
"""Dijkstra search from source to goal
:param source: Tuple of x and y coordinates of the initial position
:returns: Path traversed from source to goal position
"""
queue = PriorityQueue()
starting_node = Node(0, TIME, source, None, 0)
queue.put(starting_node)
Expand All @@ -73,7 +90,7 @@ def search(source):
return path

def main():
'''MAIN FUNCTION'''
"""Main method"""
global M, N, GRID, TIME
t = int(input())
for _ in range(t):
Expand Down
Loading

0 comments on commit 6d936f5

Please sign in to comment.