diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index db25fb7f0197e6d9c0ba94386084cc04e4198214..b7648c37bfb036c35a935ec778a8b0b35f9004d9 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -9,5 +9,12 @@
         </list>
       </option>
     </inspection_tool>
+    <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredIdentifiers">
+        <list>
+          <option value="tuple.*" />
+        </list>
+      </option>
+    </inspection_tool>
   </profile>
 </component>
\ No newline at end of file
diff --git a/search/__pycache__/main.cpython-38.pyc b/search/__pycache__/main.cpython-38.pyc
index 306b913ed92d9ff2c02f03382457c5518ae3a453..eb1ac70c63e7dcc6ece6b90117cd8b9bfe10b959 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 fd26de4a44dce1583ac4a901083de447674a94d6..a3ebab1dd81cbec0f07ea7082efc74db478d0ed9 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
index 0b2c38ff301effe104872c92bc5895229634aac7..bd303834e681a6b55b086b2bfdc84b5f8add8763 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/__pycache__/search_algorithm.cpython-38.pyc b/search/__pycache__/search_algorithm.cpython-38.pyc
index 59ce8da52be11782436d43c6965409b689989642..8b71a1b293e250952f20fa14b089c534806b984d 100644
Binary files a/search/__pycache__/search_algorithm.cpython-38.pyc and b/search/__pycache__/search_algorithm.cpython-38.pyc differ
diff --git a/search/main.py b/search/main.py
index adf21701aac675e73148276757a0817e3ff9a8a3..d4a4f710b4a8f4e3fe22130d6e60578bce8df120 100644
--- a/search/main.py
+++ b/search/main.py
@@ -5,15 +5,15 @@ Project Part A: Searching
 This script contains the entry point to the program (the code in
 `__main__.py` calls `main()`). Your solution starts here!
 """
-
 import sys
 import json
-from search.search_algo import *
+
+from search.search_algorithm import *
 
 
 def main():
     # define global variable
-    global upperDictPieces, lowerDictPieces, targetDict, setBlocks
+    global upperPiecesDict, lowerPiecesDict, targetsDict, setBlocks
     try:
         with open(sys.argv[1]) as file:
             data = json.load(file)
@@ -22,27 +22,19 @@ def main():
         sys.exit(1)
 
     parse_input(data)
-    # 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.
-    # In question 2 we are told to comment on any heuristics we use.
-    # Considering all of the above, I propose that we use the heuristic of "tiles to closest target"
-    # This is greedy, but it's a lot faster than trying to path optimally.
-    # And for search algorithm choice let's try starting with depth-first search, depth limit 1, 2 or 3
-    # Not sure which is best at the moment, looking ahead is good but looking too far ahead costs too much time
-    # We'll use a dictionary to track current targets
-    # ALGORITHM GOES HERE
 
     # Add starting targets
-    for piece in upperDictPieces:
+    for piece in upperPiecesDict:
         find_target(piece)
+
     # keep moving until all the piece met its target
-    while targetDict:
+    while targetsDict:
         input()
-        upperDictPieces = update_state(upperDictPieces, lowerDictPieces, setBlocks, targetDict)
-        targetDict = check_if_piece_hit_target(upperDictPieces, lowerDictPieces, targetDict)
+        take_turn()
+    make_board()
+    print_board(board)
+    file.close()
 
-    print_board(make_board(lowerDictPieces,upperDictPieces,setBlocks))
 
 def parse_input(data):
     """
@@ -56,7 +48,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
+    global upperPiecesDict, lowerPiecesDict, setBlocks, positionHistory
     initialPiecesUpper = data["upper"]
     initialPiecesLower = data["lower"]
     initialBlocks = data["block"]
@@ -75,8 +67,8 @@ def parse_input(data):
         else:
             nums = nums + 1
             keyWrite = "S" + str(nums)
-        upperDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
-        visit_record[keyWrite] = {}
+        upperPiecesDict[keyWrite] = (piece[F_ROW], piece[F_COLUMN])
+        positionHistory[keyWrite] = {}
 
     # parse the Lower player's token
     nump, numr, nums = 0, 0, 0
