Задача про драконьи яйца. Призываем программистов
easy

Задача про драконьи яйца. Призываем программистов

Уровень: начинающий.

Обещаем, что это последний материал про «Игру престолов». Зато это задача, которая решается с помощью программирования!

Фермер решил завести 20 драконов, чтобы продавать яйца по 50 серебряных за штуку. Рептилии (драконы же рептилии?) несут по два яйца в неделю, и каждую неделю все яйца продаются. С этих денег фермер покупает ещё по два дракона в неделю по 300 серебряных, чтобы увеличить свой доход. Но расходы велики: чтобы кормить и содержать питомцев, хозяин каждый день тратит 500 серебряных.

Фермер решил: если прибыли от рептилий так и не будет, через год он продаст их всех одной любительнице драконов, а если будет — продолжит дело. Как вы думаете, продаст он их или нет?

Как будем решать

Можно было бы составить сложную формулу, которая выводит зависимость прибыли от дня года, и начертить график. Там, где график пересёк бы ноль и пошёл вверх, мы бы увидели прибыль. Но формулы — это для математиков, а мы программисты. Мы напишем программу, которая симулирует экономику нашего фермера, перебирая день за днём. Сегодня потратил столько-то, завтра продал яйца и заработал столько-то, послезавтра потратил ещё столько-то… — и будем проверять, когда появится прибыль.

Тот же принцип используют учёные, когда делают симуляции — например, чёрных дыр или Большого взрыва: они задают исходные физические параметры своим объектам и дают компьютеру задание рассчитать каждую секунду их взаимодействия. Вот у нас как про чёрные дыры, только про драконов.

Задачу будем решать на JavaScript, потому что он у вас уже работает в браузере и вы можете спокойно повторить решение прямо сейчас, используя консоль (в меню «Вид» → «Разработчикам» → «Консоль»).

Шаг 1. Знакомство с функцией

Основную математику мы пропишем в функции: она будет заниматься симуляцией экономики фермера. Функция — это мини-программа внутри нашей программы: сначала мы пишем, что она будет делать, а потом вызываем её внутри программы и всё необходимое исполняется. В данном случае нам нужна программа внутри программы, чтобы иметь возможность выйти из неё, когда закончится год.

Чтобы задать функцию, которую мы назовём runDragonSimulator, используем такой код:

function runDragonSimulator() { }

Вначале идёт команда function, которая говорит компьютеру: мы хотим сделать новую функцию, которая будет называться runDragonSimulator. В круглых скобках пишутся параметры функции, оказывающие влияние на её работу. В нашем случае таких параметров нет, функция всегда будет действовать одинаково, поэтому в этих скобках сейчас ничего не указываем. А внутри фигурных скобок {} мы напишем тело функции — код, который выполнится, когда мы вызовем эту функцию.

Почему функция называется именно так — прочитайте в нашей статье о названии функций.

Когда компьютер встретит наименование функции, он поймёт, что нужно выполнить тот кусок кода, который стоит между фигурными скобками. Он его выполнит, а потом снова вернётся к программе — с того же места, где он прервался на функцию.

Например, заведём пару функций, которые будут выводить в консоль определённые слова:

function question() {

     console.log('Валар моргулис');

    // И можно выполнить какие угодно ещё команды, в любом количестве

}

function answer() {

    console.log('Валар дохаэрис');

    // Тут тоже можно выполнить любые дополнительные команды

}

Теперь если мы просто напишем названия этих функций, то компьютер выполнит те команды, которые мы описали в нашей функции:

    question();

    > 'Валар моргулис'

    answer();

    > 'Валар дохаэрис'

У функции есть свойство: её можно прервать в любой момент командой return. Когда компьютер в функции доходит до выполнения команды return, он прекращает осуществлять задачу ровно в этом месте и возвращается в главную программу.

Нам это поможет вот для чего. Так как мы не можем сказать точно, в какой момент доходы фермера от драконов превысят расходы, мы будем постоянно проверять, произошло это или нет. Если не произошло — работаем дальше, а если вышли в плюс по доходам — прерываем выполнение командой return и выводим данные о доходах.

