Question: I would like to make multiple processes is a bit more involved because you don't want to start a separate process for each simulationin fact,
I would like to make multiple processes is a bit more involved because you don't want to start a separate process for each simulationin 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 processorsso 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).
Here is my code.
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, 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)
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))
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