@@ -90,18 +82,11 @@ def parse_input(data):
         else:
             nums = nums + 1
             keyWrite = "s" + str(nums)
-        lowerDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
+        lowerPiecesDict[keyWrite] = (piece[F_ROW], piece[F_COLUMN])
 
     # parse the block object
     for block in initialBlocks:
-        setBlocks.add((block[ROW], block[COLUMN]))
-
-
-
-
-
-
-
+        setBlocks.add((block[F_ROW], block[F_COLUMN]))
 
     # Situation 1: If you plan the route ahead without knowing any other piece route,
     # there will be a crash at tile N as both R and S try to take a straight line
diff --git a/search/movement_logic.py b/search/movement_logic.py
index 16017e5facaeec9ab1a05fa9fef3001c859520b4..2abd2c718969a7a49aac41b8108cc407d1a5b12b 100644
--- a/search/movement_logic.py
+++ b/search/movement_logic.py
@@ -306,7 +306,8 @@ def distance_between(Upper_token, Lower_token):
     under section: double coordinates for doublewidth
     ->
     """
-    dx = abs(Upper_token[0] - Lower_token[0])
-    dy = abs(Upper_token[1] - Lower_token[1])
+
+    dx = abs(Upper_token[1] - Lower_token[1])
+    dy = abs(Upper_token[0] - Lower_token[0])
     result = dx + max(0, (dy - dx) / 2)
     return result
diff --git a/search/search_algo.py b/search/search_algo.py
index bc5632ae1fcca7c7dc69140f9594270a0a8a2e37..8452f74026b114ae24561b2172261ca136fb244b 100644
--- a/search/search_algo.py
+++ b/search/search_algo.py
@@ -30,6 +30,7 @@ visit_record = {}
 
 def make_board(lowerPieces, upperPieces, setBlocks):
     """
+    done
     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
@@ -50,6 +51,7 @@ def make_board(lowerPieces, upperPieces, setBlocks):
 
 def get_stronger_piece(piece_type):
     """
+    done
     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
@@ -63,6 +65,7 @@ def get_stronger_piece(piece_type):
 
 def add_slide_action(upperDict, piece, board):
     """
+    done
     add all the valid slide action to a list
     :param board: dictionary contain all piece and block
     :param upperDict: contain detail about upper piece
@@ -94,6 +97,7 @@ def add_slide_action(upperDict, piece, board):
 
 def add_if_valid(position_list, piece, new_position, piece_position, board):
     """
+    done
     check if the move is valid.
     :param position_list:  list contain all added slide action from this turn
     :param piece: the interested upper piece
@@ -123,6 +127,7 @@ def add_if_valid(position_list, piece, new_position, piece_position, board):
 
 def make_priority_list_of_action(upperDict, piece, targetDict, board):
     """
+    done
     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
@@ -152,6 +157,7 @@ def make_priority_list_of_action(upperDict, piece, targetDict, board):
 
 def update_state(upperPieces, lowerPieces, setBlocks, targetDict):
     """
+    done
     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
@@ -175,6 +181,7 @@ def update_state(upperPieces, lowerPieces, setBlocks, targetDict):
 def choose_optimal_combination(possible_action, upperPieces, board, targetDict):
 
     """
+    done
     prioritise action lead a piece directly to its target.
     else choose a combination that does not cause collision between upper piece
 
@@ -238,6 +245,12 @@ def choose_optimal_combination(possible_action, upperPieces, board, targetDict):
 
 
 def decrease_appeal(position, piece):
+    """
+    done
+    :param position:
+    :param piece:
+    :return:
+    """
     global visit_record
 
     if position not in visit_record[piece].keys():
@@ -249,6 +262,7 @@ def decrease_appeal(position, piece):
 
 def check_if_piece_hit_target(upperPieces, lowerPieces, targetDict):
     """
+    done
     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
@@ -281,6 +295,7 @@ def check_if_piece_hit_target(upperPieces, lowerPieces, targetDict):
 
 def piece_collision(pieceA, pieceB) -> int:
     """
