Skip to content
Snippets Groups Projects
Commit 1d757062 authored by Xuan Trinh's avatar Xuan Trinh
Browse files

[D

parent 68b1cd6f
No related branches found
No related tags found
No related merge requests found
No preview for this file type
No preview for this file type
File added
File added
......@@ -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,7 +213,6 @@ 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
......
......@@ -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))
......@@ -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
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
......@@ -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(key = (lambda x: distance_between(x, target)))
appending_list.sort()
appending_list.sort(key=(lambda x: distance_between(x, targetDict[token])))
#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] = ''
print('r' == 'r1')
\ No newline at end of file
print('R' in ('R', 's'))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment