diff --git a/search/__pycache__/main.cpython-38.pyc b/search/__pycache__/main.cpython-38.pyc
index 616e48299948de696d98b0d9e0253aa967bc760b..39cf0f0c5ea04dbc9c928500fcf177d8a05a2557 100644
Binary files a/search/__pycache__/main.cpython-38.pyc and b/search/__pycache__/main.cpython-38.pyc differ
diff --git a/search/__pycache__/movement_logic.cpython-38.pyc b/search/__pycache__/movement_logic.cpython-38.pyc
index 73f5474c9ead21cb9510b416712b3b8c3be0f9bc..fd26de4a44dce1583ac4a901083de447674a94d6 100644
Binary files a/search/__pycache__/movement_logic.cpython-38.pyc and b/search/__pycache__/movement_logic.cpython-38.pyc differ
diff --git a/search/__pycache__/search_algo.cpython-38.pyc b/search/__pycache__/search_algo.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a78ee17d6e28f7e9f68cc5ee5a115a10aa34ce4f
Binary files /dev/null and b/search/__pycache__/search_algo.cpython-38.pyc differ
diff --git a/search/__pycache__/search_algorithm.cpython-38.pyc b/search/__pycache__/search_algorithm.cpython-38.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..59ce8da52be11782436d43c6965409b689989642
Binary files /dev/null and b/search/__pycache__/search_algorithm.cpython-38.pyc differ
diff --git a/search/main.py b/search/main.py
index 882801548ed93688cc6ad1a6b39cc551cdb3e14f..5f9abbd3848ed45715689cb07dae1f81b7031f76 100644
--- a/search/main.py
+++ b/search/main.py
@@ -8,32 +8,33 @@ This script contains the entry point to the program (the code in
 
 import sys
 import json
-
-# If you want to separate your code into separate files, put them
-# inside the `search` directory (like this one and `util.py`) and
-# then import from them like this:
 from search.movement_logic import *
-from search.util import print_board, print_slide, print_swing
+from search.search_algo import check_if_piece_hit_target, make_board, update_state
+from search.util import print_board
 
 # Constant's definition.
+
+
 TYPE = 0
 ROW = 1
 COLUMN = 2
-
 A_WIN = 1
 B_WIN = 2
 DRAW = 0
-
 MAX_DISTANCE = 99
+FIRST_CHAR = 0
+
+upperDictPieces = {}
+lowerDictPieces ={}
+targetDict = {}
 
-# Why don't we just make the pieces and blocks global then?
-# No need to ever pass them around
-dictPieces = {}
 setBlocks = set()
-dictTargets = {}
 
 
 def main():
+    # define global variable
+    global upperDictPieces, lowerDictPieces, targetDict, setBlocks
+    print("a")
     try:
         with open(sys.argv[1]) as file:
             data = json.load(file)
@@ -42,8 +43,6 @@ def main():
         sys.exit(1)
 
     parse_input(data)
-    print(dictPieces)
-
     # So basically it is heavily implied to treat the game as a state-based search problem.
     # We are also told in question 3 of the design report to discuss the time and space
     # requirements, and the connection with the branching factor and search tree depth.
@@ -56,15 +55,13 @@ def main():
     # ALGORITHM GOES HERE
 
     # Add starting targets
-
-    # Algorithm start
-
-    # TODO:
-    # Find and print a solution to the board configuration described
-    # by `data`.
-    # Why not start by trying to print this configuration out using the
-    # `print_board` helper function? (See the `util.py` source code for
-    # usage information).
+    for piece in upperDictPieces:
+        find_target(piece)
+    # keep moving until all the piece met its target
+    while targetDict:
+        upperDictPieces = update_state(upperDictPieces, lowerDictPieces, setBlocks, targetDict)
+        targetDict = check_if_piece_hit_target(upperDictPieces, targetDict)
+        print(upperDictPieces)
 
 
 def parse_input(data):
@@ -79,6 +76,7 @@ def parse_input(data):
     # We can put the code to read the file NOT in the try/except statement because
     # if the file couldn't be read the process would end anyway
 
+    global upperDictPieces, lowerDictPieces, setBlocks
     initialPiecesUpper = data["upper"]
     initialPiecesLower = data["lower"]
     initialBlocks = data["block"]
@@ -97,7 +95,7 @@ def parse_input(data):
         else:
             nums = nums + 1
             keyWrite = "S" + str(nums)
-        dictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
+        upperDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
 
     # parse the Lower player's token
     nump, numr, nums = 0, 0, 0
@@ -111,7 +109,7 @@ def parse_input(data):
         else:
             nums = nums + 1
             keyWrite = "s" + str(nums)
-        dictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
+        lowerDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
 
     # parse the block object
     for block in initialBlocks:
@@ -158,41 +156,39 @@ def find_target(piece_key):
     """
     This function changes the value of the key given in the
     target dictionary to the closest enemy piece it can beat
+    XUAN: by separated the upper to lower piece, we dont need to search for the whole dictionary every time we compare.
 
     :param piece_key: key of the piece to find a target for. We should only work with upper player's pieces
     :return: null
     """
-    currentPos = dictPieces[piece_key]
+    global targetDict
     # Set the target
-    target = ""
     if piece_key[TYPE] == "R":
         target = "s"
     elif piece_key[TYPE] == "S":
         target = "p"
-    elif piece_key[TYPE] == "P":
-        target = "r"
-    # If we haven't set a target by now, we're dealing with the lower player pieces
     else:
-        return
+        target = "r"
+
     # Now we check which target is closest
     # Start with dummy information
     targetPiece = ""
     targetDist = MAX_DISTANCE
-    for key in dictPieces:
-        # XUAN: unfortunately i believe this logical operation will always be FALSE
-        # e.g: 'r' != 'r1'
-        if key[TYPE] == target:
-            distance = distance_between(dictPieces[piece_key], dictPieces[key])
+    for key in lowerDictPieces:
+        if key[FIRST_CHAR] == target:
+            distance = distance_between(lowerDictPieces[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.
             if distance < targetDist:
                 targetPiece = key
                 targetDist = distance
+
     # Now add target to dictionary
+    # case where no key that match criteria.
     if targetDist == MAX_DISTANCE:
-        dictTargets[piece_key] = ()
+        targetDict[piece_key] = ()
     else:
-        # Xuan: does this 'variable' has any value? since it is out side its scope.
-        dictTargets[piece_key] = dictPieces[targetPiece]
-    return
+        targetDict[piece_key] = lowerDictPieces[targetPiece]
 
 
     # Situation 1: If you plan the route ahead without knowing any other piece route,
@@ -217,14 +213,13 @@ def find_target(piece_key):
     #             |      |     |     |     |     |
     #             '-._.-'-._.-'-._.-'-._.-'-._.-'
 
-
     # Situation 2 (B are blocks)
     # I'm not sure if they will throw something this tricky at us
     # but this should be solvable
     #              .-'-._.-'-._.-'-._.-'-._.-'-.
     #             |     |     |     |     |     |
     #           .-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
-    #          |     |     |     |    |     |     |
+    #          |     |     |     |     |     |     |
     #        .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
     #       |     |     |     |     |     |     |     |
     #     .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
@@ -239,4 +234,4 @@ def find_target(piece_key):
     #          |     |     |     |     |     |     |
     #          '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
     #             |     |     |     |     |     |
-    #             '-._.-'-._.-'-._.-'-._.-'-._.-'
\ No newline at end of file
+    #             '-._.-'-._.-'-._.-'-._.-'-._.-'
diff --git a/search/movement_logic.py b/search/movement_logic.py
index 0943875610d76ca053af1b879ac208641ebcfbef..16017e5facaeec9ab1a05fa9fef3001c859520b4 100644
--- a/search/movement_logic.py
+++ b/search/movement_logic.py
@@ -146,10 +146,10 @@ Swing action logic:
                      '-._.-'-._.-'                '-._.-'      
 """
 
+
 def swing_to_tile_1(token, x):
     position = get_relative_position(token, x)
 
-
     if position == LEFT:
         new_postion = slide_down_left(slide_left(token))
 
@@ -168,8 +168,8 @@ def swing_to_tile_1(token, x):
     if position == DOWN_RIGHT:
         new_postion = slide_right(slide_down_right(token))
 
-    #if the position of the token after the action complete is out of board, return the token position in
-    #stead
+    # if the position of the token after the action complete is out of board, return the token position in
+    # stead
     if compare_tile(new_postion, x):
         return token
 
@@ -204,6 +204,7 @@ def swing_to_tile_2(token, x):
 
     return new_postion
 
+
 def swing_to_tile_3(token, x):
     position = get_relative_position(token, x)
 
@@ -295,7 +296,6 @@ def check_within_board(tile):
     return True
 
 
-
 def distance_between(Upper_token, Lower_token):
     """
     :argument Upper_token - compose of (row, column)
@@ -308,6 +308,5 @@ def distance_between(Upper_token, Lower_token):
     """
     dx = abs(Upper_token[0] - Lower_token[0])
     dy = abs(Upper_token[1] - Lower_token[1])
-
-    return dx + max(0, (dy - dx) / 2)
-
+    result = dx + max(0, (dy - dx) / 2)
+    return result
diff --git a/search/search_algo.py b/search/search_algo.py
new file mode 100644
index 0000000000000000000000000000000000000000..f55d69a3409706c9b357825c076e7c9c263e6447
--- /dev/null
+++ b/search/search_algo.py
@@ -0,0 +1,154 @@
+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
+from search.util import print_board
+
+BLOCK = ""
+POSITION_CLOSEST_TO_TARGET = 0
+
+
+def make_board(lowerPieces, upperPieces, setBlocks):
+    """
+    create a board of the current game -> can do a position look up.
+    :param upperPieces: dictionary contain all the upper piece and its location
+    :param lowerPieces: dictionary contain all the lower piece and its location
+    :param setBlocks: all the block
+    :return: the dictionary represent the board
+    """
+    board = {}
+    for piece in lowerPieces:
+        board[lowerPieces[piece]] = piece
+
+    for piece in upperPieces:
+        board[upperPieces[piece]] = piece
+
+    for block in setBlocks:
+        board[block] = BLOCK
+    return board
+
+
+def get_stronger_piece(piece_type):
+    """
+    Stronger piece is base on the type, even if the piece are from a player.
+    :param piece_type: the type of the piece that we are interested
+    :return: the type of the piece that stronger than the input piece
+    """
+    if piece_type == 'R':
+        return 'p'
+    if piece_type == 'S':
+        return 'r'
+    return 's'
+
+
+def add_slide_action(upperDict, piece, board):
+    """
+    add all the valid slide action to a list
+    :param board: dictionary contain all piece and block
+    :param upperDict: contain detail about upper piece
+    :param piece: key of the interested piece
+    :return: un sorted list of all position as a result of slide action
+    """
+    list = []
+
+    # check the right tile
+    appending_list = add_if_valid(list, piece, slide_right(upperDict[piece]), upperDict[piece], board)
+
+    # check the left tile
+    appending_list = add_if_valid(list, piece, slide_left(upperDict[piece]), upperDict[piece], board)
+
+    # check the up_left
+    appending_list = add_if_valid(list, piece, slide_up_left(upperDict[piece]), upperDict[piece], board)
+
+    # check the up_right
+    appending_list = add_if_valid(list, piece, slide_up_right(upperDict[piece]), upperDict[piece], board)
+
+    # check the down_left
+    appending_list = add_if_valid(list, piece, slide_down_left(upperDict[piece]), upperDict[piece], board)
+
+    # check the down_right
+    appending_list = add_if_valid(list, piece, slide_down_right(upperDict[piece]), upperDict[piece], board)
+
+    return appending_list
+
+
+def add_if_valid(position_list, piece, new_position, piece_position, board):
+    """
+    check if the move is valid.
+    :param position_list:  list contain all added slide action from this turn
+    :param piece: the interested upper piece
+    :param new_position: position result of a slide action
+    :param piece_position:  initial position of the piece.
+    :param board: dictionary contain all piece and block
+    :return: the list
+    """
+
+    # check if the new position is result of a out of board action
+    if compare_tile(new_position, piece_position):
+        return position_list
+
+    if new_position in board.keys():
+        # check if the tile is occupied by a block
+        if board[new_position] == BLOCK:
+            return position_list
+
+        # check if the new position is occupied by piece that stronger
+        elif board[new_position] == get_stronger_piece(piece):
+            return position_list
+
+    # add the new position and return
+    position_list.append(new_position)
+    return position_list
+
+
+def make_priority_list_of_action(upperDict, piece, targetDict, board):
+    """
+    compile all possible action this piece can under go.
+    sort them base on the result distance relative to the piece's target
+    :param upperDict: use to read the position of the piece
+    :param piece: key of the piece
+    :param targetDict: dictionary contain the target of every upper piece
+    :param board: the dictionary of board
+    :return: the sorted list of position result from an action
+    """
+    # add all the adjacent move to queue
+    position_list = add_slide_action(upperDict, piece, board)
+
+    # sort the list base on the how close it is to target
+    position_list.sort(key=(lambda x: distance_between(x, targetDict[piece])))
+
+    return position_list
+
+
+def update_state(upperPieces, lowerPieces, setBlocks, targetDict):
+    """
+    move the piece in a way that bring all piece closer to its target
+    # currently only in away that is work for one piece.
+    :param upperPieces: dictionary contain all the upper piece
+    :param lowerPieces: dictionary contain all the lower piece
+    :param setBlocks: dictionary contain all the block on the board
+    :param targetDict: map each piece to a target
+    :return: the updated upper piece
+    """
+    # create the board in order to support faster look up
+    board = make_board(lowerPieces, upperPieces, setBlocks)
+    print_board(board)
+
+    # 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]
+
+    return upperPieces
+
+
+def check_if_piece_hit_target(upperPiece, targetDict):
+    """
+    remove the target from the target dictionary if the upper piece is at its target location
+    :param upperPiece: contain all upper piece
+    :param targetDict: map upper piece to its lower target
+    :return: the updated target dictionary
+    """
+    for piece in upperPiece:
+        if targetDict and compare_tile(upperPiece[piece], targetDict[piece]):
+            del targetDict[piece]
+
+    return targetDict
\ No newline at end of file
diff --git a/search/search_algorithm.py b/search/search_algorithm.py
index 3e544625827b782e54eda59c8ac1db3014bd0797..25a65da05d1e627d546f53093fbf0bf8755bcb41 100644
--- a/search/search_algorithm.py
+++ b/search/search_algorithm.py
@@ -2,76 +2,114 @@
 logic:
     -> prioritise the action which take the token closer to its target
 """
-from search.movement_logic import slide_right, slide_left, slide_up_left, slide_up_right, slide_down_left, \
-    slide_down_right, distance_between
+from search.main import *
+from search.util import print_board
 
+board = {}
 
-def add_to_queue(record, queue, token_position, target):
+
+def add_to_queue(token, state, targetDict):
     """
-    :argument record: the tile that current token already pass by
-    :param queue: tile a wait to be process.
-    :param token_position: current position
-    :param target: where the token want to go
-    :return:
-
-        -> check the adjcent tile and weight them {prioritise the tile close to the target first}
-        -> append them to the queue in that order
+        -> check the adjacent tile for potential move.
+        -> add them into a priority queue
+    :param targetDict:
+    :param state: run
+    :param token: the one that we want to choose an action for
+    :return: the list sort base on how close it is to the token's target
     """
-    #add all the adjcent move to queue
-    appending_list = add_adjcent_action(record, token_position, target)
+    # add all the adjacent move to queue
+    appending_list = add_adjacent_action(token, state)
+
+    # sort the list base on the how close it is to target
+    appending_list.sort()
+    appending_list.sort(key=(lambda x: distance_between(x, targetDict[token])))
 
-    #sort the list base on the how close it is to target
-    appending_list.sort(key = (lambda x: distance_between(x, target)))
 
-    #add the list to the head to the queue
-    appending_list.extend(queue)
 
     return appending_list
 
 
-def add_if_new_tile(record, list, tile, target):
+def add_if_allowed(list, token, token_new_position, token_position):
     """
-    handle check if the tile has been seen by the token before
-    we only add after we expand the node
-    :param record: log all move of the token while moving toward the target.
+    handle check if the tile has sit on top of a block.
+    or if it is sit on top on a token would beat it
     :param list: the temporary list to append to while await to process
-    :param tile: the adjcent tile of a token
+    :param token: the adjcent tile of a token
+    :param token_new_position:
     :return: the list so the local change can be pass to higher scope
     """
-    if not tile in record or (record[tile] != target):
-        list.append(tile)
+    if compare_tile(token_new_position, token_position):
+        return list
+    if token_new_position == token_new_position not in board.keys() or \
+            board[token_new_position] != "" or \
+            board[token_new_position] != get_stronger_token(token):
+        list.append(token_new_position)
     return list
 
 
-def add_adjcent_action(record, token_position, target):
+def add_adjacent_action(token, state):
     """
-    create a abstraction to hide implementation detail on how to add adjcent move
-    :param record: ensure add the move we have not seen
-    :param token: current position of the token
-    :param target: where the token want to get to
+    create a abstraction to hide implementation detail on how to add adjacent move.
+    check if the any slide action is allowed.
+    :param token:token that we want to find a direction to
     :return: the queue
     """
     appending_list = []
 
     # check the right tile
-    appending_list = add_if_new_tile(record, appending_list, slide_right(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_right(state[token]), state[token])
 
     # check the left tile
-    appending_list = add_if_new_tile(record, appending_list, slide_left(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_left(state[token]), state[token])
 
     # check the up_left
-    appending_list = add_if_new_tile(record, appending_list, slide_up_left(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_up_left(state[token]), state[token])
 
     # check the up_uight
-    appending_list = add_if_new_tile(record, appending_list, slide_up_right(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_up_right(state[token]), state[token])
 
     # check the down_left
-    appending_list = add_if_new_tile(record, appending_list, slide_down_left(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_down_left(state[token]), state[token])
 
     # check the down_right
-    appending_list = add_if_new_tile(record, appending_list, slide_down_right(token_position), target)
+    appending_list = add_if_allowed(appending_list, token, slide_down_right(state[token]), state[token])
 
     return appending_list
 
 
+def get_stronger_token(token):
+    if token[FIRST_CHAR] == 'R':
+        return 'p'
+    if token[FIRST_CHAR] == 'S':
+        return 'r'
+    return 's'
+
+
+def update_state(state, setblocks, targetDict):
+
+    make_board(state, setblocks)
+
+    print("\n\n")
+    print_board(board)
+    for token in state:
+        if token[0] in ('s', 'p', 'r'):
+            print("continue")
+            continue
+
+        potential_new_position = add_to_queue(token, state, targetDict)
+        state[token] = potential_new_position[0]
+        print(state[token])
+    return state
+
+def make_board(state, setblocks):
+    global board
+    board = {}
+    for piece in state:
+
+        board[state[piece]] = piece
+
+    for block in setblocks:
+        board[block] = ''
+
+
 
diff --git a/search/test.py b/search/test.py
index 1fa07dd88fddfd83e75e5a6d6bce10b177c3f40e..e715455e1f581633e7dfd05ab0b2b417abc6c03f 100644
--- a/search/test.py
+++ b/search/test.py
@@ -1 +1 @@
-print('r' == 'r1')
\ No newline at end of file
+print('R' in ('R', 's'))