+    done
      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
@@ -317,6 +332,7 @@ def piece_collision(pieceA, pieceB) -> int:
 
 def add_swing_action(upperDict, piece, board):
     """
+    done
     check for adjacent tile.
     if there are any adjacent tile to this add swing action from those tile
     :param upperDict: contain all the upper piece
@@ -381,6 +397,7 @@ def add_swing_action(upperDict, piece, board):
 
 def find_target(piece_key):
     """
+    done
     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.
@@ -420,6 +437,13 @@ def find_target(piece_key):
 
 
 def rank_by_appeal(x, targetDict, piece):
+    """
+    done
+    :param x:
+    :param targetDict:
+    :param piece:
+    :return:
+    """
     # distance_between(x, targetDict[piece])
     # make_priority_list_of_action(upperDict, piece, targetDict, board)
     # the reduce would base on how close it is to its target and how many time we visit this.
diff --git a/search/search_algorithm.py b/search/search_algorithm.py
index 25a65da05d1e627d546f53093fbf0bf8755bcb41..666985893bd303aa583db1b51dfecbab13006cdf 100644
--- a/search/search_algorithm.py
+++ b/search/search_algorithm.py
@@ -1,115 +1,384 @@
 """
-logic:
-    -> prioritise the action which take the token closer to its target
+This module is hold all method relate to Search algorithm
 """
-from search.main import *
+from search.movement_logic import *
+from search.search_algo import piece_collision
+
+# Constant definition:
 from search.util import print_board
 
+BLOCK = "[X]"
+UPPER_ROCK = 'R'
+UPPER_SCISSOR = 'S'
+UPPER_PAPER = 'P'
+LOWER_ROCK = 'r'
+LOWER_PAPER = 'p'
+LOWER_SCISSOR = 's'
+TYPE = 0
+F_ROW = 1
+F_COLUMN = 2
+ROW = 0
+COLUMN = 1
+A_WIN = 1
+B_WIN = 2
+DRAW = 1
+MAX_DISTANCE = 10
+FIRST_ENTRY = 1
+RE_ENTRY = 1
+HIGHEST_RANK = 0
+
+# Global variable:
+# All the dictionary is made into global variable since all method is interact with them
+upperPiecesDict = {}
+lowerPiecesDict = {}
+setBlocks = set()
+
+targetsDict = {}
+# keep track all the lower player's piece  <- to ensure no two Upper piece can target only one distinguish lower piece
+targetedPiece = set()
+
+# keep track of how many time a upper piece visit a tile while aiming for a target.
+# this help rank the action.
+positionHistory = {}
+
 board = {}
