From 1d757062562f41da09ee1da6f830b02b275fc2a0 Mon Sep 17 00:00:00 2001
From: Xuan Trinh <xuan.trinh@student.unimelb.edu.au>
Date: Sat, 27 Mar 2021 02:56:15 +1100
Subject: [PATCH] =?UTF-8?q?=1B[D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 search/__pycache__/main.cpython-38.pyc        | Bin 3563 -> 3858 bytes
 .../__pycache__/movement_logic.cpython-38.pyc | Bin 5120 -> 5134 bytes
 search/__pycache__/search_algo.cpython-38.pyc | Bin 0 -> 4249 bytes
 .../search_algorithm.cpython-38.pyc           | Bin 0 -> 2898 bytes
 search/main.py                                |  79 +++++----
 search/movement_logic.py                      |  13 +-
 search/search_algo.py                         | 154 ++++++++++++++++++
 search/search_algorithm.py                    | 108 ++++++++----
 search/test.py                                |   2 +-
 9 files changed, 271 insertions(+), 85 deletions(-)
 create mode 100644 search/__pycache__/search_algo.cpython-38.pyc
 create mode 100644 search/__pycache__/search_algorithm.cpython-38.pyc
 create mode 100644 search/search_algo.py

diff --git a/search/__pycache__/main.cpython-38.pyc b/search/__pycache__/main.cpython-38.pyc
index 616e48299948de696d98b0d9e0253aa967bc760b..39cf0f0c5ea04dbc9c928500fcf177d8a05a2557 100644
GIT binary patch
delta 1612
zcmaDYJxPu)l$V!_fq{YHJVRVUyV68H8O9kCwN2|&SaUdXIiolk8B!RdxKh}nxKr4p
zcv9G+cvIM;_)-|7_)|Ed1X38I1Tz^Dg)$iug)<ovMN&nZ84|@(I8(S<7^1{exKnsq
z7@{OnB~y6kFsAUO@VBr;Nu>y+2(~apNvALcGiVA`o#t}(_YE*MFfcMva4agxOv_Bp
zOw5^h`bfQGaz<)$c6?@9d_iVva%y}=W=VWWVo`c($t|wj#O&1gr2NF9lv_Nd1u2Oo
zsqw`ni6yC;jJLQ8iZb&`Ad)W`85kH|GJ%L>1_lNY2Kg0?nHd-uI2jlioEaDxiWf03
zFqAN)Fg7zXGE`}lFqSZ7)ib9sNisAu_6yW9l&~ydtzlTmSj!mBV9F545X2C{5YCXN
z!@^L)md#ZZ!^i-FB@8LdB}`fDDJ;EAj0`1A3pi4k7BVt2L^9+tMKF|b)_{#K;c{V!
z<*8*V;jUo<Syz}<!c#P_gtvsNgs+6Zgr}J$k*h?YgiEG`r<o~{r-Y$|3#_ang&~+h
zlhyAQV`35e<Ul4%4#8WjV82f8X40Cxhe^7gzqFtrwa6tixg-D-V#T+((=zi?;DH7S
zJdkt|D+2?=E&iPRauns9#i=DuIr+)i#YLdd(PS>-2B~97Ni0dc#R`svl?+9)3=9mv
z44tiFLW@(2ieua|t5TC=lJj#5CUY~Zs4IbjQw9{m%p8nNi~@`jjC_oIi~>v?yc~>N
zOe~Cij9iRG@|(Sw%@~DQYglX;3Rl%IyD-Gc)N+=vEnwd~nWdajj2&bzW56xOqFanX
zw-|$OF&6u2a!giWlN1+YU|=Yc1QAjoMa+pQDVkhG(vt((!VHQ)78ik>0CpvWkOQd|
zg~hZ5$Z5PBj2w&{Oe~Y%vx!gsz$VEkx|xf88I!mgNU0`>P+?$T&}1#r0<je*ALrCk
z0C^i>;4OY|aKtC)=j3D-XXfXXPZs3Ttv3dxGEkxe*#g3B3=9mQzy_zXE(QjM8io=E
zNrn{0Y^EZi6sB6nJTa&Ub2d|vN(xIYV;)NiYb|36TP;%wV=Z$DlM6$vQ7uaiO9`_i
zLk&ouNeN2{Qw@tG1B7g5s%5QVtzph)C^9jrVX0-RVXb8@G^t@O0V%FZVJ~5=VX$Gy
z<0)aPVUlEk@KQK}88kT)OBop$Ci8Gt)hj3{C`5!h`dKL?RVoyx79<uWmZYXAlw_nT
zfD@HMNxlL&xhR1Bt)oz$s*sYOSE7)Y3R0G@P@I}rl$@cEmR|(cRGyKald6!CnOu^Y
zpO;uvsgPQhT2!e}l9`(d(h5p0iAAY;TwEZFtqLaha@W?Yg8~~I`Whe>C<=<eF`^9O
zg2LZVlMNgtw|IOVBjQ~=gF_tsoL#}G;TD&hXHalRyt9X6P?SJQW^qYkUUF)DQff(g
zYHD7Q1Sme)qBy~>kIzo6yu}8|4pH0?Iv{iMG#>e2kS&N<E)r*8V3-X`(F&l*<mO>y
zW8`6EV`5=pVPs+CVB}#GV&-6EVPs<grERckO_^Kl@$o77$?@?;d?0rVOqSx6t`~xY
zj~;}IPs~Zr2j{UO7LXcH3W?%|$mx}qWabos(hb<FMLHk_x*);;L>PhyBM@N%B1}O9
zB1?e0d5gI?wWJ7?If~>#vY@1&aEm!JucQc+Ji)GncoEgJw>WHa^HWN5QtdzqxEPf5
eSvbHMg;9i&hZW>wB+LY6GqEvqC~}zasQ>_VgK*sd

