diff --git a/Test_case/level_3/12.json b/Test_case/level_3/12.json
new file mode 100644
index 0000000000000000000000000000000000000000..37334dc7b7992dc42bceef67f62493c84469db98
--- /dev/null
+++ b/Test_case/level_3/12.json
@@ -0,0 +1,103 @@
+{
+  "upper": [
+    [
+      "p",
+      0,
+      -3
+    ],
+    [
+      "s",
+      0,
+      0
+    ]
+  ],
+  "lower": [
+    [
+      "r",
+      0,
+      1
+    ],
+    [
+      "p",
+      0,
+      2
+    ]
+  ],
+  "block": [
+    [
+      "",
+      -1,
+      -3
+    ],
+    [
+      "",
+      -1,
+      -2
+    ],
+    [
+      "",
+      -1,
+      -1
+    ],
+    [
+      "",
+      -1,
+      0
+    ],
+    [
+      "",
+      -1,
+      1
+    ],
+    [
+      "",
+      -1,
+      2
+    ],
+    [
+      "",
+      -1,
+      3
+    ],
+    [
+      "",
+      0,
+      3
+    ],
+    [
+      "",
+      1,
+      -4
+    ],
+    [
+      "",
+      1,
+      -3
+    ],
+    [
+      "",
+      1,
+      -2
+    ],
+    [
+      "",
+      1,
+      -1
+    ],
+    [
+      "",
+      1,
+      0
+    ],
+    [
+      "",
+      1,
+      1
+    ],
+    [
+      "",
+      1,
+      2
+    ]
+  ]
+}
\ No newline at end of file
diff --git a/search/__pycache__/main.cpython-38.pyc b/search/__pycache__/main.cpython-38.pyc
index 4796c0c303b7134efd9eeda4d2d15bd9c1c39d38..1ac4f3a1eb06acd9bcb68a9797aeb04de23944bd 100644
Binary files a/search/__pycache__/main.cpython-38.pyc and b/search/__pycache__/main.cpython-38.pyc differ
diff --git a/search/__pycache__/search_algo.cpython-38.pyc b/search/__pycache__/search_algo.cpython-38.pyc
index 38e12487fceb0dbd91d980333270203f9d429110..9c6190551c3a2812e7abaca1b7123fa02b9eb34a 100644
Binary files a/search/__pycache__/search_algo.cpython-38.pyc and b/search/__pycache__/search_algo.cpython-38.pyc differ
diff --git a/search/main.py b/search/main.py
index 59181f27d05a476318acab91f34e824174141309..d463cb96a92a52797c817800fd5ee67096ef59ee 100644
--- a/search/main.py
+++ b/search/main.py
@@ -8,14 +8,8 @@ This script contains the entry point to the program (the code in
 
 import sys
 import json
-from search.movement_logic import *
 from search.search_algo import *
 
-# Constant's definition.
-
-
-
-
 
 def main():
     # define global variable
@@ -47,7 +41,8 @@ def main():
         input()
         upperDictPieces = update_state(upperDictPieces, lowerDictPieces, setBlocks, targetDict)
         targetDict = check_if_piece_hit_target(upperDictPieces, lowerDictPieces, targetDict)
-    print(lowerDictPieces)
+
+    print_board(make_board(lowerDictPieces,upperDictPieces,setBlocks))
 
 def parse_input(data):
     """
@@ -101,40 +96,7 @@ def parse_input(data):
         setBlocks.add((block[ROW], block[COLUMN]))
 
 
-def piece_collision(pieceA, pieceB) -> int:
-    """
-     Our upper pieces are R, P and S, lower pieces are r, p and s
-     We will convert both to lower case letters and check each case
-     Would be nice to use comparator but can't have r>s>p>r using it
-
-     Return A_WIN if pieceA wins, B_WIN if pieceB wins and DRAW if neither win
-     Only look at first character of string
 
-    :param pieceA: type of the token in {'R','P','S','r','p','s'}
-    :param pieceB: type of the token in {'R','P','S','r','p','s'}
-    :return: A_WIN, B_WIN or DRAW
-    """
-    pieceA = pieceA[TYPE].lower()
-    pieceB = pieceB[TYPE].lower()
-    if pieceA == "r":
-        if pieceB == "s":
-            return A_WIN
-        elif pieceB == "p":
-            return B_WIN
-
-    elif pieceA == "s":
-        if pieceB == "p":
-            return A_WIN
-        elif pieceB == "r":
-            return B_WIN
-
-    elif pieceA == "p":
-        if pieceB == "r":
-            return A_WIN
-        elif pieceB == "s":
-            return B_WIN
-
-    return DRAW
 
 
 
diff --git a/search/search_algo.py b/search/search_algo.py
index 9d9519c79c39d7cc2532d05e4612a2bc3d86d4fe..5b9dfef56458f4720f00fb1d3bae0cb3e926e628 100644
--- a/search/search_algo.py
+++ b/search/search_algo.py
@@ -1,8 +1,8 @@
-from search.movement_logic import slide_right, slide_left, slide_up_left, slide_up_right, slide_down_left, \
-    slide_down_right, compare_tile, distance_between, swing_to_tile_1, swing_to_tile_2, swing_to_tile_3
+from search.movement_logic import *
 from search.util import print_board
 
-BLOCK = ""
+# BLOCK should be "" but put [X] so we can observe from the print_board statement
+BLOCK = "[X]"
 POSITION_CLOSEST_TO_TARGET = 0
 TYPE = 0
 ROW = 1
@@ -16,9 +16,10 @@ FIRST_CHAR = 0
 upperDictPieces = {}
 lowerDictPieces ={}
 targetDict = {}
-
+targeted_l_piece = set()
 setBlocks = set()
 
+
 def make_board(lowerPieces, upperPieces, setBlocks):
     """
     create a board of the current game -> can do a position look up.
@@ -124,11 +125,13 @@ def make_priority_list_of_action(upperDict, piece, targetDict, board):
     """
     # add all the adjacent move to queue
     position_list = add_slide_action(upperDict, piece, board)
+
+    # add all the swing action to queue
     position_list.extend(add_swing_action(upperDict, piece, board))
 
-    #print(position_list)
     # sort the list base on the how close it is to target
-    position_list.sort(key=(lambda x: distance_between(x, targetDict[piece])))
+    if piece in targetDict.keys():
+        position_list.sort(key=(lambda x: distance_between(x, targetDict[piece])))
 
     return position_list
 
@@ -146,15 +149,71 @@ def update_state(upperPieces, lowerPieces, setBlocks, targetDict):
     # create the board in order to support faster look up
     board = make_board(lowerPieces, upperPieces, setBlocks)
     print_board(board)
-
+    possible_action = {}
     # right now, i assume there only 1 piece, there will be more code combine all the queue.
     for piece in upperPieces:
-        position_list = make_priority_list_of_action(upperPieces, piece, targetDict, board)
-        upperPieces[piece] = position_list[POSITION_CLOSEST_TO_TARGET]
+        possible_action[piece] = make_priority_list_of_action(upperPieces, piece, targetDict, board)
+
+    upperPieces = choose_optimal_combination(possible_action, upperPieces, board, targetDict)
+    return upperPieces
+
+
+def choose_optimal_combination(possible_action, upperPieces, board, targetDict):
+
+    """
+    prioritise action lead a piece directly to its target.
+    else choose a combination that does not cause collision between upper piece
+
+    :param possible_action: all set of possible move sorted base on how close they are to the piece target
+    :param upperPieces: contain all upper piece
+    :param board: all piece
+    :param targetDict: map all piece to its target
+    :return:
+    """
+    finished = set()
+    for piece in possible_action.keys():
+        if piece in possible_action.keys():
+
+            if piece in targetDict.keys() and compare_tile(possible_action[piece][0], targetDict[piece]):
+
+                # perform swap and update board
+                del board[upperPieces[piece]]
+                upperPieces[piece] = targetDict[piece]
+
+                board[targetDict[piece]] = piece
+                # we've finished with this piece.
+                finished.add(piece)
+
+    # each piece is moved once and only once.
+    for piece in possible_action:
+        if piece in finished:
+            continue
+        index = 0
+        moved = False
+        while not moved:
+            # check if the move exist in the board
+            if possible_action[piece][index] not in board.keys():
+                # perform swap and update board
+                del board[upperPieces[piece]]
+                upperPieces[piece] = possible_action[piece][index]
+
+                board[possible_action[piece][index]] = piece
+                moved = True
+            else:
+                # check if no collision happen:
+                if piece_collision(board[possible_action[piece][index]], piece) == DRAW:
+                    # perform swap and update board
+                    del board[upperPieces[piece]]
+                    upperPieces[piece] = possible_action[piece][index]
+
+                    board[possible_action[piece][index]] = piece
+                    moved = True
+            index += 1
 
     return upperPieces
 
 
+
 def check_if_piece_hit_target(upperPieces, lowerPieces, targetDict):
     """
     remove the target from the target dictionary if the upper piece is at its target location
@@ -164,7 +223,7 @@ def check_if_piece_hit_target(upperPieces, lowerPieces, targetDict):
     """
     removed = False
     for piece in upperPieces:
-        if targetDict and compare_tile(upperPieces[piece], targetDict[piece]):
+        if piece in targetDict.keys() and compare_tile(upperPieces[piece], targetDict[piece]):
             for removed_piece in lowerPieces:
                 if compare_tile(lowerPieces[removed_piece],targetDict[piece]):
                    removed = removed_piece
@@ -185,6 +244,42 @@ def check_if_piece_hit_target(upperPieces, lowerPieces, targetDict):
     return targetDict
 
 
+def piece_collision(pieceA, pieceB) -> int:
+    """
+     Our upper pieces are R, P and S, lower pieces are r, p and s
+     We will convert both to lower case letters and check each case
+     Would be nice to use comparator but can't have r>s>p>r using it
+
+     Return A_WIN if pieceA wins, B_WIN if pieceB wins and DRAW if neither win
+     Only look at first character of string
+
+    :param pieceA: type of the token in {'R','P','S','r','p','s'}
+    :param pieceB: type of the token in {'R','P','S','r','p','s'}
+    :return: A_WIN, B_WIN or DRAW
+    """
+    pieceA = pieceA[TYPE].lower()[0]
+    pieceB = pieceB[TYPE].lower()[0]
+    if pieceA == "r":
+        if pieceB == "s":
+            return A_WIN
+        elif pieceB == "p":
+            return B_WIN
+
+    elif pieceA == "s":
+        if pieceB == "p":
+            return A_WIN
+        elif pieceB == "r":
+            return B_WIN
+
+    elif pieceA == "p":
+        if pieceB == "r":
+            return A_WIN
+        elif pieceB == "s":
+            return B_WIN
+
+    return DRAW
+
+
 def add_swing_action(upperDict, piece, board):
     """
     check for adjacent tile.
@@ -198,37 +293,37 @@ def add_swing_action(upperDict, piece, board):
     # check the right tile
     right_tile = slide_right(upperDict[piece])
     if not compare_tile(right_tile, upperDict[piece]) and\
-            right_tile in board and board[right_tile] != "":
+            right_tile in board and board[right_tile] != BLOCK:
         adjacent_list.append(right_tile)
 
     # check the left tile
     left_tile = slide_left(upperDict[piece])
     if not compare_tile(left_tile, upperDict[piece]) and\
-            left_tile in board and board[left_tile] != "":
+            left_tile in board and board[left_tile] != BLOCK:
         adjacent_list.append(left_tile)
 
     # check the up_left
     up_left_tile = slide_up_left(upperDict[piece])
     if not compare_tile(up_left_tile, upperDict[piece]) and\
-            up_left_tile in board and board[up_left_tile] != "":
+            up_left_tile in board and board[up_left_tile] != BLOCK:
         adjacent_list.append(up_left_tile)
 
     # check the up_right
     up_right_tile = slide_up_right(upperDict[piece])
     if not compare_tile(up_right_tile, upperDict[piece]) and\
-            up_right_tile in board and board[up_right_tile] != "":
+            up_right_tile in board and board[up_right_tile] != BLOCK:
         adjacent_list.append(up_right_tile)
 
     # check the down_left
     down_left_tile = slide_down_left(upperDict[piece])
     if not compare_tile(down_left_tile, upperDict[piece]) and\
-            down_left_tile in board and board[down_left_tile] != "":
+            down_left_tile in board and board[down_left_tile] != BLOCK:
         adjacent_list.append(down_left_tile)
 
     # check the down_right
     down_right_tile = slide_down_right(upperDict[piece])
     if not compare_tile(down_right_tile, upperDict[piece]) and\
-            down_right_tile in board and board[down_right_tile] != "":
+            down_right_tile in board and board[down_right_tile] != BLOCK:
         adjacent_list.append(down_right_tile)
 
     # if there are at least one adjacent piece : add the adjacent move from  those tile
@@ -271,9 +366,8 @@ def find_target(piece_key):
     # Start with dummy information
     targetPiece = ""
     targetDist = MAX_DISTANCE
-    print(lowerDictPieces)
     for key in lowerDictPieces:
-        if key[FIRST_CHAR] == target:
+        if key[FIRST_CHAR] == target and key not in targeted_l_piece:
             distance = distance_between(upperDictPieces[piece_key], lowerDictPieces[key])
             # if the distance between this key and the query key is less than the least distance.
             # as well as the key is not targeted by any other key.
@@ -287,4 +381,5 @@ def find_target(piece_key):
         return
     else:
         targetDict[piece_key] = lowerDictPieces[targetPiece]
+        targeted_l_piece.add(targetPiece)