+'''
+METHOD
+'''
+def get_weaker_piece(piece: str) -> str:
+    """
+    get the weaker piece type in low case
+    :param piece:  key of the piece {e.g: 'r1'}
+    :return: a single character the follow the rule: P> R> S> P
+    """
+    if piece[TYPE] in [LOWER_ROCK, UPPER_ROCK]:
+        return LOWER_SCISSOR
+    elif piece[TYPE] in [LOWER_PAPER, UPPER_PAPER]:
+        return LOWER_ROCK
+    return LOWER_PAPER
+
+
+def get_stronger_piece(piece: str) -> str:
+    """
+    get the stronger piece type in low case
+    :param piece: key of the piece {e.g: 'R1'}
+    :return: a single character that follow the rule: P> R> S> P
+    """
+    if piece[TYPE] in [LOWER_ROCK, UPPER_ROCK]:
+        return LOWER_PAPER
+    elif piece[TYPE] in [LOWER_PAPER, UPPER_PAPER]:
+        return LOWER_SCISSOR
+    return LOWER_ROCK
+
+
+def make_board():
+    """
+    add all the piece into a dictionary of board:
+    (1) -> help with illustrate the current board
+    (2) -> faster look up using a location.
+    """
+    global board
+
+    for piece in lowerPiecesDict:
+        board[lowerPiecesDict[piece]] = piece
+    for piece in upperPiecesDict:
+        board[upperPiecesDict[piece]] = piece
+    for block in setBlocks:
+        board[block] = BLOCK
+
+
+
+
+def check_valid_action(piece: str, new_position: tuple) -> bool:
+    """
+    check if the action is resolved successfully.
+    -> no piece should defeat any other piece unless the one whom it defeated is its Target.
+    -> cant move on top the Block
+    :param piece: we investigate
+    :param new_position: result after perform the action
+    :return: True if the action is successful. False if there are invalid move
+    """
+    # check if if the action happen {if it fail the new_position will be same as piece's position}
+    if compare_tile(upperPiecesDict[piece], new_position):
+        return False
+
+    # check if new_position is the piece's target
+    if piece in targetsDict.keys() and compare_tile(targetsDict[piece], new_position):
+        return True
+
+    # check if the position result from an action is into a free tile.
+    if new_position in board.keys():
+        if board[new_position] == BLOCK:
+            return False
+        if piece_collision(board[new_position], piece) != DRAW:
+            return False
+
+    return True
+
+
+def check_in(position: tuple, piece: str):
+    """
+    log each time piece visit a tile.
+    -> if the piece comeplete its journey {arrived at its Target's location}
+    :param position: of the piece
+    :param piece: that we want to log
+    """
+    global positionHistory
+    # first time visit this tile.
+    if position not in positionHistory[piece].keys():
+        positionHistory[piece][position] = FIRST_ENTRY
+    else:
+        positionHistory[piece][position] += RE_ENTRY
+
+
+def rank(position: tuple, piece: str) -> int:
+    """
+    rank is base on how far of interested position to piece's target position
+    -> how ever position is will be rank lower if it is visit before
+    :param position: we want to rank
+    :param piece: rank base on the piece
+    :return: rank
+    """
+    # base rank is the distance between current position to the piece's target
+    baseRank = distance_between(position, targetsDict[piece])
+    # reduce_factor is base on how many time has this piece visit current tile.
+    reduceFactor = 0
+    if piece in positionHistory.keys() and position in positionHistory[piece].keys():
+        reduceFactor = positionHistory[piece][position]
+
+    return baseRank + reduceFactor
 
 
-def add_to_queue(token, state, targetDict):
+def piece_collision(pieceA: str, pieceB: str) -> int:
     """
-        -> 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
+     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
+
+    :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
     """
-    # add all the adjacent move to queue
-    appending_list = add_adjacent_action(token, state)
+    pieceA = pieceA[TYPE].lower()
+    pieceB = pieceB[TYPE].lower()
+    if pieceA is LOWER_ROCK:
+        if pieceB == LOWER_SCISSOR:
+            return A_WIN
+        elif pieceB == LOWER_PAPER:
+            return B_WIN
 
-    # 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])))
+    elif pieceA == LOWER_SCISSOR:
+        if pieceB == LOWER_PAPER:
+            return A_WIN
+        elif pieceB == LOWER_ROCK:
+            return B_WIN
 
+    elif pieceA == LOWER_PAPER:
+        if pieceB == LOWER_ROCK:
+            return A_WIN
+        elif pieceB == LOWER_SCISSOR:
+            return B_WIN
+    return DRAW
 
 
-    return appending_list
+def slide_action(piece: str) -> list:
+    """
+    for each piece there will be 6 total position as result of slide action.
+    -> check each to ensure they are valid move
+    :param piece: will perform an slide action
+    :return: unsorted list of all the valid action
+    """
+    action_list = []
 
+    position = upperPiecesDict[piece]
+    for action in (slide_right(position), slide_left(position), slide_up_left(position),
+                   slide_up_right(position), slide_down_left(position), slide_down_right(position)):
+        if check_valid_action(piece, action):
+            action_list.append(action)
 