Если схематично построить логику нашего решения, оно будет выглядеть так:

  • Считаем дни, сколько прошло всего и с начала месяца.
  • Ежедневно тратим деньги на корм и содержание драконов.
  • Каждую неделю продаём все яйца.
  • На полученные деньги каждую неделю покупаем ещё двух драконов.
  • Если после этого доходы всё ещё меньше расходов — возвращаемся в первый пункт, в противном случае прерываем подсчёты и подводим итоги: пишем, сколько мы заработали и сколько времени на это ушло.

Шаг 2. Установка переменных

Переменные — это ячейки памяти компьютера, где будут храниться нужные нам данные. Нам понадобятся переменные для дохода и расходов, для общего количества дней и для подсчёта каждого седьмого дня, который приносит нам доход.

Переменные в языке JavaScript задаются словами var или let. У них есть разница в видимости, сейчас она нас не волнует, но в будущем о них поговорим. Для этого примера используем var:

// сюда мы будем складывать наш общий доход и расход
var margin, expense;
// переменная поможет нам отследить седьмой день, когда снесутся все драконы и мы продадим все яйца. Пока ничего не началось, это считается нулевым днём.
var day = 0;
// считаем количество дней всего, один год — это 365 дней
var dayZ = 0;

Теперь задаём количество драконов в самом начале и стартовые значения дохода и расхода:

// число драконов на старте — 20
var group = 20;
// сколько яиц нам принесли все драконы за неделю, в самом начале пока — 0
var eggs = 0;
// устанавливаем стартовые цифры дохода и расхода на первый день работы
margin = 0;
expense = 500;

Весь основной код мы поместим в нашу функцию:

function runDragonSimulator() {
   // тут будет наш код
}

Шаг 3. Цикл

Основное, что нам нужно будет делать всё время, — выполнять код до тех пор, пока не сработает наше условие, что доход больше расхода. Для этого используем новый цикл — while:

while ( условие ) { команды }

Смысл такой: пока условие верное, команды выполняются раз за разом. После каждой отработки всех команд цикл возвращается в начало и снова проверяет — выполняется ли до сих пор условие. Если да, снова делаем все команды, если нет — цикл на этом прекращается.

Мы поставим такое условие: пусть всё работает, пока доходы меньше расходов, а мы посмотрим, что настанет раньше — пройдёт один год или мы выйдем в плюс:

while (margin < expense) {
   // тут будет основной код программы
}

Шаг 4. Подсчёты

Началась ежедневная рутина: подсчёт дней, понедельный и общий, и постоянные траты на корм и уход за драконами.

Чтобы увеличить количество прошедших дней на единицу, можно использовать привычную команду day = day + 1. Она берёт старое значение day, прибавляет к нему единицу и результат помещает снова в day. А можно сделать изящнее:

day += 1;

Команда += 1 увеличивает значение нашей переменной на единицу. Если бы мы написали day +=3, то это бы увеличило значение day на 3.

Что у нас происходит каждый день: меняется текущий день недели, возрастает общее количество прошедших дней, тратим 500 серебряных на содержание драконов:

day += 1;

dayZ += 1;

expense += 500;

Теперь надо проверить, вдруг сегодня уже седьмой день, — и тогда мы соберём по два яйца с каждого дракона, продадим их и купим ещё рептилий:

// каждый седьмой день нам приносит доход, это значит:
if (day == 7) {
  // все драконы несут за неделю по два яйца
  eggs += group * 2;
  // берём наш доход и увеличиваем его на прибыль от продажи всех яиц, собранных за неделю
  margin += eggs * 50;
  //каждую неделю покупаем два дракона по 300 серебряных…
  expense += 2 * 300;
  // …это увеличивает общее количество рептилий
  group += 2;
  // все яйца распродали, начинаем сначала
  eggs = 0;
  // начинаем отсчитывать дни заново
  day = 0;
}

Мы увеличиваем размер нашего дохода на ту сумму, которую нам принесёт продажа яиц, а затем обнуляем количество прошедших дней с начала недели: седьмой день закончился, начинаем отсчёт сначала.

Шаг 5. Проверки

Теперь надо проверить, вдруг прошёл уже один год и общая сумма наших доходов до сих пор не превысила все наши расходы? Если так, то сообщаем об итогах эксперимента и останавливаем выполнение функции:

