Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Here is my code is about simulating a number of Risk battles. import sys import

ID: 3889227 • Letter: H

Question

Here is my code is about simulating a number of Risk battles.

import sys
import random
import time
import statistics as stats

def roll(attack_dice, defend_dice):
'''Carry out a roll for both sides
Return a tuple (attack_loss, defend_loss)'''
attack_roll = [] #Accumulates rolls of attacker's dice
for i in range(0, attack_dice): #Carry out attacker's rolls
attack_roll.append(random.randint(1, 6))
defend_roll = [] #Accumulates rolls of defender's dice
for i in range(0, defend_dice): #Carry out defender's rolls
defend_roll.append(random.randint(1, 6))
attack_roll.sort()
attack_roll.reverse() #Put attacker's rolls in descending order
defend_roll.sort()
defend_roll.reverse() #Put defender's rolls in descending order
attack_loss = 0 #This will count number of losees for attacker
defend_loss = 0 #Number of losses for defender
for i in range(0, len(defend_roll)): #Compare attacker's rolls with defender's
if attack_roll[i] > defend_roll[i]: #Defender loses if attacker's is higher
defend_loss = defend_loss + 1
else:
attack_loss = attack_loss + 1 #Else attacker loses (defender wins ties)
#print(attack_roll, defend_roll, attack_loss, defend_loss)
return attack_loss, defend_loss #Return a tuple with number losses for each player

def run_simulations(num_simulations, num_armies, attack_dice, defend_dice):
results = []
for i in range(num_simulations):
attacknum = num_armies
defendnum = num_armies
while attacknum > 1 and defendnum > 0: #Attacker needs at least 2 to continue
if attacknum > 3: #Check number of attacking armies
aroll = attack_dice #if > 3, roll all of attacker's dice
else:
aroll = 2 #Else attacker rolls 2 dice
if defendnum > 1: #Check number of defending armies
droll = defend_dice #if > 1, roll all of defender's dice (max is 2)
else:
droll = 1 #Else defender can only roll 1 die
result = roll(aroll, droll)
#Update number of armies for each player
attacknum = attacknum - result[0]
defendnum = defendnum - result[1]
#print("Attackers:", attacknum, "Defenders:", defendnum)
#Append number of attacker's armies at end of each simulation
#Assume defender has 0 armies (if attacker has 1 then defender won)
results.append(attacknum)
return results

def main(num_simulations):
num_armies = 10000 #Number of armies for both attacker and defender at outset
num_attack_dice = 3 #Number of dice for attacker when holding enough armies
num_defend_dice = 2 #Number of dice for defender when holding enough armies
  
#Carry out simulations
results = run_simulations(num_simulations, num_armies,
num_attack_dice, num_defend_dice)
#Print statistics
print(round(stats.mean(results), 2), round(stats.stdev(results), 2),
stats.median(results))

if __name__ == "__main__":
num_simulations = int(sys.argv[1])
start = time.time()
main(num_simulations)
elapsed_time = time.time() - start
print("Elapsed time: {}".format(elapsed_time))

I would like to use multiple processes is a bit more involved because you don't want to start a separate process for each simulation—in fact, you should use the number of processors available to the program. You can find the number of processors using multiprocessing.cpu_count(). The number of simulated battles is not likely to be evenly divisible by the number of processors—so one processor may have to do some additional simulations. For example, if you have 4 processors to run 50 simulations, three processors will do 12 simulations while one will do 14 simulations. You can determine how to apportion simulations among processors using integer division (num_simulations // num_processors) and modulo (num_simulations % num_processors).

Make a list of processes then start them in one loop and join them in another loop. Once again, you'll have to move the results from the queue into a list before printing the statistics (by the way, be sure your queue for this program is a multiprocessing queue).

Explanation / Answer

import sys
import random
import time
import statistics as stats
import multiprocessing as mp

def roll(attack_dice, defend_dice):
'''Carry out a roll for both sides
Return a tuple (attack_loss, defend_loss)'''
attack_roll = [] #Accumulates rolls of attacker's dice
for i in range(0, attack_dice): #Carry out attacker's rolls
attack_roll.append(random.randint(1, 6))
defend_roll = [] #Accumulates rolls of defender's dice
for i in range(0, defend_dice): #Carry out defender's rolls
defend_roll.append(random.randint(1, 6))
attack_roll.sort()
attack_roll.reverse() #Put attacker's rolls in descending order
defend_roll.sort()
defend_roll.reverse() #Put defender's rolls in descending order
attack_loss = 0 #This will count number of losees for attacker
defend_loss = 0 #Number of losses for defender
for i in range(0, len(defend_roll)): #Compare attacker's rolls with defender's
if attack_roll[i] > defend_roll[i]: #Defender loses if attacker's is higher
defend_loss = defend_loss + 1
else:
attack_loss = attack_loss + 1 #Else attacker loses (defender wins ties)
#print(attack_roll, defend_roll, attack_loss, defend_loss)
return attack_loss, defend_loss #Return a tuple with number losses for each player

def get_result(num_armies, attack_dice, defend_dice, que, i, num_simulations, num_procs):
for j in range(i+1, num_simulations+1, num_procs):
attacknum = num_armies
defendnum = num_armies
while attacknum > 1 and defendnum > 0: #Attacker needs at least 2 to continue
if attacknum > 3: #Check number of attacking armies
aroll = attack_dice #if > 3, roll all of attacker's dice
else:
aroll = 2 #Else attacker rolls 2 dice
if defendnum > 1: #Check number of defending armies
droll = defend_dice #if > 1, roll all of defender's dice (max is 2)
else:
droll = 1 #Else defender can only roll 1 die
result = roll(aroll, droll)
#Update number of armies for each player
attacknum = attacknum - result[0]
defendnum = defendnum - result[1]
que.put(attacknum)
#print("Attackers:", attacknum, "Defenders:", defendnum)
#Append number of attacker's armies at end of each simulation
#Assume defender has 0 armies (if attacker has 1 then defender won)

def run_simulations(num_simulations, num_armies, attack_dice, defend_dice, que):
results = []
processes = []
num_procs = mp.cpu_count()
for i in range(0, num_procs):
p = mp.Process(target=get_result, args=[num_armies, attack_dice, defend_dice, que, i, num_simulations, num_procs])
processes.append(p)
p.start()
for j in range(0, num_procs):
p.join()
while not que.empty():
results.append(que.get())
return results

def main(num_simulations):
que = mp.Queue()
num_armies = 10000 #Number of armies for both attacker and defender at outset
num_attack_dice = 3 #Number of dice for attacker when holding enough armies
num_defend_dice = 2 #Number of dice for defender when holding enough armies
  
#Carry out simulations
results = run_simulations(num_simulations, num_armies,
num_attack_dice, num_defend_dice, que)
#Print statistics
print(round(stats.mean(results), 2), round(stats.stdev(results), 2),
stats.median(results))

if __name__ == "__main__":
num_simulations = int(sys.argv[1])
start = time.time()
main(num_simulations)
elapsed_time = time.time() - start
print("Elapsed time: {}".format(elapsed_time))

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote