## DEV Community is a community of 865,621 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

dev.to staff

Posted on

# Daily Challenge #192 - Can you Survive the Zombies?

### Setup

Unfortunately, you have found yourself in a difficult situation. You have injured your leg and are unable to walk. A number n of zombies are shuffling towards you, intent on eating your brains. Luckily, you've got your trusty rifle.

The zombies will start at a range of r meters. They will move at 0.5m per second. Each second, you shoot one zombie, which depletes your ammo reserve a by 1 each shot. The remaining zombies shamble forward. Since you're a good shot but also debilitated, there's a 5% chance you might miss.

If any of the zombies manage to reach 0 meters, you get eaten and lose. If you run out of ammo, you'll also get eaten. Ignore any time that would be spent reloading.

Write a function that accepts the total number of zombies n, a range in meters r, and the number of bullets you have a.

If you shoot all the zombies, return "You shot all X zombies." If you get eaten before killing all the zombies, and before running out of ammo, return "You shot X zombies before being eaten: overwhelmed." If you run out of ammo before shooting all the zombies, return "You shot X zombies before being eaten: ran out of ammo." (If you run out of ammo at the same time as the remaining zombies reach you, return "You shot X zombies before being eaten: overwhelmed.".)

### Example

zombie_shootout(3, 10, 10) => "You shot all 3 zombies."

### Tests

zombie_shootout(100, 8, 200)
zombie_shootout(50, 10, 8)

Good luck! (I think you're going to need it.)

This challenge comes from Captain_Howdy on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

## Discussion (10)

SavagePixie

Something like this should do the trick in Elixir. I'm just doubling the range and subtracting one on each iteration to avoid issues with floats and because working with integers is faster.

defmodule ZombieWars do
def zombie_shootout(n, r, a), do: _zombie_shootout(n, r * 2, a, n)

defp _zombie_shootout(0, _, _, s) do
"You shot all #{s} zombies."
end
defp _zombie_shootout(n, 0, _a, s) do
"You shot #{s - n} zombies before being eaten: overwhelmed."
end
defp _zombie_shootout(n, _r, 0, s) do
"You shot #{s - n} zombies before being eaten: ran out of ammo."
end
defp _zombie_shootout(n, r, a, s) do
if Enum.random(1..20) == 1 do
_zombie_shootout(n, r - 1, a - 1, s)
else
_zombie_shootout(n - 1, r - 1, a - 1, s)
end
end
end
Craig McIlwrath

The 5% is throwing me off. There's no way to compute a certain live/die verdict when a probability. A singular zombie could be 2000 away and you get really unlucky and miss all shots.

Maybe you mean every 20th shot you miss? Or create an impure function that returns a different value depending on random chance from the probability? Or something else?

Amin

I believe it would mean something like that in Haskell (I'm not really confortable enough with Monad so there is room to improvements).

import System.Random (getStdGen, randomR)

hasHit :: IO Bool
hasHit = do
g <- getStdGen
return \$ (>5) \$ fst \$ randomR (1 :: Int, 100) g

main :: IO ()
main = do
h <- hasHit
print \$ h -- True/False

And I would use this on each shot. Meaning I have 5/100 chance of missing my target. That is what I understood but I may be wrong on this one.

Kyle Jones

This was the problem that I couldn't work out either - the tests become flaky and unreliable. Seems at odds with the rest of the scenario

lusen / they / them 🏳️‍🌈🥑

Python, where of course the expected number of zombies killed is a maximum and sometimes the function says less were killed.

import random

# n: number of zombies
# r: range in meters
# a: number of bullets
def zombie_shootout(n, r, a):
zombie_speed = 0.5 # m/s
bullets_per_second = 1 # bullet/s
miss_rate = .05 # %

zombie_distance = r
number_zombies = n
number_bullets = a

while True:
#print(zombie_distance, number_zombies, number_bullets)
# if shoot all zombies:
if number_zombies <= 0:
return "You shot all %s zombies." % n

# if get eaten:
if zombie_distance <= 0.0:
return "You shot %s zombies before being eaten: overwhelmed." % (n - number_zombies)

# if run out of ammo:
if number_bullets <=  0:
return "You shot %s zombies before being eaten: ran out of ammo." % (n - number_zombies)

zombie_distance -= zombie_speed
number_bullets -= bullets_per_second

zombie_killed = 1
if random.randint(1,100) > 95:
zombie_killed = 0
number_zombies -= zombie_killed

print(zombie_shootout(3, 10, 10), "\nYou shot all 3 zombies.\n")
print(zombie_shootout(3, 3, 3), "\nYou shot all 3 zombies.\n")
print(zombie_shootout(3, 4, 4), "\nYou shot all 3 zombies.\n")
print(zombie_shootout(10, 2, 30), "\nYou shot 4 zombies before being eaten: overwhelmed.\n")
print(zombie_shootout(10, 30, 4), "\nYou shot 4 zombies before being eaten: ran out of ammo.\n")
Kyle Jones

In Python

import sys
import random

def zombie_shootout(num_of_zombies, distance, num_of_bullets):
'''
Work out if you survive the zombie's assault
'''
zombie_speed = 0.5
num_of_zombies_shot = 0
probability_of_missing = 0.05
num_of_zombies_remaining = num_of_zombies

for bullet in range(num_of_bullets):
if distance == 0:
return "You shot {} zombie(s) before being eaten: overwhelmed.".format(
num_of_zombies_shot)
if num_of_zombies_remaining == 0:
return "You shot all {} zombies.".format(
num_of_zombies)

distance -= zombie_speed
shot_chance = random.randint(0, 100)

if shot_chance >= probability_of_missing:
num_of_zombies_shot += 1
num_of_zombies_remaining -= 1
return "You shot {} zombie(s) before being eaten: ran out of ammo.".format(
num_of_zombies_shot)

if len(sys.argv) > 3:
print(zombie_shootout(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3])))

