-
Notifications
You must be signed in to change notification settings - Fork 0
/
moveFunctions.py
375 lines (321 loc) · 17.1 KB
/
moveFunctions.py
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# contains functions for running move phases, retreat phases, and build phases
from boardSetup import territories as territories
########################### Move phase input functions ############################
def validMove(terrs, startPoint, endPoint, unitType): #returns whether the selected unit can move from start to end point
if startPoint not in terrs or endPoint not in terrs: #checks to see that start and end points are real
return False
elif endPoint not in terrs[startPoint]["borders"]: #checks to see if the given end point borders the start point
return False
if unitType == "army": #checks to see if the unit type can move to the end point
if terrs[endPoint]["type"] == "sea":
return False
elif unitType == "fleet":
if terrs[endPoint]["type"] == "land":
return False
if terrs[startPoint]["type"] == "coast" and terrs[endPoint]["type"] == "coast": #checks edge case: can navy move along coast?
for connectingSea in terrs:
if terrs[connectingSea]["type"] == "sea" and startPoint in terrs[connectingSea]["borders"] and endPoint in terrs[connectingSea]["borders"]:
return True
return False
#TODO check for mult coast terrs
return True
def inputUserMove(inputOrder, terrs, nation, turnMoves, nationality): #Adds user input move to turnMoves dict/list
#input order cleanup: - (a bit clunky at the moment but it kind of works)
order = (inputOrder.lower()).split()
try:
if order[0] in ("a", "army", "f", "fleet"):
del order[0]
order[1] #fails if the list has less than 2 remaining items
if len(order) > 2:
if order[2] == "to":
del order[2]
except IndexError:
print("\t\tInvalid move detected.")
return
moveType = ''
moveTargetStart = ''
moveTargetEnd = ''
unit = order[0]
convoyedMove = False
fleetMCTMove = False
#checks for valid user unit location
if unit not in nation:
print("\t\tNo user unit found in " + str(unit))
return
if unit in turnMoves:
print("\t\tOrder already exists for " + unit + "; previous order has been overwritten")
unitType = nation[unit]["type"]
#sorts input into move types
orderType = order[1]
if orderType in ("move", "moves", "attack", "attacks", "to", "m", ">"):
moveType = 'move'
try:
moveTargetEnd = order[2]
except IndexError:
print ("\t\tMove format not recognized. Try again.\n")
return
#Checks if the target is a multiple coast territory
if moveTargetEnd in ["bul",'spa',"stp"] and unitType == "fleet":
try:
unitCoast = order[3]
except:
print("\t\tPlease specify a coast for this fleet to move to.")
return
if unitCoast in territories[moveTargetEnd]["coasts"] and unit in territories[moveTargetEnd].get(unitCoast + " borders", []):
fleetMCTMove = True
else:
print("\t\tPlease specify a valid coast for this fleet to move to.")
return
#move via convoy
if "via" in order and "convoy" in order:
convoyedMove = True
elif orderType in ("support", "supports", "s"):
moveType = 'support'
if len(order) > 4:
if order[4] not in terrs or order[2] not in terrs:
print("\t\tSupport target start/end not recognized. Try again.\n")
return
moveTargetStart = order[2]
moveTargetEnd = order[4]
else:
if order[2] not in terrs:
print("\t\tSupport target not recognized. Try again.\n")
return
moveTargetEnd = order[2]
elif orderType in ("convoy", "convoys", "c"):
moveType = 'convoy'
if len(order) > 4:
if order[4] not in terrs or order[2] not in terrs:
print("\t\tConvoy target start/end not recognized. Try again.")
return
moveTargetEnd = order[4]
moveTargetStart = order[2]
else:
print("\t\tConvoy order format not recognized. Try again with the format: unit convoys A to B")
return
elif orderType in ("hold", "holds", "h"):
moveType = 'hold'
moveTargetEnd = order[0]
else:
print("\t\tNo move type recognized")
return
try:
moveTargetName = terrs[moveTargetEnd]["name"]
except KeyError:
print ("\t\tMove target location not recognized. Try again.\n")
return
#checks for a valid move #TODO amend for convoyed
if not validMove(terrs, unit, moveTargetEnd, unitType) and moveType not in ("convoy", "hold") and not convoyedMove:
print("\t\tInvalid move - %s in %s cannot %s %s\n" % (unitType,terrs[order[0]]["name"],moveType,moveTargetName))
return
elif len(order) > 4 and not convoyedMove:
if moveType == "convoy" and unitType == "army":
print("\t\tArmies can't convoy units. Try again.\n")
return
print("\t\tValid move - %s in %s %s %s to %s\n" % (unitType,terrs[order[0]]["name"],moveType,terrs[moveTargetStart]["name"],moveTargetName))
elif convoyedMove:
if unitType == "fleet":
print("\t\tFleets can't be convoyed. Try again.\n")
return
if terrs[order[0]]["type"] != "coast" or terrs[moveTargetEnd]["type"] != "coast":
print("\t\tConvoys may only happen from one coastal territory to another. Try again.\n")
return
print("\t\tValid move - %s in %s moves via convoy to %s\n" % (unitType,terrs[order[0]]["name"],moveTargetName))
else:
print("\t\tValid move - %s in %s %s %s\n" % (unitType,terrs[order[0]]["name"],moveType,moveTargetName))
#adds move dictionary of unit to turnMoves list
turnMoves[unit] = {
'nation' : nationality,
"unit type" : unitType,
"order" : moveType,
'outcome' : "undecided",
"dislodge status" : "undecided"
}
#movetype-dependent optional keys
if moveType == "support":
if moveTargetStart !='':
turnMoves[unit]["support type"] = 'move support'
else:
turnMoves[unit]["support type"] = 'hold support'
if moveType in ["move", "support","convoy"]:
turnMoves[unit]['target end'] = moveTargetEnd
if moveType == "convoy" or (moveType == "support" and turnMoves[unit]["support type"] == "move support"):
turnMoves[unit]['target start'] = moveTargetStart
if convoyedMove:
turnMoves[unit]['move type'] = "via convoy"
if fleetMCTMove:
turnMoves[unit]['coast'] = unitCoast
return unit
def getUserMoves(terrs, nation, turnMoves, nationality): #Prompts user for all their move inputs and adds them to turnMoves list
unassignedUnits = set()
for unit in nation:
unassignedUnits.add(unit)
while len(unassignedUnits) > 0:
unAssUnitsStr = ''
for unit in unassignedUnits:
unAssUnitsStr += (str(nation[unit]["type"]) + ' in ' + str(terrs[unit]["name"]) + " (" + unit + "), ")
if nation[unit].get("coast","") != "": #sloppy code here
unAssUnitsStr += nation[unit].get("coast","") + " coast, "
unAssUnitsStr = unAssUnitsStr[:-2]
print("\tUnassigned user units: " + unAssUnitsStr + ". Enter the order \"hold all\" to hold all remaining units")
userMove = input("\tEnter order:")
if userMove == "hold all":
for unit in unassignedUnits:
inputUserMove(unit + " h", terrs, nation, turnMoves, nationality)
break
move = inputUserMove(userMove, terrs, nation, turnMoves, nationality)
if move in unassignedUnits:
unassignedUnits.remove(move)
print("\t\tAll unit moves submitted")
########################### Move phase output functions ############################
def movePhaseOutput(movelistAdj, nationalityList, inputNation): #write movelist output to new gamestate after adjudicator runs; write to terminal
outputList = {}
dislodgedList = {}
for unit in movelistAdj:
fullName = territories[unit]["name"]
nation = movelistAdj[unit]["nation"]
if nation != inputNation: #this should only sort moves from the inputNation into the output move lists
continue
nationality = nationalityList[nation][nation]
unitType = movelistAdj[unit]["unit type"]
order = movelistAdj[unit]["order"]
outcome = movelistAdj[unit]["outcome"]
dislodged = movelistAdj[unit]["dislodge status"]
#not necessary: #TODO remove
#del movelistAdj[unit]["order"]
#del movelistAdj[unit]["outcome"]
#del movelistAdj[unit]["dislodge status"]
#Breaks loop if movelistAdj has not been fully adjudicated
if outcome == "undecided":
print("ERROR -- " + fullName + "outcome still undecided")
return {},{}
elif dislodged == "undecided":
print("ERROR -- " + fullName + "dislodge status still undecided")
return {},{}
#removes dislodged units to separate list
if dislodged == "dislodged":
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' has been dislodged')
dislodgedList[unit] = {'type' : unitType, "dislodging attacker" : movelistAdj[unit]["dislodging attacker"]}
continue
if order == "move":
if outcome == "moves":
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' successfully moves to ' + territories[movelistAdj[unit]["target end"]]["name"])
outputList[movelistAdj[unit]["target end"]] = {'type' : unitType}
else:
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' fails move to ' + territories[movelistAdj[unit]["target end"]]["name"])
outputList[unit] = {'type' : unitType}
elif order == "hold":
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' holds')
outputList[unit] = {'type' : unitType}
elif order == "convoy": #TODO -- fill out convoy information given to terminal
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' convoys')
outputList[unit] = {'type' : unitType}
elif order == "support":
sType = movelistAdj[unit]["support type"]
moveEnd = movelistAdj[unit]["target end"]
if sType == "move support":
moveStart = movelistAdj[unit]["target start"]
if outcome == "given":
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' supports ' + territories[moveStart]["name"] + " move into " + territories[moveEnd]["name"])
else:
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' support is cut for '+ territories[moveStart]["name"] + " move into " + territories[moveEnd]["name"])
elif sType == "hold support":
if outcome == "given":
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' supports ' + territories[moveEnd]["name"])
else:
print('\t' + nationality + ' ' + unitType + ' in ' + fullName + ' support is cut for ' + territories[moveEnd]["name"])
outputList[unit] = {'type' : unitType}
return outputList, dislodgedList
########################### Dislodge phase functions ############################
def inputUserDislodge(unit, unitDict, allExistingUnits):
print('\t\t' + unitDict["type"] + " in " + territories[unit]["name"] + " -- retreat to where? If unit cannot retreat anywhere, enter \'disband\'")
def targetInExistingUnits(target):
for country in allExistingUnits:
if target in allExistingUnits[country].keys():
return True
return False
while True: #keep asking for user input until a valid retreat target is provided
dislodgeTarget = input('\t\t')
if dislodgeTarget in territories.keys():
if not validMove(territories, unit, dislodgeTarget, unitDict["type"]):
print("\t\tInvalid; " + unitDict["type"] + " in " + territories[unit]["name"] + " cannot retreat to " + territories[dislodgeTarget]["name"] + ". Try again")
elif targetInExistingUnits(dislodgeTarget):
print("\t\tInvalid; a unit already exists in " + territories[dislodgeTarget]["name"] + ". Try again")
elif dislodgeTarget == unitDict["dislodging attacker"]:
print("\t\tInvalid; a dislodged unit cannot swap places with the dislodging attacker. Try again")
else:
print('\t\t' + unitDict["type"] + " in " + territories[unit]["name"] + " retreats to " + territories[dislodgeTarget]["name"])
#TODO:pop out unitDict["dislodging attacker"]?
return dislodgeTarget
elif dislodgeTarget == "disband":
print('\t\t' + unitDict["type"] + " in " + territories[unit]["name"] + " disbands.")
return ''
else:
print("\t\tTarget territory not recognized; try again")
def getUserDislodges(dislodgeList, allExistingUnits): #gets user input for a single nation's dislodgeList dislodge targets
for unit in dislodgeList.keys():
dislodgeList[unit]["dislodge target"] = inputUserDislodge(unit, dislodgeList[unit], allExistingUnits)
return dislodgeList
########################### Build/Disband phase functions ############################
def build(terrs, allUnits, nation, buildCount):
while buildCount > 0:
buildOrder = input("\t" + str(buildCount) + " build(s) remaining. Please specify a build order (enter \"end builds\" if you have no more valid builds to make):\n\t\t")
print()
#sanitize buildOrder input
if buildOrder == 'end builds':
break
try:
buildOrder = (buildOrder.lower()).split()
unitType = buildOrder[0]
unitArea = buildOrder[1]
except:
print("\tOrder not recognized. Please format build order as: unittype area, e.g fleet mar")
continue
if unitType == "a":
unitType = 'army'
elif unitType == "f":
unitType = 'fleet'
if unitType not in ["army", "fleet"] or unitArea not in terrs.keys():
print("\tOrder not recognized. Please format build order as: unittype area, e.g fleet mar")
continue
#check for occupied build territory
alreadyOccupied = False
for anyNation in allUnits.keys():
if unitArea in allUnits[anyNation].keys():
alreadyOccupied = True
if alreadyOccupied:
print("\tYou cannot build on an occupied territory.")
continue
#check for valid fleet build
if unitType == "fleet" and terrs[unitArea]["type"] == "land":
print("\tYou cannot build a fleet on land, dumb dumb.")
continue
stpCoast = ''
if unitType == "fleet" and unitArea == "stp":
stpCoast = input("\tBuild fleet on north or south coast? ")
if stpCoast not in ["north","south"]:
print("\tCoast not recognized")
continue
if terrs[unitArea]["supplyCenter"] and terrs[unitArea].get("homeCenter", '') == nation and terrs[unitArea]["country"] == nation:
print("\t\t" + (str(unitType)).capitalize() + " built in " + str(terrs[unitArea]["name"]))
allUnits[nation][unitArea] = {"type" : unitType}
if stpCoast != '':
allUnits[nation][unitArea]["coast"] = stpCoast
else:
#invalid build
print("\tYou cannot build a(n) " + str(unitType) + " in " + str(terrs[unitArea]["name"]))
continue
buildCount -= 1
return allUnits
def disband(allUnits, nation, buildCount):
while buildCount < 0:
disbandOrder = (input("\t" + str(abs(buildCount)) + " disband(s) remaining. Please specify a unit to disband:\n\t\t")).lower()
print()
if disbandOrder in allUnits[nation].keys():
print("\t\t" + (str(allUnits[nation][disbandOrder]["type"])).capitalize() + " disbanded in " + str(territories[disbandOrder]["name"]))
allUnits[nation].pop(disbandOrder)
else:
print("\tDisband order not recognized. Please specify a unit to disband (don't include unit type e.g. army/fleet)")
continue
buildCount += 1
return allUnits