Two bullet roulette

From Rosetta Code
Revision as of 20:35, 27 November 2020 by Wherrera (talk | contribs) (Created page with """" {{draft task}} # The following is supposedly a question given to mathematics graduates seeking jobs on Wall Street: A revolver handgun has a revolving cylinder with s...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

"""

Two bullet roulette is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
  1. The following is supposedly a question given to mathematics graduates seeking jobs on Wall Street:
   A revolver handgun has a revolving cylinder with six chambers for bullets.
   
   It is loaded with the following procedure:
       1. Check the first chamber to the right of the trigger for a bullet. If a bullet
          is seen, the cylinder is rotated one chamber clockwise and the next chamber
          checked until an empty chamber is found.
       2. A cartrige containing a bullet is placed in the empty chamber.
       3. The cylinder is then rotated one chamber clockwise.
   
   To randomize the cylinder's position, the cylinder is spun, which causes the cylinder
   to take a random position from 1 to 6 chamber rotations clockwise from its starting position.
   
   When the trigger is pulled the gun will fire if there is a bullet in position 0, which is just
   counterclockwise from the loading position.
   
   The gun is unloaded by removing all catriges from the cylinder.
   
   According to the legend, a suicidal Russian imperial military officer plays a game of 
   Russian roulette by putting two bullets in a six-chamber cylinder and pulls the trigger 
   twice. If the gun fires with a trigger pull, this is considered a succesful suicide.
   
   The cylinder is always spun before the first shot, but it may or may not be spun
   after putting in the first bullet and may or may not be spun after taking the first shot.
   Which of the following situations produces the highest probability of suicide?
   A. Spinning the cylinder after loading the first bullet, and spinning again
      after the first shot.
   B. Spinning the cylinder after loading the first bullet only.
   C. Spinning the cylinder after firing the first shot only.
   D. Not spinning the cylinder either after loading the first bullet or after
      the first shot or after the first shot.
   E. The probability is the same for all cases.
Task
  1. Run a repeated simulation of each of the above scenario, calculating the percentage of suicide with a randomization of the four spinning, loading and firing order scenarios.
  2. Show the results as a percentage of deaths for each type of scenario.
   Note: the true probabilities are 5/9, 7/12, 5/9, and 1/2. A correct program should produce
   results close enough to those to allow a correct response to the interview question.  
Reference
   Youtube video on the Russian 1895 Nagant revolver [[1]]


Python

<lang python>""" Russian roulette problem """ import numpy as np

class Revolver:

   """ simulates 6-shot revolving cylinger pistol """
   def __init__(self):
       """ start unloaded """
       self.cylinder = np.array([False] * 6)
   def unload(self):
       """ empty all chambers of cylinder """
       self.cylinder[:] = False
   def load(self):
       """ load a chamber (advance til empty if full already), then advance once """
       while self.cylinder[1]:
           self.cylinder[:] = np.roll(self.cylinder, 1)
       self.cylinder[1] = True
   def spin(self):
       """ spin cylinder, randomizing position of chamber to be fired """
       self.cylinder[:] = np.roll(self.cylinder, np.random.randint(1, high=7))
   def fire(self):
       """ pull trigger of revolver, return True if fired, False if did not fire """
       shot = self.cylinder[1]
       self.cylinder[:] = np.roll(self.cylinder, 1)
       return shot
   def LSLSFSF(self):
       """ load, spin, load, spin, fire, spin, fire """
       self.unload()
       self.load()
       self.spin()
       self.load()
       self.spin()
       if self.fire():
           return True
       self.spin()
       if self.fire():
           return True
       return False
   def LSLSFF(self):
       """ load, spin, load, spin, fire, fire """
       self.unload()
       self.load()
       self.spin()
       self.load()
       self.spin()
       if self.fire():
           return True
       if self.fire():
           return True
       return False
   def LLSFSF(self):
       """ load, load, spin, fire, spin, fire """
       self.unload()
       self.load()
       self.load()
       self.spin()
       if self.fire():
           return True
       self.spin()
       if self.fire():
           return True
       return False
   def LLSFF(self):
       """ load, load, spin, fire, fire """
       self.unload()
       self.load()
       self.load()
       self.spin()
       if self.fire():
           return True
       if self.fire():
           return True
       return False


if __name__ == '__main__':

   REV = Revolver()
   TESTCOUNT = 100000
   for (name, method) in [['load, spin, load, spin, fire, spin, fire', REV.LSLSFSF],
                          ['load, spin, load, spin, fire, fire', REV.LSLSFF],
                          ['load, load, spin, fire, spin, fire', REV.LLSFSF],
                          ['load, load, spin, fire, fire', REV.LLSFF]]:
       percentage = 100 * sum([method() for _ in range(TESTCOUNT)]) / TESTCOUNT
       print("Method", name, "produces", percentage, "per cent deaths.")

</lang>

Output:
Method load, spin, load, spin, fire, spin, fire produces 55.652 per cent deaths.
Method load, spin, load, spin, fire, fire produces 58.239 per cent deaths.
Method load, load, spin, fire, spin, fire produces 55.774 per cent deaths.
Method load, load, spin, fire, fire produces 50.071 per cent deaths.