-def add_if_allowed(list, token, token_new_position, token_position):
+    return action_list
+
+
+def swing_action(piece: str) -> list:
     """
-    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 token: the adjcent tile of a token
-    :param token_new_position:
-    :return: the list so the local change can be pass to higher scope
+    for each adjacent piece there will be at most 3 swing move.
+    -> check those move to ensure they are valid
+    :param piece: will perform swing action
+    :return: unsorted list of all valid action
     """
-    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
 
+    # find all the adjacent piece
+    adjacent_pieces = []
+
+    position = upperPiecesDict[piece]
+    for tile in (slide_right(position), slide_left(position), slide_up_left(position),
+                 slide_up_right(position), slide_down_left(position), slide_down_right(position)):
+        # check if the move is not out of board
+        if not compare_tile(position, tile):
+            # the tile can be any object except block
+            if tile in board and board[tile] != BLOCK:
+                adjacent_pieces.append(tile)
+
+    # if there are at least one adjacent piece, add the position result from performing swing action from those piece.
+    action_list = []
 
-def add_adjacent_action(token, state):
+    for adjacent_piece in adjacent_pieces:
+        for action in (swing_to_tile_1(position, adjacent_piece), swing_to_tile_2(position, adjacent_piece),
+                       swing_to_tile_3(position, adjacent_piece)):
+            if check_valid_action(piece, action):
+                action_list.append(action)
+
+    return action_list
+
+
+def find_target(piece: str):
     """
-    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
+    Find a weaker piece to this piece which closest
+    -> only add if that potential target is not targeted by any other upper piece.
+    :param piece: which we want to map a target to
     """
-    appending_list = []
+    global targetsDict
+    # get the target
+    targetType = get_weaker_piece(piece)
+
+    targetDistance = MAX_DISTANCE
+    target = ""
 
-    # check the right tile
-    appending_list = add_if_allowed(appending_list, token, slide_right(state[token]), state[token])
+    for lowerPiece in lowerPiecesDict:
+        if lowerPiece[TYPE] == targetType and lowerPiece not in targetedPiece:
 
-    # check the left tile
-    appending_list = add_if_allowed(appending_list, token, slide_left(state[token]), state[token])
+            distance = distance_between(upperPiecesDict[piece], lowerPiecesDict[lowerPiece])
 
-    # check the up_left
-    appending_list = add_if_allowed(appending_list, token, slide_up_left(state[token]), state[token])
+            if distance < targetDistance:
+                target = lowerPiece
+                targetDistance = distance
+    if targetDistance != MAX_DISTANCE:
+        targetsDict[piece] = lowerPiecesDict[target]
+        targetedPiece.add(target)
 
-    # check the up_uight
-    appending_list = add_if_allowed(appending_list, token, slide_up_right(state[token]), state[token])
 
-    # check the down_left
-    appending_list = add_if_allowed(appending_list, token, slide_down_left(state[token]), state[token])
+def make_ranked_move_list(piece: str) -> list:
+    """
+    add all the possible position after perform an action.
+    sort them according to their rank{low to high}
+    :param piece: will be perform the move
+    :return: sorted list of position
+    """
 
-    # check the down_right
-    appending_list = add_if_allowed(appending_list, token, slide_down_right(state[token]), state[token])
+    # add all the valid adjacent position result from perform a slide action
+    position_list = slide_action(piece)
 
-    return appending_list
+    # add all the valid position result from perform a swing action
+    position_list.extend(swing_action(piece))
 
+    # rank the list base on how close it is to its target. The least visited position the higher rank it is.
+    if piece in targetsDict.keys():
+        position_list.sort(key=(lambda x: rank(x, piece)))
+    return position_list
 
-def get_stronger_token(token):
-    if token[FIRST_CHAR] == 'R':
-        return 'p'
-    if token[FIRST_CHAR] == 'S':
-        return 'r'
-    return 's'
 
+def perform_optimal_combination(move_list: dict):
+    """
+    perform an action from each of the piece sorted action list.
+    -> prioritise action that after complete bring piece to its target.
+    -> then choose an action from those piece with the least choice.
+    -> then choose action from the remained piece in a way that not cause collision
+    :param move_list: contain all the pottential moved for all piece
+    """
+    # perform all the action that directly lead the piece to its target.
+    priority_list = []
 
