Daily Challenge #271 - Simulate Population Growth

In a small town the population is p0 = 1000 at the beginning of a year. The population regularly increases by 2 percent per year and moreover 50 new inhabitants per year come to live in the town. How many years does the town need to see its population greater or equal to p = 1200 inhabitants?

Note: Always keep the number of inhabitants as an integer. Round up when necessary.

At the end of the first year there will be:
1000 + 1000 * 0.02 + 50 => 1070 inhabitants

At the end of the 2nd year there will be:
1070 + 1070 * 0.02 + 50 => 1141 inhabitants

At the end of the 3rd year there will be:
1141 + 1141 * 0.02 + 50 => 1213

It will need 3 entire years to get to 1200 folks.


Parameters:
p0, percent, aug (inhabitants coming or leaving each year), p (population to surpass)

the function nb_year should return n number of entire years needed to get a population greater or equal to p.

aug is an integer, percent a positive or null number, p0 and p are positive integers (> 0)

Examples:
nb_year(1500, 5, 100, 5000) -> 15
nb_year(1500000, 2.5, 10000, 2000000) -> 10

Tests:
nbYear(1500, 5, 100, 5000)
nbYear(1500000, 2.5, 10000, 2000000)
nbYear(1500000, 0.25, 1000, 2000000)

Good luck!

This challenge comes from g964 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!

Posted on by:

dev.to staff

The hardworking team behind dev.to ❤️

Discussion

Using an iterative style in Clojure. I think an iterative style is best suited for a sequential problem like this, and Clojure felt like a good fit.

(defn nb_year [p0 percent aug p]
(count
(take-while
#(<= % p)
(iterate
#(Math/ceil (+ % (* % (/ percent 100)) aug))
p0))))


This is a 7kyu question in codewar but it's a bit tricky.

I remember I solved it after tens of submissions, because one or two tests were failed for some reason.

Turned out that I should have to deal with integers more carefully.

Here is an answer for ruby version:

def nb_year(p0, percent, aug, p)
year = 0
while p0 < p
year += 1
p0 = spawn(p0, percent, aug)
end
year
end

def spawn(p, percent, aug)
(p + (p * percent / 100).floor + aug)
end


Javascript

Using a generator function to calculate the successive years

function nbYear(p0, percent, aug, p) {
let i, population = pop(p0, percent / 100, aug);
for (i = 0; population.next().value < p; i++);
return i;
}

function * pop(p, r, ann) {
while (true) {
yield p;
p += p * r + ann;
}
}


If you're using generators, go wild :v

const chain = (...fns) => x => fns.reduce((x, fn) => fn(x), x)
const count = it => {
let i = 0
for (_ of it) i++
return i
}
const takeWhile = fn => function * takeWhile(it) {
for (x of it) {
if (!fn(x)) break
yield x
}
}

function * pop(p, r, ann) {
while (true) {
yield p
p += p * r + ann
}
}

const nbYear = (p0, percent, aug, p) => chain(
takeWhile(x => x < p),
count,
)(pop(p0, percent / 100, aug))


or at least

function nbYear(p0, percent, aug, p) {
const population = pop(p0, percent / 100, aug)
let i = 0
for (pop of population) {
if (pop > p) return i
i++
}
}


(even though the following is actually shorter)

function nbYear(p0, percent, aug, p) {
const population = pop(p0, percent / 100, aug)
let i = 0
while (population.next().value < p) i++
return i
}


Here is my solution with PHP code snippets:

function nbYear($p0,$percent, $aug,$p) {
$percent =$percent / 100;
$entry = 0; while ($p0 < $p) {$p0 = $p0 +$p0 * $percent +$aug;
$entry += 1; } return$entry;
}


import Data.Maybe (fromMaybe)
import Data.List (findIndex)

nbYear :: Int -> Double -> Int -> Int -> Int
nbYear p0 growth aug pGoal = fromMaybe 0 $maybeYears where maybeYears = findIndex (>= pGoal)$ p0 : nbYear' p0
nbYear' p =
let p' = (ceiling \$ fromIntegral p * (1 + growth')) + aug
in p' : nbYear' p'
growth' = growth / 100


General idea of the solution is to generate an infinite list of population growth per year with the recursive function nbYear'. Since Haskell is lazy, I can then use this infinite list to find the first item in the list, which exceeds the goal population.

const nbYear = (p0,percent,aug,final)=>
p0 < final ? 1+nbYear(p0 + p0 *(percent/100)+aug ,percent,aug,final) : 0;


const nb_year = (p0, percent, aug, p) => p <= p0
? 0
: 1 + nb_year(p0 * (percent / 100) + aug + p0, percent, aug, p)


def nb_year(p0, percent, aug, p,  year = 0):
if (p0 >= p):
return year
else:
year += 1
pop = p0 + p0 * (percent/100) + aug
return nb_year(pop, percent, aug, p, year)