// если прошёл год, а проект так и не взлетел (хехех) — останавливаемся и считаем убытки
if ((dayZ == 356) && ((margin - expense) < 0)) {
  // выводим сообщение о доходах и расходах за этот год
  console.log('Драконы за год так и не принеcли вам денег, милорд. Ваши убытки за это время составили ' + (expense - margin) + ' c.');
  // останавливаем функцию и больше ничего не вычисляем
  return;
}

Но что будет, если наш цикл однажды закончится сам? Речь про условие while (margin < expense).

Если однажды это условие не выполнится, это значит, что доходы перестали быть меньше расходов, то есть мы вышли в плюс. Тогда нужно вывести количество дней, сколько у нас ушло на это, а также прибыль, которую мы получили:

console.log('За ' + dayZ + ' дней вы вышли в плюс. Всего вы потратили ' + expense + ' и заработали ' + margin + ' c. Первая прибыль: ' + (margin - expense));

Собираем всё

Все части программы у нас уже есть. Собираем готовый код:

// сюда мы будем складывать наш общий доход и расход
var margin, expense;
// переменная поможет нам отследить седьмой день, когда все драконы снесут яйца
var day = 0;
// считаем количество дней всего, один год — это 365 дней
var dayZ = 0;
// количество драконов, на старте — 20
var group = 20;
// сколько яиц нам принесли все рептилии за неделю, в самом начале пока — 0
var eggs = 0;
// устанавливаем стартовые цифры дохода и расхода на первый день работы
margin = 0;
expense = 500;
// чтобы иметь возможность прекратить подсчёты, когда пройдёт один год, поместим все наши вычисления в функцию
// объявляем функцию с названием runDragonSimulator
function runDragonSimulator() {
  // пока расходы превышают доходы — работаем
  while (margin < expense) {
    // наступил новый день из семи
    day += 1;
    // и сразу считаем общее количество дней
    dayZ += 1;
    // каждый день мы тратим 500 серебряных…
    expense += 500;
    // каждый седьмой день нам приносит доход, это значит:
    if (day == 7) {
      // все драконы несут за неделю по два яйца
      eggs += group * 2;
      // берём наш доход и увеличиваем его на доход от продажи всех яиц, собранных за неделю
      margin += eggs * 50;
      //каждую неделю покупаем два дракона по 300 серебряных…
      expense += 2 * 300;
      // …это увеличивает общее количество рептилий
      group += 2;
      // все яйца распродали, начинаем сначала
      eggs = 0;
      // отсчитываем дни заново
      day = 0;
    }
    // если прошёл год, а проект так и не взлетел — останавливаемся и считаем убытки
    if ((dayZ == 356) && ((margin - expense) < 0)) {
      // выводим сообщение о доходах и расходах за этот год
      console.log('Драконы за год так и не принеcли вам денег, милорд. Ваши убытки за это время составили ' + (expense - margin) + ' c.');
      // останавливаем функцию и больше ничего не вычисляем
      return;
    }
  }
  // если мы всё-таки вышли из цикла, значит доходы превысили расходы — выведем это на экран
  console.log('За ' + dayZ + ' дней вы вышли в плюс. Всего вы потратили ' + expense + ' и заработали ' + margin + ' с. Первая прибыль: ' + (margin - expense));
}
// запускаем функцию с расчётами
runDragonSimulator();

Обратите внимание: сначала мы создали функцию, описали все её ветки и логику. Но когда мы её описываем, она ещё не работает. Мы как бы задали правила игры, но саму игру не запустили. И только на последней строке кода мы говорим runDragonSimulator(); — и вот тогда программа действительно активируется и выполняет всё, как мы её просили.

Такую программу можно доработать под себя и использовать уже для оценки реальных проектов — насколько они рентабельны и какие нужны условия для того, чтобы они стали прибыльными.

Любите такие задачи? Подойдите поближе
Внизу кнопка, при нажатии на нее вы попадете на витрину курсов «Практикума» с нуля. Выбираете там то, что вам близко, и погружаетесь в профессию. Через год-полтора вы работаете в какой-нибудь ИТ-компании. И там вы решаете подобные задачи, но уже за деньги. Старт бесплатно.
Начать бесплатно
Любите такие задачи? Подойдите поближе Любите такие задачи? Подойдите поближе Любите такие задачи? Подойдите поближе Любите такие задачи? Подойдите поближе
Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
easy