Select Git revision
main.py NaN GiB
"""
COMP30024 Artificial Intelligence, Semester 1, 2021
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.movement_logic import *
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 = {}
setBlocks = set()
def main():
# define global variable
global upperDictPieces, lowerDictPieces, targetDict, setBlocks
print("a")
try:
with open(sys.argv[1]) as file:
data = json.load(file)
except IndexError:
print("usage: python3 -m search path/to/input.json", file=sys.stderr)
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:
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):
"""
data is a dictionary with keys "upper", "lower" and "block"
pieces in dictionary, blocks in set, we can use if position in setblocks
parse data into either dictPieces or setBlocks
:param data: Dictionary obtain after read from JSON file using JSON module.
:return: NULL
"""
# 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"]
keyWrite = ""
# Parse the Upper's player token
nump, numr, nums = 0, 0, 0
for piece in initialPiecesUpper:
if piece[TYPE] == "p":
nump = nump + 1
keyWrite = "P" + str(nump)
elif piece[TYPE] == "r":
numr = numr + 1
keyWrite = "R" + str(numr)
else:
nums = nums + 1
keyWrite = "S" + str(nums)
upperDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
# parse the Lower player's token
nump, numr, nums = 0, 0, 0
for piece in initialPiecesLower:
if piece[TYPE] == "p":
nump = nump + 1
keyWrite = "p" + str(nump)
elif piece[TYPE] == "r":
numr = numr + 1
keyWrite = "r" + str(numr)
else:
nums = nums + 1
keyWrite = "s" + str(nums)
lowerDictPieces[keyWrite] = (piece[ROW], piece[COLUMN])
# parse the block object
for block in initialBlocks:
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
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
"""
global targetDict
# Set the target
if piece_key[TYPE] == "R":
target = "s"
elif piece_key[TYPE] == "S":
target = "p"
else:
target = "r"
# Now we check which target is closest
# Start with dummy information
targetPiece = ""
targetDist = MAX_DISTANCE
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:
targetDict[piece_key] = ()
else:
targetDict[piece_key] = lowerDictPieces[targetPiece]
# 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
# .-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | p | | | s | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | N | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | R | | | S | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'
# Situation 2 (B are blocks)
# I'm not sure if they will throw something this tricky at us
# but this should be solvable
# .-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | | | | | | | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | B | B | B | B | B | B | B | |
# .-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-.
# | B | P | | | S | r | p | B | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | B | B | B | B | B | B | B | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'-._.-'
# | | | | | |
# '-._.-'-._.-'-._.-'-._.-'-._.-'