R I P 3 F R A M E S

here's my solution in Python

from random import choices

def zombie_shootout(zombies, distance, ammo):
population = [0,1]
distribution = [0.05, 0.95]
zombies_killed = 0

for i in range(distance*2):
if ammo == 0 and zombies_killed < zombies:
print("You killed %d zombies before being eaten: out of ammo" % zombies_killed)
return

if zombies_killed == zombies:
print("You killed %d zombies and survived" % zombies_killed)
return
hit = choices(population, distribution)
if not hit:
ammo -= 1
print(hit)
else:
ammo -= 1
zombies_killed += 1

if zombies_killed < zombies:
print("You killed %d zombies before being eaten: overwhelmed" % zombies_killed)
Vidit Sarkar

C++

// takes number of bullets and percentage of missing as input
// i.e. 5 for 5% chance of missing
// this functions guarantees that the given percentage of total bullets will miss zombies
vector<bool> hitOrMiss(int numBullets,int percentage){
vector<bool> hits(numBullets,true);
for(int i=0;i<numBullets*percentage/100;i++){
hits[i] = false;
}
shuffle(hits.begin(),hits.end(),default_random_engine(time(0)));
return hits;
}

void zombie_shootout(int totalZombie, float range, int numBullets){
int tempTotalZombie = totalZombie; // holds the total number of zombies
int tempNumBullets = numBullets; // holds the total number of bullets
vector<bool> hits = hitOrMiss(numBullets,5);

while(numBullets>0 && totalZombie > 0 && range > 0){
if(hits[numBullets-1]){
totalZombie--;
}
numBullets--;
if(totalZombie==0)
break;
range -= 0.5;
}

// If you shoot all the zombies
if(totalZombie == 0 && range > 0 && numBullets >= 0){
cout << "You shot all " << tempTotalZombie << " zombies.\n";
return;
}

// If you get eaten before killing all the zombies, and before running out of ammo
// or If you run out of ammo at the same time as the remaining zombies reach you
if(range == 0 && totalZombie > 0 && numBullets >= 0){
cout << "You shot " << tempTotalZombie-totalZombie << " zombies before being eaten: overwhelmed.\n";
return;
}

// If you run out of ammo before shooting all the zombies,
if(numBullets == 0 && totalZombie > 0){
cout << "You shot "<< tempTotalZombie-totalZombie <<" zombies before being eaten: ran out of ammo.\n";
return;
}
}
Nijeesh Joshy • Edited on
MISS_PROBABILITY = 5

def hit?
rand(1..100) > MISS_PROBABILITY
end

"You shot all #{killed} zombies."
end

def got_eaten_message(killed)
"You shot #{killed} zombies before being eaten: overwhelmed."
end

def ran_out_of_ammo_message(killed)
"You shot #{killed} zombies before being eaten: ran out of ammo."
end

def zombie_shootout(n, r, a)
ran_out_of_ammo_message(0) if a < n
zombies_killed = 0
(r * 2).times do
return all_zombies_dead_message(zombies_killed) if n == zombies_killed
return ran_out_of_ammo_message(zombies_killed) if a == 0
a -= 1
if hit?
zombies_killed += 1
end
end
return got_eaten_message(zombies_killed) if zombies_killed < n
end

puts zombie_shootout(3, 10, 10)
puts zombie_shootout(100, 8, 200)
puts zombie_shootout(50, 10, 8)

Python

import random

n = int(input('Enter the number of Zombies: '))
r = float(input('Enter the range: '))
a = int(input('Enter the number of ammo: '))

def zombie_shootout(n,r,a):
n1 = n
for i in range(a):
if n == 0:
return "You shot all "+str(n1)+" zombies."
if r == 0:
return "You shot "+str(n1-n)+" zombies before being eaten: overwhelmed."
if a == 0:
return "You shot "+str(n1-n)+" zombies before being eaten: ran out of ammo."

x = random.randint(1,100)
if x <= 5:                      # Missed the shot
a -= 1
r -= 0.5
else:                           # Zombie Killed
a -= 1
n -= 1
r -= 0.5

return "You shot "+str(n1-n)+" zombies before being eaten: overwhelmed."

print(zombie_shootout(n,r,a))