loading...
Cover image for Daily Challenge #271 - Simulate Population Growth

Daily Challenge #271 - Simulate Population Growth

thepracticaldev profile image dev.to staff ・1 min read

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:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

pic
Editor guide
 

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;
}
 

Lazy Haskell goodness:

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)