-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate_problem.py
More file actions
154 lines (126 loc) · 8.02 KB
/
create_problem.py
File metadata and controls
154 lines (126 loc) · 8.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from pulp import *
from utils import *
import json
scoring_locations = ['C_CS', 'C_RL', 'C_RMH', 'P_CS', 'P_RL', 'P_RMH']
# Dictionary associating position names with scouted metric names
locations = dict(C_CS='Cargo in Cargo Ship,Teleop', C_RL='Cargo in low Rocket,Teleop',
C_RMH='Cargo in middle/high Rocket,Teleop', P_CS='Panels on Cargo Ship,Teleop',
P_RL='Panels on low Rocket,Teleop', P_RMH='Panels on middle/high Rocket,Teleop')
"""
Creates and solves a LP problem optimizing the number of game piece points with constraints corresponding to teams'
scouted abilities, number of game pieces, number of scoring locations, and number of null hatch panels.
return :optimum_positions: dict
Dictionary with keys corresponding to position names and
values corresponding to number of game pieces to be scored in that position
"""
def create_problem(datafile, teams, num_null_panels=6, optimize_rocket='auto', verbose=False):
# Reads the given file of formatted scouting data
with open(datafile, 'r') as fp:
scouting_data = json.load(fp)
# Determine whether rocket completion should be factored in the constraints
optimize_rocket = evaluate_possible_rocket(scouting_data, teams, 5,
2) if optimize_rocket == 'auto' else optimize_rocket
# Variable to contain the problem data
prob = LpProblem("Maximizing Deepspace Scoring Potential", LpMaximize)
# Creating initial list of scoring positions in format [teamnumber-gamepiece_scoringlocation]
positions = []
for scoring_location in scoring_locations:
for team in teams:
positions.append('{}-{}'.format(str(team), scoring_location))
# Assigning the proper point values to each of the positions
point_values = {position: 2 if 'P' in position.split('-')[1] else 3 for position in positions}
# Creating dictionary of positions with keys being original values in positions list and values being
# the name of the variable in the model
positions = LpVariable.dicts("position", positions, 0, cat=LpInteger)
"""
=====================================================================================================
OBJECTIVE FUNCTION
=====================================================================================================
"""
# Creating the objective function of each position * point value of game piece scored in that position
prob += lpSum([positions[i] * point_values[i] for i in positions]), "Maximum Game Piece Score"
"""
=====================================================================================================
CONSTRAINTS
=====================================================================================================
"""
# Creates constraints based on a team's scouted scoring potential on panels and cargo
# in the cargo ship, rocket low, and rocket middle high
for (position, position_model_name) in positions.items():
# Parse the position string to get the team number and scoring location
team_num, scoring_location = parse_position(position)
# Look up the team's scoring potential in a location from the scouting data and add it to the constraints
prob += lpSum(position_model_name) <= scouting_data[team_num][locations[scoring_location]][
'max'], 'Team {} scoring potential on {}'.format(team_num, scoring_location)
# Create constraints based on the total number of panels/cargo on one side of the field
prob += lpSum(positions[i] for i in positions if 'P' in i) <= 24, "Total Number of Hatch Panels"
prob += lpSum(positions[i] for i in positions if 'P' not in i) <= 24, "Total Number of Cargo"
# Create constraints based on available hatches/bays
prob += lpSum(
positions[i] for i in positions if
'CS' in i and 'P' in i) + num_null_panels <= 8, "Total Number of Hatches on Cargo Ship"
prob += lpSum(
positions[i] for i in positions if 'CS' in i and 'P' not in i) <= 8, "Total Number of Bays on Cargo Ship"
prob += lpSum(
positions[i] for i in positions if 'RL' in i and 'P' in i) <= 4, "Total Number of Hatches on Low Rockets"
prob += lpSum(
positions[i] for i in positions if 'RL' in i and 'P' not in i) <= 4, "Total Number of Bays on Low Rockets"
prob += lpSum(positions[i] for i in positions if
'RMH' in i and 'P' in i) <= 8, "Total Number of Hatches on Middle/High Rockets"
prob += lpSum(positions[i] for i in positions if
'RMH' in i and 'P' not in i) <= 8, "Total Number of Bays on Middle/High Rockets"
# Create constraints limiting cargo placements to be equal or less than panel placements
prob += lpSum(positions[i] for i in positions if 'CS' in i and 'P' not in i) <= lpSum(
positions[i] for i in positions if
'CS' in i and 'P' in i) + num_null_panels, "Panels must be placed before Cargo on Cargo Ship"
prob += lpSum(positions[i] for i in positions if 'RL' in i and 'P' not in i) <= lpSum(
positions[i] for i in positions if 'RL' in i and 'P' in i), "Panels must be placed before Cargo on Low Rockets"
prob += lpSum(positions[i] for i in positions if 'RMH' in i and 'P' not in i) <= lpSum(
positions[i] for i in positions if
'RMH' in i and 'P' in i), "Panels must be placed before Cargo on Middle/High Rockets"
# Create constraints ensuring a complete rocket if optimize_rocket is true
if optimize_rocket:
prob += lpSum(
positions[i] for i in positions if 'RL' in i and 'P' in i) >= 2, "At least two Panels on Low Rocket"
prob += lpSum(
positions[i] for i in positions if 'RL' in i and 'P' not in i) >= 2, "At least two Cargo in Low Rocket"
prob += lpSum(positions[i] for i in positions if
'RMH' in i and 'P' in i) >= 4, "At least four Panels on Middle/High Rocket"
prob += lpSum(positions[i] for i in positions if
'RMH' in i and 'P' not in i) >= 4, "At least four Cargo in Middle/High Rocket"
"""
=====================================================================================================
SOLVING
=====================================================================================================
"""
# Write the LP problem to a file
prob.writeLP('deepspace_optimizer')
# The problem is solved using PuLP's choice of Solver
prob.solve()
if verbose:
# The status of the solution is printed to the screen
print("Status:", LpStatus[prob.status])
# Each of the variables is printed with it's resolved optimum value
for v in prob.variables():
print(v.name, "=", v.varValue)
# The optimised objective function value is printed to the screen
print("MAX", value(prob.objective))
# Create dictionary to store the optimum game pieces at each scoring location, max score,
# whether score was optimized for a complete rocket, and number of null panels to use
optimum_positions = {v.name: v.varValue for v in prob.variables()}
optimum_positions.update(score=value(prob.objective), num_null_panels=num_null_panels,
optimize_rocket=optimize_rocket)
return optimum_positions
# Creates 6 different LP problems with different number of null panels and returns the highest-scoring solution
def find_optimal_null(datafile, teams, optimize_rocket='auto'):
best_score = 0
all_scores = []
for num_null_panels in range(0, 6 + 1):
optimums = create_problem(datafile, teams, num_null_panels, optimize_rocket)
all_scores.append(optimums['score'])
# If there are identical scores with different numbers of null panels, keep the one that uses the most
if optimums['score'] >= best_score:
best_score = optimums['score']
best_optimums = optimums
print('All the possible scores were: ', all_scores)
return best_optimums