delta 1295
zcmbOv_gb1Sl$V!_fq{X+IX5;TS7IWc3}eegZPSn_juh4?&J?yNt`ycN?i98to)pF?
z-W2vIzD$NF{#1cxhA6>IhA5#Fjug%ohA80_t`zPThA5F#(G;FJj48Y+d@U?dVk!J7
z0xb+t;wenQ44Q%yPu$MrE-1>(D~V6aPb^Bg1?3dyWTvFTIpvvo=`R@>7#LnMfrw-V
z1_lrYxe<&(qMRTHGcYg|XE87^RB4njlrUy7r7%h|G&A-K)H0MXFJPH$$RzH>n$1-d
z!pH!EC2T27C5&0@Da^f0j0`1=3pi337cw$3L^9+tMKF|b)-X0RGBT8~m2iRR6oz01
zO%}f*w#j>$EE%~c|6|g!V+A|?7F%&iN@`KjEtb@Z%#vH&1&Kw)sqvY41*IjoxKc8c
zO9C=elT(W|nTkM;yv34|SdzGsp-61<DrOsL6_A?+K;B?vViaJMVB}-uV-#TGU@Vf@
z%*$fND9lpBV#83ls)pHxAy%fAvxId4+vYIVaz=MH1_p*(i~+Y8i*7Ln-C_*B#aQg8
z$$pC^Br?GD7ISe)(Jkg6|L|LE&i+23zJ5g_AmyCJsU=Q1`N`SEx0n-CQZ%`WL?;Wg
zhZ#k&7J%GXB+bCUP$UK?#6c`!1_lN<kSi@fuH@lh<Y44rVwt?2U3~Hec1cFz&8OIx
zF^S8Alq!J;Sq26MP1Yi15L;?;JC~LMs)4uo!FI(b=jY^P7H8(?RZhOhrCYBHid9e~
zgKPm|b_NCpR#>dAU|?V<VW?q{WT<6KVXS4UVJKmgWJqDkW-5|PVXkG$(}0SwWHS{R
zq_Ea9<%vN>*s__5oKo0pnetdtID#2c7;BkJm}*%{7+e@)jcQqISV1P$_=AiJDq)6L
zQo>NfD#_5yRLfSwR>P9bP!v?dTFYF+R?AWtRKrpNQadAsvxKFF!G<A^2cjCn16iTT
zRrPoBM((P~i+Nh=WkBJe03yJlqX=Swf~ZIi!~zAIA2`G{S;0{R4!2u8zK#*`E}p?5
zj(*OrQ35HM#U+V($*J*4sU_v9sd=}!LCGp4u_!&Yq*#+ZiW3r|*{PLLT*;+HMX7lu
z0r|zZ*h&(MCeP&6sYi<d?zGIjl=u>`_PL;#)dGb#2L}@iBM&1R3^TJZvoNwSaxn5R
z3NdmpvM{nSaWHZ*^Dq_}fnr$V7JGbrN`7*Dd=WRuC%g;{3{j%Rsfk6&8G5<-WvRKT
zc_r~V`RSR-^-<hV@zRpaoFZnBauyH)ie9jXi&Q~eH4p)EOOZB+r2``LKm<7LG8d<o
z6sd!_`XE9AM1a!fE#}O;k|I#@0XqyFm`H>;1A_&_Ee@O9{FKt1R69@#D+Xmc77h+Z
g4pt6E5wI^=m_UAIVPaunVPs=uVdhZcFy>PM060Dz?EnA(

diff --git a/search/__pycache__/movement_logic.cpython-38.pyc b/search/__pycache__/movement_logic.cpython-38.pyc
index 73f5474c9ead21cb9510b416712b3b8c3be0f9bc..fd26de4a44dce1583ac4a901083de447674a94d6 100644
GIT binary patch
delta 157
zcmZqB=+oc}<>lpKU|?W)_%b$uMRg<JZ4Sn1ll!<eHw$xCF)?1)+{azd#Q1hIAD=5D
zBj4r_{>_Yx5|cRub@*5r7#Kj<nSp_!*lDtppgl`1OAX8BM!`TvM%Kxfg_JmMu@$8j
zm*$jA{wk!##{sg1ON3E`QH-%jf3mu86PrE*149w_<VH5($%ljudDS^&!BCNdi$fRy
D0H7mO

delta 153
zcmeCvXwcvb<>lpKU|?Vn@Qz6MsIrmoHV5xi1_p*=1&|;k7xUy<+_Ia6Ijfi$&u{MI
zu4iI=vzd?2m64Hma|r)tMn>_;9D+K0EDQ_`tPBhc&LEw3lbr<ZH@6A~GBUDEzAmIR
znNe7chYe&Lmk6T>Q<2_eQ{g5yJq8AbBJRnJY{HW-2pjUMamaDVaL95fa&U2o006qT
B9rpkL

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
GIT binary patch
literal 4249
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
P2nR2RJclfYFoy^LujYgr

literal 0
HcmV?d00001

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
GIT binary patch
literal 2898
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

literal 0
HcmV?d00001

diff --git a/search/main.py b/search/main.py
index 8828015..5f9abbd 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 0943875..16017e5 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 0000000..f55d69a
--- /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 3e54462..25a65da 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 1fa07dd..e715455 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'))
-- 
GitLab