Our goal-choosing code tries to find the best possible goal to score in given a field state. Field state is specified by a list of goal tuples, where each index in the list is matched with the corresponding goal number. A goal tuple has 3 elements (bottom, middle, top). Each element is either 0 for none, 1 for ours, or 2 for opponent. In addition to the field state, the goal-choosing code will also consider the robot's current position and the distances to all of the goals.
To choose a goal, we first determine the 9 possible field states that would result from scoring on any one goal. For each possible field state, we determine the signed difference between our score and our opponent's score. We then use the distance to the goal and whether scoring on it changes ownership as tiebreakers between close score differences. Finally, we pick the strategy which results in the highest total score, with these tiebreakers considered.
def strategy(field, pos):
"""strategy choosing
field: the current field state. Each index is a goal,
each goal has a tuple with balls bottom-to-top. 0=none, 1=us 2=opponent
pos: (x, y) coordinates wrt goal 0
Field looks like this:
--> x+
0 1 2
3 4 5
6 7 8
y+
"""
scores = []
for i, goal in enumerate(field):
# given no scoring in full goals
# can be changed if we can consistently descore
if goal[2]:
scores.append(-999999)
continue
# possible score if we add on top
pField = field.copy()
pField[i] = scoreOn(goal)
our, opponent = scoreField(pField)
# goal ownership score
if goalOwner(goal) != 1:
our += 1.5
scores.append(our - opponent)
# add in fractional time cost
costPerInch = 0.001
locs = [(0,0), (72,0), (144,0), (0,72), (72,72), (144,72), (144,0), (144,72), (144,144)]
for i in range(len(scores)):
scores[i] -= dist(pos, locs[i]) * costPerInch
# choose max score
print(scores)
return scores.index(max(scores))
def dist(pos1, pos2):
x1, y1 = pos1
x2, y2 = pos2
return ((x2-x1)**2 + (y2-y1)**2)**0.5
def scoreOn(goal):
tempList = list(goal)
for i, val in enumerate(goal):
if not val:
tempList[i] = 1
break
return tuple(tempList)
def scoreField(field):
ourPoints = 0
opponentPoints = 0
# 1point per scored ball
for goal in field:
for spot in goal:
if spot == 1:
ourPoints += 1
elif spot == 2:
opponentPoints += 1
# connected rows
rows = [(0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8), (0,4,8), (2,4,6)]
for possible in rows:
possibleIsScored = True
testOwner = goalOwner(field[possible[0]])
if not testOwner:
continue
for req in possible:
if goalOwner(field[req]) != testOwner:
possibleIsScored = False
if possibleIsScored:
if testOwner == 1:
ourPoints += 6
elif testOwner == 2:
opponentPoints += 6
return (ourPoints, opponentPoints)
def goalOwner(goal):
for spot in goal[::-1]:
if spot:
return spot
return 0
# test scoring
if __name__ == "__main__":
testField = [(2,0,0),(0,0,0),(0,0,0),
(0,0,0),(2,0,0),(0,0,0),
(0,0,0),(0,0,0),(2,0,0)]
testPos = (72, 62)
print(strategy(testField, testPos))