-def update_state(state, setblocks, targetDict):
+    for piece in move_list:
+        if piece in targetsDict.keys() and compare_tile(move_list[piece][HIGHEST_RANK], targetsDict[piece]):
 
-    make_board(state, setblocks)
+            # perform swap and update board
+            del board[upperPiecesDict[piece]]
+            upperPiecesDict[piece] = targetsDict[piece]
 
-    print("\n\n")
+            board[targetsDict[piece]] = piece
+        else:
+            priority_list.append(piece)
+
+    # sort the list base on number of action.
+    priority_list.sort(key=(lambda key: len(move_list[key])))
+
+    # perform an action that does not result in a collision.
+    for piece in priority_list:
+        index = HIGHEST_RANK
+        moved = False
+
+        while not moved:
+            if index >= len(move_list[piece]):
+                break
+
+            if move_list[piece][index] in board.keys() and\
+                    piece_collision(board[move_list[piece][index]], piece) != DRAW:
+                index += 1
+                continue
+
+            # perform the action
+            if upperPiecesDict[piece] in board.keys():
+                del board[upperPiecesDict[piece]]
+            upperPiecesDict[piece] = move_list[piece][index]
+
+            board[move_list[piece][index]] = piece
+            moved = True
+
+            check_in(move_list[piece][index], piece)
+
+
+
+def take_turn():
+    """
+    each turn: map out the board in order to look up easily.
+
+    choose a combination of move that is partially optimal {move all the piece <some time> closer to its target}
+    """
+    make_board()
     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
+    possible_actions = {}
+    for piece in upperPiecesDict:
+        possible_actions[piece] = make_ranked_move_list(piece)
 
-def make_board(state, setblocks):
-    global board
-    board = {}
-    for piece in state:
+    perform_optimal_combination(possible_actions)
+    update_target_dictionary()
 
-        board[state[piece]] = piece
 
-    for block in setblocks:
-        board[block] = ''
+def update_target_dictionary():
+    """
+    removed all piece that hit its target.
+    attempt to assign it a new target.
+    :return:
+    """
+    global  targetsDict, lowerPiecesDict, positionHistory
+    removed = False
+    deleted = []
+    for piece in targetsDict.keys():
+        if compare_tile(upperPiecesDict[piece], targetsDict[piece]):
+            # remove the defeated piece
+            removed_piece = ""
+            for removed_p in lowerPiecesDict:
+                if compare_tile(lowerPiecesDict[removed_p], targetsDict[piece]):
+                    removed_piece = removed_p
+                    break
+            deleted.append(piece)
+            del lowerPiecesDict[removed_piece]
+            targetedPiece.remove(removed_piece)
 
+            # reset the log for visited node
+            positionHistory[piece] = {}
+            removed = True
 
+    for piece in deleted:
+        del targetsDict[piece]
+    # once the piece hit it target, it is free to find a new target.
+    # if there are more lower piece then which already targeted {some lower piece is not target}
+    # we can check if the available pieces can target those
+    if removed and len(lowerPiecesDict) > len(targetsDict):
+        for piece in upperPiecesDict:
+            # when a piece is remove then there will
+            if piece in targetsDict.keys():
+                continue
 
+            find_target(piece)
\ No newline at end of file
diff --git a/search/test.py b/search/test.py
index e715455e1f581633e7dfd05ab0b2b417abc6c03f..374b8ce5f34e531230b0d08821dae092721dd52b 100644
--- a/search/test.py
+++ b/search/test.py
@@ -1 +1,8 @@
-print('R' in ('R', 's'))
+from search.movement_logic import distance_between
+
+print(distance_between((2, -2), (4, 0)))
+print(distance_between((2, -1), (4, 0)))
+print(distance_between((1,  0), (4, 0)))
+print(distance_between((0,  0), (4, 0)))
+print(distance_between((0, -1), (4, 0)))
+print(distance_between((1, -2), (4, 0)))
\ No newline at end of file