Текст
                    nолнь,й КУРС.

(Е.л R ндч111t1АЮ\ЦИ~


ПОЛНЫЙ КУРС ДЛЯ НАЧИНАЮЩИХ ПРОГРАММИСТОВ OCHOBbl ПРОГРАММИРОВАНИЯ МОСКВА ИЗдАТЕЛЬСТВО АСТ
УДК ББК 004.43 32.973.26-018.1 Н 22 Книга «Основи на програмирането c}avaScript» на болгарском языке распространяется в соответствии с открытой лицензией CC-BY-SA (https:l/creativecommons.orgllicenses/by-sa/4.01). Книга доступна в электронном виде на официальном сайте: https:lljs-book.softuni.bg. Исходный код доступен по ссылке: https:llgithub.com/SoftUni/Programming-Basics-Book-}S-BG. Авторский коллектив: Бончо Вальков, Венцислав Петров, Димитар Далев, Елена Роглева, Джульетта Ата н асова, Захария Пехливанова, Здравко Костадинов, Ивелин Арнаудов, Кристиан Марьянов, Марти н Чаов, Николай Банкин, Никола й Костов, Павел Колев, Петр Иванов, Светлин Наков, Сти лян Кан галов, Кристиан Христов, Христо Минков. Наков, Светлин. Н22 JavaSc r ipt. Москва : Основы программиро в ания Издател ьство АСТ, 2025. - 480 с. / С. Наков [и др.]. : ил. - - (Полный курс для начинающих прог р аммистов). ISBN 978-5-17-162193-3. Данное пособ ие по программированию на современном высокоуров• невом мультипарадигменном языке редактора кода Visual Studio Code JavaScript с помощью продвинутого представляет собой тщательно структу­ рирова н ный и систематизированный сборник задач в области разработки программного обеспечения началь ного уров ня. Все задачи подробно разобраны и снабжены готовым решением на языке JavaScript. Это свое­ образный учебник для новичков, пока еще только ищущих свой путь в сфере и н формационных технологи й и желающих изучить основные конструкции языкaJavaScri pt для создания про граммно го кода. Благодаря изложен ному здесь материалу они получат представление о различных алгоритмах, что позволит им в дальнейшем решать любые задачи без привязки к опреде­ ленному языку программирования. И что важно : каждая рассматриваемая тема сопровождается конкретными примерами и подробно разобра н ными задачами, реше н ия которы х можно сразу же проверить в интерактивной судейской системе. Книга закладывает прочный фундамент практических навыков, без которы х обучение программированию не представляется возможным. УДКОО4.43 ББК 32.973.26-018.1 © Светлин Наков и колектив. 2018 г. Перевод на русский язык: ООО « Интеджер». ISBN 978-5-17-162193-З Издание на русском языке: ООО «Издательство АСТ».
Краткое содержание Предисловие ........................................................................................................................ 9 Глава 1. Начало работы в программировании ..................................................... 28 Глава 2.1. Простые вычисления ................................................................................. 59 Глава 2.2. Простые вычисления - Глава 3.1. Простые проверки ..................................................................................... 108 Глава 3.2. Простые проверки - Глава 4.1. Более сложные проверки ....................................................................... 155 Глава 4.2. Более сложные проверки - Глава 5.1. Циклы ............................................................................................................. 212 Глава 5.2. Циклъ1 - Глава 6.1. Вложенные циклы .................................................................................... 261 Глава 6.2. Вложенные циклы - Глава 7.1. Более сложные циклы ............................................................................. 300 Глава 7.2. Более сложные циклы - Глава 8.1. Подготовка к практическому экзамену- часть 1 ........................ 336 Глава 8.2. Подготовка к практическому экзамену- часть Глава 9.1. Задачи для чемпионов - часть 1......................................................... 386 Глава 9.2. Задачи для чемпионов - часть II ....................................................... 404 Глава 10. Функции ......................................................................................................... 422 Глава 11. Трюки и хаки ................................................................................................ 455 Заключение экзаменационные задачи ......................... 89 экзаменационные задачи ........................... 139 экзаменационные задачи ............. 189 экзаменационные задачи .................................................. 241 экзаменационные задачи .......................... 284 экзаменационные задачи ................... 323 П ....................... 367 ..................................................................................................................... 471
Содержание Предисловие ........................................................................................................................ 9 Для кого эта книга? ..................................................................................................... 9 Почему мы выбрали JavaScript? ........................................................................... 10 книга на других языках программирования: С#, Java, Python, С++, РНР ......................................................................................... 11 Программированию обучаются, когда пишут, а не читают! ................................................................................................................. 11 (SoftUni) ...................................... 12 Как стать программистом? .................................................................................... 15 книга в помощь преподавателям ....................................................................... 23 История этой книги .................................................................................................. 24 Авторский коллектив .............................................................................................. 24 Официальная страница книги ............................................................................. 25 <I>орум для ваших вопросов ................................................................................... 25 лицензия на распространение ............................................................................ 26 Сообщения об ошибках ........................................................................................... 26 Университет программного обеспечения Глава 1. Начало работы в программировании ..................................................... 28 Что значит «программировать»? ........................................................................ 28 Как написать компьютерную программу? ...................................................... 36 Среда разработки (IDE) ............................................................................................ 36 Пример: консольная программа «Hello JavaScript» ...................................... 40 Выполнение кода в браузере с помощью НТМL + JS .................................... 45 Типичные ошибки в программах на JavaScript ............................................. 46 Что мы узнали из этой главы? .............................................................................. 47 Упражнения: первые шаги в программировании ....................................... 47 Консольные, графические и веб-приложения ............................................... 53 Упражнения: веб-приложения ............................................................................. 54 2.1. Пр остые вычисления ................................................................................ 59 Вычисления в программировании .................................................................... 59 Типы данных и переменнъ1е ................................................................................. 60 Вывод результата на экран .................................................................................... 60 Считывание пользовательского ввода - целое число .............................. 60 Считывание дробного числа ................................................................................. 63 Считывание ввода - текст .................................................................................... 63 Объединение текста и чисел ................................................................................ 64 Глава
Содержание 5 Арифметические операции ................................................................................... 65 Объединение текста и числа ................................................................................ 66 Числовые выражения .............................................................................................. 67 Округление чисел ...................................................................................................... 68 Что мы узнали из этой главы? .............................................................................. 70 Упражнения: простые вычисления ................................................................... 71 Графические приложения с числовыми выражениями .................................................................................. 82 Глава 2.2. Простые вычисления - экзаменационные задачи ....................... 89 Обзор: чтение, вьmод чисел и вычисления ..................................................... 89 Экзаменационные задачи ...................................................................................... 91 Задача: аудитория ..................................................................................................... 91 Задача: овощной рынок .......................................................................................... 95 Задача: укладка плитки .......................................................................................... 97 Задача: конверсия валют ...................................................................................... 101 Задача: ежедневная прибыль ............................................................................. 105 3.1. Простые проверки ..................................................................................... 108 Операторы сравнения ........................................................................................... 108 Пр остые проверки ................................................................................................... 110 Проверки с помощью оператора if-else ........................................................... 110 Фигурные скобки {} после if / else ..................................................................... 111 Время жизни переменной ................................................................................... 114 Серия проверок ........................................................................................................ 115 Упражнения: простые проверки ....................................................................... 116 Отладка - простые операции с отладчиком ............................................... 121 Упражнения: простые проверки ....................................................................... 122 Графическое веб-приложение ............................................................................ 133 Глава 3.2. Простые проверки - экзаменационные задачи ........................... 139 Экзаменационные задачи .................................................................................... 139 Задача: транспортные расходы .......................................................................... 140 Задача: трубы в бассейне ...................................................................................... 143 Задача: сонный кот Том ........................................................................................ 145 Задача: сбор урожая ................................................................................................ 149 Задача: компания .................................................................................................... 152 Глава 4.1. Более сложные проверки........................................................................ 155 Вложенные проверки ............................................................................................ 155 Более сложные проверки ..................................................................................... 158 Логическое «ИЛИ» ................................................................................................... 161 Логическое отрицание .......................................................................................... 163 Глава
б Содержание Оператор кругльrх скобок О ................................................................................. 163 Более сложные логические условия ................................................................ 164 Конструкция switch-case ....................................................................................... 168 ............................................................................ 171 Упражнения: более сложные проверки ......................................................... 172 Что мы узнали из этой главы? Упражнение: графическое приложение с более сложными проверками ......................................................................... 178 ............. 189 Вложенные проверки ............................................................................................ 189 Switch-case проверки .............................................................................................. 189 Экзаменационнъrе задачи .................................................................................... 190 Задача: успеть на экзамен .................................................................................... 190 Задача: путешествие .............................................................................................. 195 Задача: операции над числами .......................................................................... 200 Задача: билеты на матчи ...................................................................................... 204 Задача: гостиничный номер ............................................................................... 207 Глава 4.2. Более сложные проверки - экзаменационные задачи 5.1. Циклы ............................................................................................................. 212 Повторяющиеся блоки кода (цикл for) ........................................................... 212 Code snippet для цикла for в Visual Studio Code ............................................ 214 Глава ............................................................................ 223 Упражнения: цикль1 ............................................................................................... 223 Упражнения: графические и веб-приложения ............................................ 227 Что мы узнали из этой главы? .................................................. 241 Экзаменационнъ1е задачи .................................................................................... 241 Задача: гистограмма ............................................................................................... 242 Глава 5.2. Циклы - экзаменационные задачи Задача: умная лили ................................................................................................ 246 .............................................................................. 249 Задача: больница ..................................................................................................... 252 Задача: деление без остатка ................................................................................ 255 Задача: логистика .................................................................................................... 258 Задача: вернуться в прошлое .................................................................................... 261 Вложенные циклы .................................................................................................. 263 Рисование более сложнъ1х фигур ...................................................................... 269 Что мы узнали из этой главы? ............................................................................ 277 Упражнение: рисование фигур в веб-среде .................................................. 277 Глава 6.1. Вложенные цикль1 - экзаменационнъ1е задачи .......................... 284 Экзаменационнъ1е задачи .................................................................................... 284 Задача: нарисовать крепость .............................................................................. 284 Глава 6.2. Вложеннъ1е циклы
Содержание 7 ........................................................................................................287 Задача: знак «STOP!» ...............................................................................................290 Задача: стрелка .........................................................................................................293 Задача: топор .............................................................................................................296 Задача: бабочка 7.1. Более сложнь1е циклы .............................................................................300 Циклы с шагом .........................................................................................................300 Цикл While..................................................................................................................303 Наибольший общий делитель (НОД) ...............................................................306 Цикл Do-while ............................................................................................................307 Бесконечные циклы и оператор break ............................................................310 Вложенные циклы и оператор break...............................................................314 Задачи с циклами ....................................................................................................316 Что мы узнали из этой rлавы? ............................................................................322 Глава Глава 7.2. Более сложные циклъ1 - экзаменационные задачи ...................323 Экзаменационные задачи ....................................................................................323 Задача: генератор паролей ..................................................................................323 Задача: магические числа ....................................................................................326 ..................................................................................................330 Задача: особые числа .............................................................................................332 Задача: разрядь1 числа ...........................................................................................333 Задача: стоп-число Глава 8.1. Подготовка к практическому экзамену- часть 1 ........................336 Практический экзамен по «Основам программирования» ....................336 Система онлайн-оценки .......................................................................................336 Задачи с простыми вычислениями ..................................................................337 Задачи с однократной проверкой .....................................................................341 Задачи с более сложными проверками ..........................................................345 Задача: сумма трех чисел .....................................................................................348 Задачи с одним циклом ........................................................................................350 Задачи по рисованию фигур в консоли ..........................................................355 Задачи с вложенными циклами с более сложной логикой ...................361 8.2. Подготовка к практическому экзамену- часть 11 .......................367 типы экзаменационных задач ...........................................................................367 Задача: расстояние ..................................................................................................368 Задача: замена плитки ..........................................................................................371 Задача: цветочный маrазин ................................................................................374 Задача: оценки ..........................................................................................................377 Задача: рождественская шапка ..........................................................................379 Задача: сочетания букв .........................................................................................382 Глава
Содержание 8 l .........................................................386 Б олее сложные задачи по изученному материалу ..................................... 386 Задача: пересекающиеся последовательности ............................................386 Задача: магические даты ......................................................................................392 Задача: пять особых букв .....................................................................................397 Глава 9.1. Задачи для чемпионов - часть 9.2. Задачи для чемпионов - часть II .......................................................404 Более сложные задачи по изученному материалу.....................................404 Задача: дни страстного шопинга ....................................................................... 404 Задача: числовое выражение .............................................................................410 Задача: быки и коровы ..........................................................................................416 Глава 10. Функции .........................................................................................................422 Что тако е функция? ................................................................................................422 Объявление функций ............................................................................................424 Вызов функций .........................................................................................................426 Функции с параметрами ......................................................................................429 Возвр ат результата функции ..............................................................................434 Варианты функций .................................................................................................439 Вложенные функции .............................................................................................439 Глава Именование функций. Лучшие практики при работе с функциями ................................................441 Что мы узнали из этой главы? ............................................................................444 Упражнения ...............................................................................................................445 11. Трюки и хаки ................................................................................................455 <I>орматирование кода ...........................................................................................455 Именование пер еменных ....................................................................................458 Глава Горячие клавиши в Visual Studio Code ..................................................................................................459 (code snippets) ..........................................................................461 Техники отладки кода ...........................................................................................465 Полезные приемы ...................................................................................................467 Что мы узнали из этой главы? ............................................................................470 Фрагменты кода .....................................................................................................................471 Эта книга - лишь первый шаг! ........................................................................472 Куда двигаться дальше? ........................................................................................472 Онлайн-сообщества для начинающих программистов ...........................477 Заключение
Предисловие книга «Основы программирования» является офJЩИальным учеб­ ным пособием для курса «Programrning Basics» для начинающих про­ граммистов в Университете программирования (SoftUni): https:// softuni.bg/courses/programrning-basics. Она знакомит читателей с ос­ новами написания программного кода, работой в интегрированной среде разработки (ШЕ), использованием переменных и данных, опе­ раторов и выражений, взаимодействием с консолью (ввод и вьmод данных), условными конструкциями клами (for, (if, if-else, switch-case), ци­ while, do-while) и функциями (объявление, вызов, пере­ дача параметров и возврат значения). В качестве языка программиро­ вания используется JavaScript, а в качестве среды разработки-Visuаl Studio Code. Представленный учебный материал обеспечивает базо­ вую подготовку для более глубокого изучения программирования и готовит читателей к вступительному экзамену в SoftUni. Эта книга дает вам только начальные основы программ.ирования. Она охватьmает базовые навыки, которые нужно развивать года­ ми, чтобы достичь достаточно высокого уровня для начала работы программистом. Кроме того, книга используется в качестве неофициального учеб­ ника для школьных курсов по программированию в профессио ­ нальных средних школах Болгарии по программам обучения « про ­ граммирование», «прикладное программирование» и «системное программирование», а также в качестве дополнительного учебни­ ка на начальных курсах по программированию в средних школах, специализированных и математических гимназиях, для классов с профилем «Информатика и информационные технологии » . Для кого эта книга? Эта книга предназначена для начинающих программистов, ко­ торые хотят узнать, что такое программирование, и изучить основ­ ные конструкции для создания программного кода, используемые
Предисловие 10 при разработке программного обеспечения, независимо от приме­ няемых языков программирования и технологий. книга закладыва­ ет прочный фундамент практических навыков, которые использу­ ются для дальнейшего обучения программированию и разработке программного обеспечения. Всем тем, кто еще не прошел бесплатный курс по основам про­ граммирования для начинающих в университете SoftUni, мы на­ стоятельно рекомендуем пройти его бесплатно, ведь программиро­ ванию учатся практикуясь, а не читая! Н а курсе вы получите бесплатный доступ к учебным пособиям, очным или онлайн-объяснениям и демонстрациям (как в видео­ уроках), много практики в написании кода, помощь в решении за­ дач после изучения каждой темы, доступ к наставникам, помощни­ кам и менторам, возможность участия в форумах и дискуссионных группах для обсуждения возникших вопросов, доступ в многоты­ сячное сообщество начинающих программистов и всевозможную помощь новичкам. Бесплатный курс кам (с 5-ro класса), SoftUni для начинающих подходит школьни­ студентам и людям других профессий, которые хотят получить технические знания и понять, нравится ли им про­ граммирование и хотят ли они в будущем серьезно заниматься раз­ работкой программного обеспечения. Каждый месяц набирается новая группа. Курс «Основы програм­ мирования » в SoftUni организуется регулярно и включает в себя несколько различных языков программирования, так что попро­ буйте. Курс бесплатный, и вы можете отказаться от него в любой момент, если он вам не понравится. Записаться на бесплатное оч­ ное или онлайн-обучение начинающим программистам можно через форму заявки в SoftUni: https://softuni.bg/apply. Почему мы выбрали JavaScript? Для этой книги мы выбрали язык JavaScript, потому что он явля­ ется современным высокоуровневым языком программирования и при этом достаточно прост для изучения новичками. JavaScript широко используется, имеет хорошо развитую экосистему с боль­ шим количеством библиотек и фреймворков, что открывает широ­ кие перспективы для развития.
Книга на других языках программирования: С#, JavaScript Java, Python, С++, РНР 11 сочетает в себе парадигмы процедурного, функцио­ нального и объектно-ориентированного программирования со­ временным способом с простым синтаксисом. В книге мы бу­ дем использовать от JavaScript и среду разработки Visual Studio Code Microsoft, которая поставляется бесплатно. Как мы объясним позже, выбор языка программирования для на­ чала не имеет большого значения, но все же нужно использовать какой-то язык, и в этой книге мы выбрали именно JavaScript. книга может быть адаптирована и для других языков программирования, таких как С#, Java и Python (см. https://csharp-book.softuni.Ьg). Книга на других языках программирования: С#, Java, Python, С++, РНР Эта книга по программированию для начинающих доступна на нескольких языках программирования (или находится в процес­ се адаптации): • • • • • Основы программирования на С# Основы программирования на Java Основы программирования на Python Основы программирования на С++ Основы программирования на РН Р Если вы предпочитаете другой язык, выберите его из приведен­ ного выше списка. Программированию обучаются, когда пишут, а не читают! Если кто-то думает, что, прочитав книгу, научится программиро­ вать без написания кода и решения задач, то он, безусловно, заблу­ ждается. Программирование осваивается с помощью постоянной практики, путем ежедневного написания кода и решения сотен, а то и тысяч задач, серьезно и упорно, в течение многих лет. Приходится решать проблемы, возиться, что-то исправлять , искать решения и информацию в Интернете, пробовать, экспе­ риментировать , находить лучшие решения, привыкать к коду, синтаксису, языку программирования, среде разработки, право-
Предисловие 12 дить поиск ошибок и отладку неработающего кода, обдумывать задачи, учиться алгоритмическому мышлению, разбиению задач на шаги и реализации каждого шага, каждый день набираться опыта и повышать свою квалификацию, ведь научиться писать код- это только первый шаг на пути к профессии «инженер-про­ граммист». Вам предстоит еще многому научиться, действитель­ но многому! Как минимум мы рекомендуем читателю решить все приве­ денные в книге примеры, «поиграть» с ними, модифицировать их и протестировать. Однако еще более важными, чем примеры, яв­ ляются практические задачи, поскольку они развивают практиче­ ские навыки. Решите все задачи, приведенные в книге, потому что програм­ мирование познается с практикой! Задачи после каждой темы тща­ тельно подобраны для глубокого охвата материала, а цель реше­ ния всех задач из всех пройденных тем состоит в том, чтобы дать исчерпывающие навыки написания кода для программирова­ ния начального уровня (что также является целью данной книги). Не зря на курсах SoftUni мы делаем упор на практику и решение за­ дач, и на большинстве курсов написание кода в классе занимает бо­ лее 70 % всего времени. Решите все упражнения в книге. Иначе вы ничему не научитесь! Программирование изучается путем написания большого коли­ чества кода и решения тысяч задач! Университет программного обеспечения Университет программного обеспечения https://softuni.org/) - (SoftUni) (SoftUni, наш адРес - крупнейший образовательный центр для ин­ женеров-программистов в Болгарии. Ежегодно через него про­ ходят десятки тысяч студентов. как продолжение SoftUni был основан в большой работы доктора 2014 Светлина году Иакова по массовой подготовке квалифицированных специалистов в об­ ласти программного обеспечения через реальное, современное и качественное образование, сочетающее фундаментальные зна­ ния с современными программными технологиями и большим количеством практики.
Университет программного обеспечения SoftUni Университет (SoftUni) 13 предоставляет возможность полу­ чить качественное образование, профессию , работу и степень бакалавра для программистов , и IТ-специалистов. SoftUni инженеров-программистов добился огромных успехов в нала­ живании прочных отношений между образ о ванием и промыш­ ленностью, сотрудничая с сотнями комп аний - разработчи­ ков программного о б еспечения, предоставляя рабочие места и стажировки своим студентам , поставляя квалифицирован­ ных специалистов в индустрию программного обеспечения и непосредственно ориентируясь на потребности работодате­ лей в процессе обучения. Бесплатнъ1е курсы программирования в SoftUni Компания SoftUni организует бесплатные курсы программирова­ ния для начинающих по всей Болгарии - очно и онлайн. Цель - чтобы каждый, кто интересуется программированием и техно ­ логиями, мог попробовать себя в программировании и понять, интересно ли это ему и хочет ли он всерьез заняться разработкой программного обеспечения. Записаться на бесплатный курс по основам программирования можно на сайте SoftUni: https://softuni.bg/apply. Бесплатные курсы по основам программирования в универси­ тете SoftUni призваны познакомить вас с основными конструк­ циями программирования из мира разработки программного обеспечения, которые вы сможете применить в любом языке про­ граммирования. Это работа с данными, переменными и выраже­ ниями, использование проверок, построение циклов, определе­ ние и вызов функций, а также другие приемы построения логики программы. Обучение очень практичное , то есть большое внима­ ние уделяется практике, и вы получаете возможность применить полученные знания еще в процессе обучения. Данная книга по программированию сопровождает бесплатные курсы программирования для начинающих в университете SoftUni и служит дополнительным учебным пособием для поддержки про­ цесса обучения.
Предисловие 14 Автоматизированная система для проверки заданий SoftUni Judge Система SoftUni Judge (https://judge.softuni.bg) представляет собой автоматизированную веб-систему для проверки решений задач по программированию с помощью серии тестов . Передача и провер­ ка задач происходят в реальном времени: вы отправляете решение и через несколько секунд получаете ответ, если оно правильное. За каждый успешно пройденный тест начисляются предусмотрен­ ные для него баллы. Если решение правильное, то вы получаете все балль1 за задачу. В случае частично верного решения вы получаете часть баллов за задание. В случае полностью неверного решения вы получаете О баллов. Все задачи, приведенные в книге, доступны для тестирования в системе SoftUni Judge, и мы настоятельно рекомендуем проте­ стировать их после решения, чтобы понять, не упустили ли вы че­ го-нибудь и действительно ли ваше решение работает правильно, в соответствии с требованиями задачи. Отметим также некоторые особенности системы • SoftUni Judge. Для каждого задания система проверки сохраняет наи­ большее количество набранных баллов. Если вы загрузите решение с неправильным кодом или с меньшим количе­ ством баллов, чем у ранее представленного решения, систе­ ма не снимет балль1. • Вывод вашей программы сравнивается системой строго с ожидаемым результатом. Любой лишний символ, пропу­ щенная запятая или пробел могут привести к О баллов на со­ ответствующем тесте. Выходные данные, которые ожидает получить система проверки, описаны в условии каждой за­ дачи, и ничего больше к ним добавлять не следует. Пример: если для вывода требуется вывести число (например не выводите описательных сообщений типа Результат : 25, а 25), выве­ дите именно то, что требуется, то есть только число. Доступ к системе SoftUni Judge на сайте: https://judge.softuni.bg. • Для входа в систему используйте свою аутентификацию с сайта • можно получить в любое время SoftUni: https://softuni.bg. Использование системы является бесплатным и не связано с обучением на курсах SoftUni.
Как стать программистом? 15 Мы уверены, что уже после нескольких сданных задач вам по­ нравится получать мгновенные отзывы о правильности выполнен­ ного вами решения, и система Judge станет вашим любимым по­ мощником при изучении программирования. Как стать программистом? Уважаемые читатели, наверняка у многих из вас есть желание стать программистом, зарабатьmать на жизнь разработкой про­ граммного обеспечения или работать в сфере информационных технологий. Именно поэтому мы подготовили краткое руководство «Как стать программистом», чтобы сориентировать вас на пути к этой желанной профессии. Программистами (на уровне начала работы в софтверной ком­ пании) становятся как минимум через 1-2 года упорного обучения и ежедневного написания кода, решения нескольких тысяч задач по программированию, разработки нескольких серьезных практи­ ческих проектов и приобретения большого опыта в написании кода и разработке программного обеспечения. Это не происходит за ме­ сяц или два! Профессия инженера-программиста требует большого объема знаний, подкрепленных многими и многими практически­ ми действиями. Существует четыре основных набора навыков, которыми долж­ нь1 обладать все программисты. Большинство из этих навыков ста­ бильны во времени и не подвержены существенному влиянию эво­ люции конкретных технологий (которые постоянно меняются). Это те навыки, которыми обладает каждый хороший программист и к которым должен стремиться каждый новичок: • написание кода • алгоритмическое мышление • фундаментальные знания о профессии • языки и технологии разработки Навык No 1 - (20 %) написание кода (30 %) (25 %) (25 %) (20 %) Умение писать код составляет около 20 % минимальных навы­ ков, необходимых программисту для начала работы в компании,
Предисловие 16 занимающейся разработкой программного обеспечения. Умение писать код включает в себя следующие компоненты: • работа с переменными, проверками, циклами • • использование функций, методов, классов и объектов работа с данными: массивами, списками, хеш-таблицами, строками Навыком кодирования можно овладеть за несколько месяцев упорной учебы и практического решения задач путем ежедневно­ го написания кода. В этой книге рассматривается только первый пункт навыка кодирования: работа с пер еменными, проверками и циклами. Остальное предстоит узнать на последующих тренин­ гах, курсах и из книг. Эта книга (и основанные на ней курсы) - лишь начало долго­ го и серьезного обучения на пути к профессиональному програм­ мированию. Если вы не овладеете в совершенстве материалом, изложенным в этой книге, то не сможете стать программистом. В ы упустите фундаментальные основы, и с каждым разом пости­ гать основы программирования будет все труднее. Поэтому уделите достаточно внимания основам: р ешайте трудные задачи и пишите много кода в течение нескольких месяцев, пока не научитесь с лег­ костью решать все задачи из этой книги. Затем двигайтесь дальше. Особо обращаем внимание, что язык программирования не имеет существенного значения для навыка кодирования. ЛИбо ты можешь кодировать, либо нет. Если ты можешь кодировать на JavaScript, ты легко научишься кодировать и на Java, и на С++, и на любом другом языке. Поэтому навыки кодирования изучаются очень серьезно на начальных курсах для программистов в SoftUni (см. учебный план), и с них начинается каждая книга по програм­ мированию для начинающих, включая нашу. Навык No 2 - алгоритмическое мъ1шление Алгоритмическое (логическое, инженерное, абстрактное) мышление составляет около 30 % (30 %) математическое, минимальных на­ выков программиста, необходимых для начала профессиональ­ ной деятельности. Алгоритмическое мышление - это способность разложить задачу на логическую последовательность шагов (алго­ ритм) и найти решение для каждого шага, а затем собрать все шаги
Как стать программистом? 17 в р абочее решение исходной задачи. Это самый важный навык про ­ граммиста. Как сформировать алгоритмическое мышление? • Алгоритмическое мышление развивается путем решения множества (1000+) задач по программированию, причем как можно более разнообразных. Это и есть рецепт: решить тысячи практических задач, придумать для них алгоритм и реализовать его, попутно находя и исправляя ошибки. • Физика, математика и/или близкие к ним естественные на­ уки полезны, но не обязательны! Людям с инженерными и техническими наклонностями обычно легче научиться логически мыслить, поскольку у них уже сформированы навыки решения задач, пусть и не алгоритмические. • Умение решать задачи программирования (что требует ал­ горитмического мышления) чрезвычайно важно для про­ граммиста. Многие компании проверяют этот навык сразу на собеседованиях. Данная книга развивает начальный уровень алгоритмического мышления, но этого недостаточно для того, чтобы стать хорошим программистом. Чтобы обрести статус квалифицированного специ­ алиста, необходимо добавить навыки логического мышления и ре­ шения задач, выходящие за рамки данной книги, такие как работа со структурами данных (массивы, списки, матрицы, хеш-таблицы, древовидные структуры) и базовыми алгоритмами (поиск, сорти­ ровка, обход древовидных структур, рекурсия и др.). Навыки алгоритмического мышления серьезно развивают­ ся на вводных курсах для инженеров-программистов в SoftUni (см. учебный план на https://softuni.bg/curriculum), а также на специ­ ализированных курсах по bg/opencourses/data-structures) opencourses/algorithms). структурам и (https://softuni. (https://softuni.bg/ данных алгоритмам Как вы уже догадались, язык программирования не имеет ника­ кого отношения к развитию алгоритмического мышления. Логи­ ческое мышление универсально, оно не связано только с програм­ мированием. Именно благодаря высокоразвитому логическому мышлению программисты считаются достаточно умными, а чело-
Предисловие 18 век, не обладающий таким мышлением, не может стать програм­ мистом. Навык No 3- о профессии фундаменталънъ1е знания (25 %) Фундаментальные знания и навыки в области программиро­ вания, разработки программного обеспечения, программной ин­ женерии и информатики составляют около 25 % от минимальной квалификации программиста начального уровня. Вот наиболее важные из этих знаний и навыков: • основные математические понятия, связанные с програм­ мированием: системы координат, векторы и матрицы, дискретные и недискретные математические функции, ко­ нечные автоматы и автоматы состояний, понятия из ком­ бинаторики и статистики, сложность алгоритмов, матема­ тическое моделирование и др.; • навыки программирования - написание кода, работа с данными, использование условных операторов и ци­ клов, работа с массивами, списками и ассоциативными массивами, строками и обработкой текста, работа с пото­ ками и файлами, использование API, работа с отладчика­ ми и др.; • структуры данных и алгоритмы - списки, деревья, хеш-та­ блицы, графы, поиск, сортировка, рекурсия, обход древо­ видных структур и т. д.; • объектно-ориентированное программирование (ООП) - работа с классами, объектами, наследование, полимор­ физм, абстракция, интерфейсы, инкапсуляция данных, управление исключениями, шаблоны проектирования; • функциональное программирование (ФП) - работа с лямбда-функциями, функциями высшего порядка, функ­ циями, возвращающими в качестве результата функцию, замыкание • (closure) и др.; базы данных - реляционные и нереляционные базы дан­ ных, моделирование баз данных (таблицы и связи междУ ними), язык запросов SQL, объектно-реляционные техноло-
Как стать программистом? 19 гии доступа к данным (ОRМ), транзакционность и управле­ ние транзакциями; • сетевое программирование взаимодействие, - сетевые протоколы, сетевое TCP/IP, концепции, средства и технологии построения компьютерных сетей; • клиент-серверное взаимодействие, связь между система­ ми, back-end технологии, технологии front-end, архитекту­ ры МVС; • технологии разработки на стороне сервера (Ьack-end) - ар­ хитектура веб-сервера, протокол НТТР, архитектура МVС, REST архитектура, фреймворки веб-разработки, шаблони­ заторы; • фронтенд-технолоrии (клиентская разработка) - HTML, CSS, JS, НТТР, DOM, AJAX, связь с back-end, вызов REST API, фронтенд-фреймворки, базовые концепции дизайна и UX (user experience); • мобильные технологии ботка под терфейс • - Android и iOS, мобильные приложения, разра­ мобильный пользовательский ин­ (UI), вызов серверной логики; встраиваемые системы - микроконтроллеры, управление цифровыми и аналоговыми входами и выходами, доступ к датчикам, управление периферийными устройствами; • операционные системы мами - работа с операционными систе­ (Linux, Windows и дР.), установка, настройка и основы системного администрирования, работа с процессами, па­ мятью, файловой системой, пользователями, многозадач­ ность, виртуализация и контейнеры; • параллельное программирование и асинхронность - управление потоками, асинхронные задачи, общие ресур­ сы и синхронизация доступа; • программная инженерия - системы контроля исходных текстов, управление разработкой, планирование и управ­ ление задачами, методологии разработки ПО, требования
Предисловие 20 к ПО и прототипы, проектирование ПО, архитектуры ПО, документация ПО; • тестирование программного обеспечения - модульное те­ стирование, разработка, управляемая тестами, QА-инжи­ ниринr, создание отчетов об ошибках и баr-трекеров, авто­ матизация тестирования, процессы сборки и непрерывной интеграции. Опять же следует уточнить, что для овладения всеми этими на­ выками язык программирования неважен. Они накапливаются по­ степенно, в течение многих лет практики в профессии. Некоторые знания являются фундаментальными и могут быть усвоены теоре­ тически, но для их полного понимания и глубокой реализации тре­ буются годы практики. Фундаментальные знания и навыки в области программирова­ ния, разработки программного обеспечения, программной инже­ нерии и информатики преподаются в рамках комплексной про­ граммы « Инженер-программист» в SoftUni https://softuni.bg/ курсов (см. https:// (см. curriculum), а также на ряде факультативных softuni.bg/trainings/opencourses). Работа с разнообразными про­ граммными библиотеками, интерфейсами прикладного програм­ мирования (API), технологическими фр еймворками (Frameworks), программными технологиями и их взаимодействием постепен­ но формирует эти знания и навыки, поэтому не стоит ожидать, что они будут получены в результате изучения одного курса, кни­ ги или проекта. Для начала работы программистом, как правило, до статочно лишь базовых знаний в перечисленных областях, а углубление про­ исходит в процессе работы в соответствии с технологиями и сред­ ствами разработки, используемыми в конкретной компании и кол­ лективе. Навык No 4 - языки программирования и программные технологии (25 %) Языки программирования и технологии разработки программ­ ного обеспечения составляют около 25 % минимальных навыков программиста. Они занимают наибольшую часть в программах обучения, но очень быстро меняются с течением времени. Если по-
Как стать программистом? 21 смотреть на объявления о вакансиях в сфере программного обе­ спечения, то там часто используются всевозможные «жужжащие» слова (например, перечисленные ниже), но на самом деле в объяв­ лениях подразумеваются первые три навыка: умение кодировать, алгоритмически мыслить и владеть основами информатики и про­ граммной инженерии. Для этих чисто технологических навыков язык программирова­ ния уже имеет значение. Но обратите внимание: только в 25 % требований язык про­ граммирования имеет значение! Для остальных 75 % требуемых навыков язык программирования неважен, и эти навыки устойчи­ вы во времени и переносимы между различными языками и тех­ нологиями. Вот некоторые широко используемые языки и технологии (сте­ ки разработки программного обеспечения), во стребованные софт­ верными компаниями: • С# + ООП + ФП + классы .NET + базы данных SQL Server + Entity Framework (EF) + ASP.NET МVС + НТТРS + НТМL + CSS + JS + DOM + jQuery • Java + классы Java API + ООП + ФП + базы данных+ MySQL + НТТРS + веб-разработка + HTML + CSS + JS + DOM + jQuery + JSP/Servlets + Spring МVС или Java EE/JSF • РНР ка + ООП + базы данных + MySQL + НТТРS + веб-разработ­ + HTML + CSS + JS + DOM + jQuery + Laravel / Symfony / дру­ гой МVС-фреймворк для РНР • JavaScript (JS) + ООП + ФП + базы данных + MongoDB или MySQL + НТТРS + веб-программирование + HTML + CSS + JS + DOM + jQuery + Node.js + Express + Angular или React • Python + ООП + ФП + базы данных + MongoDB или MySQL + НТТРS + веб-программирование + HTML + CSS + JS + DOM + jQuery + Django • С+++ ОО П + STL + Boost + нативная ных + НТТРS + другие языки • Swift + macOS + iOS + Сосоа + Сосоа Touch + XCode + НТТРS + REST + другие языки разработка + базы дан­
22 Предисловие Если перечисленные слова и аббревиатуры кажутся вам страшны­ ми и абсототно непонятными, значит, вы находитесь в самом начале своей карьеры, и до получения профессии «июкенер-программист» вам предстоит учиться не один год. Не волнуйтесь, каждый програм­ мист проходит чер ез один или несколько технологических стеков и вынужден изучать набор взаимосвязанных технологий, но в осно­ ве всего этого лежит умение писать логику программы («кадить »), которое подробно изучается в этой книге, и умение алгоритмически мыслить (решать задачи программирования). Без них никак нельзя ! Язык программирования не имеет значения! Как уже было сказано, разница между языками программирова­ ния, а точнее, между навыками программистов на разных языках и технологиях, составляет порядка • 10-20 % навыков. Все программисты обладают примерно 80-90 % одних и тех же навыков, независимо от языка! Это навыки программи­ рования и разработки программного обеспечения, которые очень похожи для всех языков программирования и техно­ логий разработки. • Чем больше языков и технологий вы освоите, тем быстрее вы выучите новые и тем меньше будете чувствовать разни­ цу между ними. На самом деле язык программирования практически не имеет значения, нужно просто научиться программировать, а это начина­ ется с кодирования (данная книга), продолжается более сложными концепциями программирования (такими как структуры данных, алгоритмы, ООП и ФП) и вкточает в себя освоение фундаменталь­ ных знаний и навыков разработки программного обеспечения, программной июкенерии и компьютерных наук. Только в конце, когда вы начнете использовать конкретные технологии в программном проекте, вам понадобятся определен­ ный язык программирования и знания о конкретных библиотеках (API), фреймворках и программных техноло­ (технологии front-end UI, back-end, ORM и т. д.). Ра сслабьтесь, программирования гиях вы их изучите, все программисты их изучают, но сначала нужно изучить основы программирования, и изучить их хорошо.
Книга в помощь преподавателям 23 В книге используется язык но, он может быть заменен Go, Kotlin JavaScript, но это не принципиаль­ на С#, Java, Python, РНР, RuЬy, Swift, или другой язык. Чтобы освоить профессию «разработ­ чик программного обеспечения», необходимо научиться «кадить» (20 %), научиться алгоритмически мыслить и решать задачи (30 %), обладать фундаментальными знаниями в области программирова­ ния и информатики (25 %), владеть конкретным языком програм­ мирования и сопутствующими технологиями (25 %). Наберитесь терпения, через год-два в се это можно освоить на хорошем началь­ ном уровне при условии серьезного подхода. Книга в помощь преподавателям Если вы преподаете программирование, информатику или инфор­ мационные технологии либо хотите преподавать программирование, то эта книга даст вам больше, чем просто хорошо структурированный учебный материал с большим количеством примеров и задач. Вместе с книгой вы получите качественный учебный материал для школы, адаптированный к ее требованиям. • Учебные презентации (слайды адаптированные к PowerPoint) по каждой теме, 45-минутным урокам в школах бес­ платно. • Тщательно разработанные задачи для аудиторных занятий и домашних заданий с подробными условиями и примера­ ми входных и выходных данных - • бесплатно. Автоматизированную систему проверки заданий и домаш­ них. работ (Online Judge Systern), которой студенты могут пользоваться также бесплатно . • Видеоуроки с методическими указаниями из бесплатного курса для преподавателей программирования, который ре­ гулярно проводит SoftUni. Все эти бесплатные учебные ресур сы, а также учебные материа­ ль1 для целого ряда курсов по программированию и программным технологиям можно найти на сайте университета SoftUni. Скачать их можно здесь: http://softuni.foundation/projects/applied-softwaredeveloper-profession.
24 Предисловие История этой книги Основной движущей силой и руководителем проекта по созда­ нию этой книги по программированию с открытым кодом для на­ чинающих является доктор Светлин Иаков (http://www.nakov.com/). Он стал главным идеологом и создателем учебного контента курса «Основы программирования» (https://softuni.bg/courses/programming- basics) в университете SoftUni, который положен в основу кнши. Все началось с массовых бесплатных курсов по основам про­ граммирования, которые проводятся по всей Болгарии с 2014 года, когда была запущена инициатива SoftUni. Вначале эти курсы были более масштабными и включали больше теории, но в 2016 rодУ док­ тор Светлин Иаков полностью переработал их, обновил, упростил и сделал основной упор на практику. Так было создано основное учебное наполнение этой кнши. Бесплатные тренинги SoftUni по основам программирования - пожалуй, самые масштабные из всех, которые когда-либо прово­ дились в Болгарии. К прошел более 200 2018 году курс «Основы программирования » раз почти в 40 городах Болгарии очно и много­ кратно онлайн, в нем приняли участие более 70 ООО человек. Вполне естественно , что возникла необходимость написать учебник для десятков тысяч слушателей курсов по программиро­ ванию для начинающих от SoftUni. Исходя из принципа свободно­ го программного обеспечения и свободных знаний, Светлин Иаков возглавил комаНдУ добровольцев и продвинул этот проект с откры­ тым исходным кодом, сначала для создания учебника по основам программирования на языке С#, а затем и на других языках про­ граммирования. Проект является частью деятельности Foundation (http://softuni.foundation/) Software University по созданию и распростране­ нию открытого образовательного контента для подготовки инже­ неров-программистов и IТ-специалистов. Авторский коллектив Над этой книгой работала большая команда энтузиастов, кото­ рые добровольно выделили свое время, чтобы предоставить вам систематизированные знания и рекомендации для начала вашего
Официальная страница книги 25 пути в программировании. Список всех авторов и редакторов (в ал­ фавитном порядке): Бончо Вальков, Венцислав Петров, Димитар Далев, Елена Рогле­ ва, Джульетта Атанасова, Захария Пехливанова, Здравко Костади­ нов, Ивелин Арнаудов, Кристиан Марьянов, Мартин Чаов, Нико­ лай Банкин, Николай Костов, Павел Колев, Петр Иванов, Светлин Иаков, Стилян Кангалов, Кристиан Христов, Христа Минков. книга основана на ее первоначальном варианте для С# («Введе­ ние в программирование на С#»), который был разработан широ­ ким авторским коллективом, также внесшим свой вклад в созда­ ние этой книги: Александр Крастев, Александр Лазаров, Ангел ДИмитриев, Ва­ ско Викторов, Венцислав Петров, Даниил Цветков, Димитар Татар­ ский, Димо ДИмов, ДИан Тончев, Елена Роглева, Живко Недялков, Джульетта Атанасова, Захария Пехливанова, Ивелин Кирилов, Ис­ кра Николова, Калин Примов, Кристиан Памидов, Любослав Лю­ бенов, Николай Банкин, Николай Димов, Павлин Петков, Петр Иванов, Росица Ненова, Руслан Филиппов, Светлин Иаков, Стефка Васильева, Теодор Куртев, тоньо Желев, Кристиан Христов, Хри­ ста Христов, Цветан Илиев, Юлиан Линев, Яница Валева. Официальная страница книги Настоящая книга по основам программирования на JavaScript для начинающих доступна для свободного использования в интер­ нете по адресу: https://js-book.softuni.bg Это официальный сайт книги, и здесь будет выкладываться ее последняя версия. Книга также адаптирована к другим языкам про­ граммирования (таким как С#, Java, Python и С+ +), ссылки на кото­ рые указаны на ее сайте. Форум для ваших вопросов Задавайте свои вопросы по данной книге по основам програм­ мирования на форуме SoftUni: https://softuni.bg/forum
26 Предисловие На этом дискуссионном форуме вы получите бесплатный и ква­ лифицированный ответ на любой вопрос, связанный с учебным материалом данной книги, а также на другие вопросы по про­ граммированию. Сообщество SoftUni для начинающих програм­ мистов настолько велико, что обычно ответ на заданный вопрос приходит в течение нескольких минут. Преподаватели, асси­ стенты и менторы SoftUni также постоянно отвечают на ваши вопросы. Из-за большого количества студентов, изучающих данную кни­ гу, на форуме вы можете найти решение практически любой зада­ чи из нее, предложенное вашим коллегой. Тысячи студентов до вас уже решали эти же задачи, поэтому, если вы «застряли», поищи­ те ответ на форуме. Хотя задачи на курсе « Основы программиро­ вания» время от времени меняются, обмен опытом всегда поощ­ ряется в SoftUni, поэтому вы легко найдете решения и подсказки для всех задач. Если у вас есть конкретный вопрос, например, почему не работа­ ет определенная программа, над которой вы бьетесь уже несколь­ ко часов, задайте его на форуме, и вы получите ответ. Вы удиви­ тесь, насколько доброжелательны и отзывчивы участники форума SoftUni. Лицензия на распространение книга распространяется бесплатно в электронном формате по от­ крытой лицензии CC-BY-SA (https://creativecommons.org/licenses/Ьy­ sa/4.0). Исходный код книги можно найти на GitHuЬ: https://githuЬ.com/SoftUni/Programming-Basics-Book-JS-BG. Сообщения об ошибках Если вы обнаружили ошибки, неточности или опечатки в книге, вы можете сообщить о них в официальном трекере проекта: https://githuЬ.com/SoftUni/Programming-Basics-Book-JS-BG/issues
Сообщения об ошибках 27 Мы не обещаем исправить все, что вы нам отправите, но мы стре­ мимся постоянно улучшать качество данной книги, поэтому все не­ оспоримые ошибки и разумные предложения будут рассмотрены. Приятного чтения! И не забывайте писать код в больших количествах, пробовать примеры из каждой темы и, самое главное, решать задачи из упраж­ нений. Просто читая, вы не научитесь программировать, поэтому решайте задачи усердно!
Глава 1. Начало работы в программировании В этой главе мы разберемся, что такое программирование. Мы введем понятие языков программирования, рассмотрим инте­ грированные среды разработки (IDE) и работу с ними, в частности Visual Studio Code. Мы напишем и запустим нашу первую программу на языке программирования JavaScript, а затем выполним несколь­ ко заданий: создадим консольную программу и веб-приложение. Мы научимся проверять решения задач из этой книги на правиль­ ность в системе Judge SoftUni, а также узнаем о типичных ошибках, которые часто допускаются при написании кода, и о том, как их из­ бежать. Что значит « программировать»? Программирование означает подачу компьютеру команд, напри­ мер, «воспроизвести звук», «вывести что-то на экран» или «пере­ множить два числа». Если команд несколько и они следуют подряд, то они называются компьютерной программой. Текст компьютер­ ных программ называется программным кодом (или исходным ко­ дом, или сокращенно кодом). Компьютернъ1е программы Компьютерные программы - это последовательность ко­ манд, написанных на заранее выбранном языке программирова­ ния, например Go JavaScript, Python, С#, Java, РНР, RuЬy, С, С ++, Swift, или другом. Для того чтобы писать команды, нам необходимо знать синтаксис и семантику языка , с которым мы будем работать, в нашем случае JavaScript. Поэтому в данной книге мы познако­ мимся с синтаксисом и семантикой языка JavaScript и программи­ рованием в целом, шаг за шагом изучая, как писать код, начиная
29 Что значит «программировать»? с самых простых и заканчивая более сложными конструкциями прогр аммирования. Алгоритмъ1 Компьютерные пр ограммы обычно выполняют алгоритм. Алго­ ритмы - это последовательность шагов, необходимых для выпол­ нения определенного задания и достижения некоторого ожидае­ мого результата, своего рода «рецепт». Например, если мы жарим яичницу, то выполняем некоторый рецепт (алгоритм) : разогреваем масло на сковороде, разбиваем яйца, ждем, пока они поджарятся, снимаем с огня. Аналогично в программировании компьютерные программы выполняют алгоритмы - серии команд, необходимых для выполнения определенной работы. Например, чтобы располо­ жить последовательность чисел в порядке возрастания, требуется алгоритм, скажем, найти наименьшее число и вывести его, среди оставшихся чисел снова найти наименьшее и вывести его, и так повторять, пока числа не закончатся. Для удобства создания программ, написания программного кода (команд), выполнения программ и других операций, связаннь1х с программированием, нам также необходима среда разработки (IDE), например Visual Studio Code. Языки программирования, компиляторы, интерпретаторы и средь~ разработки Язык программирования - это своего рода искусственный язык (он обладает собственнь1м синтаксисом), предназначенньIЙ для за­ дания компьютеру команд, которые он после этого должен считать, обработать и выполнить. С помощью языков программирования мы пшuем последовательности команд (программы), которые ука­ зывают компьютеру, что необходимо сделать. Вьmолнение компью­ терных программ может быть реализовано с помощью компилятора или интерпретатора. Компилятор переводит код с языка программирования в машин­ НЬIЙ код, выбирая для каждого оператора (команды) кода соответству­ ющий, заранее подготовленньIЙ фрагмент машинного кода и прове­ ряя при этом текст программы на наличие ошибок В совокупности скомпилированнь1е фрагменты составляют программу в машинном коде, которую ожидает увидеть микропроцессор компьютера. После
Глава 30 1. Начало работы в программировании компиляции программы она может быть непосредственно вьmолне­ на микропроцессором совместно с операционной системой. В компилируемых языках программирования компиляция про­ граммы перед ее выполнением является обязательной, а синтакси­ ческие ошибки (неправильно указанные инструкции) выявляют­ ся в процессе компиляции. С компилятором работают такие языки как С++, С#, Java, Swift и Go. Некоторые языки программирования не используют компилятор, а интерпретируются напрямую с помощью специализированного программного обеспечения, называемого интерпретатором. Интер­ претатор-это «исполнитель программы» для программ, написанных на каком-либо языке программирования. Он вьшолняет команды про­ граммы одну за дРуrой, понимая не только отдельные команды и по­ следовательности команд, но и дРуrие язьn<овые конструкции (услов­ ные ветвления, циклы, функции и т. д.). Такие язьП<И, как РНР, Python и JavaScript, работают с интерпретатором и запускаются без коМIШЛЯ­ ции. Из-за отсутствия предварительной компиляции ошибки в ин­ терпретируемых языках обнаруживаются во время вьmолнения про­ граммы, после того как она начинает работать, а не заранее. Интегрированная среда разработки (IDE) - это набор традици­ онных инструментов для разработки программных приложений. В среде разработки мы пишем код, компилируем и вьmолняем про­ граммы. Среда разработки включает в себя текстовый редактор для написания кода, язьn< программирования, компилятор или ин­ терпретатор, отладчик для отслеживания выполнения программы и поиска ошибок, средства проектирования пользовательского ин­ терфейса, а также дРуrие инструменты и дополнения. Среды программирования удобны тем, что они объединяют в себе все необходимое для разработки программы. Если мы не ис­ пользуем среду разработки, нам придется писать код в текстовом редакторе, выполнять его с помощью дРуrой команды из консо­ ли, а при необходимости писать дополнительные команды, и это отнимает время. Именно поэтому большинство программистов используют IDE в своей повседневной работе. Для программирования на JavaScript очень часто использует­ ся среда разработки Visual Studio Code, которая разрабатывается и бесплатно распространяется компанией Microsoft и может быть
Что значит «программировать »? 31 загружена с сайта: https://www.visualstudio.com/downloads. Аль­ тернативой Visual Studio Code являются WebStorrn (https://www. jetbrains.corn/webstorrn), Atorn (https://atorn.io) и другие. В этой кни­ ге мы будем использовать среду разработки Visual Studio Code. Языки низкого и высокого уровня, ср еды выполнения Программа - это, по сути, набор инструкций, которые предпи­ сывают компьютеру выполнить определенную задачу. Они вводят­ ся программистом и безоговорочно вьmолняются машиной. Существуют различные типы языков программирования. Языки самого низкого уровня могут использоваться для написания соб­ ственно инструкций, управляющих процессором, например, язык ассемблера. Языки более высокого уровня, такие как С и С++ , мо­ гут применяться для создания операционных систем, драйверов для управления аппаратным обеспечением (например, драйвера видеокарты), веб-браузеров, компиляторов, графических и игровых движков, а также других системных компонентов и программ. Еще более высокоуровневые языки, такие как JavaScript, Python и С#, ис­ пользуются для создания прикладных программ, например, про­ граммы для чтения почты или чата. Языки низкого уровня управляют аппаратным обеспечением напрямую и требуют больших усилий и огромного количества ко­ манд для вьmолнения какого-либо задания. Языки более высоко­ го уровня требуют меньше кода для выполнения того же задания, но не имеют прямого доступа к аппаратному обеспечению. Они ис­ пользуются для разработки прикладного программного обеспече­ ния, такого как веб-приложения и мобильные приложения. Большинство программ, которыми мы пользуемся ежедневно, например музыкальный плеер, видеоплеер, программа написаны на языках прикладного GPS программирования и т. д., высокого уровня, таких как JavaScript, Python, С#, Java, С+ +, РНР и т. д. JavaScript - интерпретируемый язык, а это значит, что мы пи­ шем команды, которые выполняются непосредственно по сле запу­ ска программы. Следовательно, если мы допустили ошибку при на­ писании кода, то узнаем об этом только после того, как запустим программу и доЙДем до неправильной команды. Именно здесь на помощь приходят такие IDE, как Visual Studio Code, которые про-
Глава 32 1. Начало работы в программировании веряют наш код по ходу написания и предупреждают о проблемах. Когда мы написали код и хотим его протестировать, мы можем со­ хранить его в файле с расширением Большинство языков . j s. программирования специализируются на разработке определенного типа приложений - десктопных - для Windows или Мае, мобильных, серверных, для управления rад­ жетами и т. д. JavaScript- один из немногих языков, позволяющих создавать приложения во всех возможных областях - от веб-сай­ тов и мобильных приложений до серверных и десктопных. JavaScript являются веб-браузеры, которыми вы пользуетесь каждый день Chrome, Firefox, Internet Explorer и т. д. Когда вы загружаете свой любимый сайт, вполне вероятно, что он содержит файлы JavaScript, Н аиболее популярными средами для интерпретации которые будут выполняться при открытии сайта и сделают ваш просмотр более приятным. Также в ероятно, что если на сайте есть выпадающие меню, анимация, регистрация пользователей, на­ зойливая реклама, то они реализованы с помощью JavaScript. Часто можно услышать, что код «выполняется на клиенте» - это означает, что код JavaScript выполняется в вашем браузере, ко­ торый играет роль клиента, или приемника. Для того чтобы суще­ ствовал приемник, должен быть передатчик. В мире IТ-технологий эти передатчики называются серверами. Вы можете представить себе серверы как несколько очень мощных компьютеров, к кото­ рым имеет доступ множество людей. Все веб-сайты располагают­ ся на таких серверах - то есть файлы, которые помогают веб-сай­ ту выглядеть таким, как вы его видите (картинки, текст, файлы JavaScript) располагаются на определенном сервере. Ваш браузер (клиент) подключается к серверу, на котором находится посещае­ мый вами сайт, и сервер отправляет обратно необходимые файлы, чтобы отобразить для вас ваш любимый сайт. Вы можете предста­ вить, что ваш браузер - это радиоприемник в вашем автомоби­ ле, по которому вы слушаете любимую программу, а сервер - зда­ ние, откуда эта программа транслируется, хотя связь между ними разная. Другой популярный интерпретатор JavaScript - NodeJS. Его можно рассматривать как приложение, которое вы устанавливае­ те на свой компьютер, и оно начинает понимать JavaScript так же, как это делает ваш браузер. Таким образом, вы можете вьmолнять
Что значит «программировать»? 33 JavaScript-кoд прямо на своем компьютере без использования бра­ узера. Как мы уже говорили, серверы - это просто более мощные JavaScript так же, как и ваш компьютер - просто установите на них NodeJS. Вы можете бесплат­ но установить NodeJS с официального сайта https://nodejs.org, сле­ компьютеры. Они начинают понимать дуя инструкциям. Компьютерные программъ1 Как уже говорилось, программа реализация - это последовательность ин­ струкций, другими словами, она описывает ряд вычислений, про­ верок, итераций и любых других подобных операций, направлен­ ных на достижение некоторого результата. Программа пишется в текстовом формате, а сам текст програм­ мы называется исходным кодом. Он сохраняется в файле с рас­ ширением .j s (например, main. j s) и затем может быть вьmол­ нен через веб-браузер или системную консоль с помощью NodeJS. Мы рассмотрим оба варианта в ближайшее время. Компьютерные программы Начнем с очень простого примеры примера короткой программы на JavaScript, которую мы запустим прямо в браузере (он поддержи­ вает JS без установки дополнительных компонентов). Пример: программа, уведомляющая пользователя Наша первая программа будет состоять из одной команды JavaScript, которая уведомит пользователя о том, что он выиграл 1 ООО ООО долларов, как это часто бывает при просмотре сайта с боль­ шим количеством спама и рекламы: alert("Congratulations! ! ! You have just won $1 000 000!"); Мы можем выполнить программу с помощью консоли JavaScript в нашем веб-браузере. Например , в и вводим код в окно top мы нажимаем [F12] [ Console]: Elements 18 {)) Chrorne Console • ! Sources 0 Networl< Filter » : Default levels • х О > alert( "Congrat ulations! ! ! Vou have just won $1 000 000! ") ; В результате вы увидите вспльшающее сообщение в браузере:
Глава 34 D •Ьout:Ыank Начало работы в программировании + х С 1. □ х : х Ф aЬout-Ьlank This page says Congratu1ations!!! You have just ,von S1 ООО ООО! Elements 1Ш > (S) Console ... top Sources 0 » Filter о Default levels ... alert( "Congratulations! ! ! You have just won $1 000 000!" ); > Пример: программа, рассылающая уведомления пользователю Мы можем усложнить предыдущую программу, указав цикличе­ ские команды, которые нужно вьmошrnть в последовательности, что­ бы уведомить пользователя о том, что он стал победителем лотереи: for (i = 0; i < 10; i += 1) { alert(''Congratulations! ! ! You have just won $1 000 000!''); } В приведенном выше примере мы заставляем веб-браузер отправ­ лять уведомлеюrя одно за другим, пока их коJШЧество не доСТШ1-Iет де­ сяти. В результате мы получаем очень раздраженного пользователя: С) •ЬOU<Ьlonk ~ С - х □ + х Ф o1>ou Ыank This page says Congr,1tu~ttOns~!! You МW'just v"on S1 ООО~ +++ Elements [Ш 6) top Console " Sources 0 Network Filter » х Default levels " О > for ( i = 0; i < 10; i += 1 ) { alert( "Congratulati ons! ! ! You have just won $1 000 000 ! "" ); } > О том, как работают циклы в программировании, мы узнаем в главе «Циклы» , а пока предположим, что мы просто повторяем некоторую команду много раз.
35 Что значит «программировать »? Пример: программа, которая конвертирует левы в евро Рассмотрим еще одну простую программу, которая запрашива­ ет у п ользователя некоторую сумму в левах (целое число), проверя­ ет, что введенное число является числом, конвертирует его в евро (деля на курс евро) и выводит результат. Эта программа состоит из трех последовательных команд: let myMoney = prompt("How much money do you want to convert :"); let leva = parseint(myMoney); let euro = leva / 1.95583; console.log(euro); Если мы запустим эту программу в консоли JavaScript браузера, то получим что-то вроде этого : ~ •ЬOUtЬl.!nk С х Ф о + ahoul Ыank 0. х * • This page says НО\'/ much money do you want to convwm.: 50 - Elements ~ Э top Console "' Sources 0 c.tncel Network Filter » х Default levels .,. о > let myMoney = prompt( "Ho1~ much money do you want to convert:") ; let leva = parseint(my~\oney); let euro = leva / 1.95583; console.log( euro); > Elements ~ Э top Console "' Sources 0 Network Filter » х Default levels "' let leva = pa rsei nt (my~loney); let e uro = leva / 1.95583; console . log( euro); 25.564594059810926 ◄ undefined VM264:5 о
Глава 36 1. Начало работы в программировании Мы рассмотрели три примера компьютерных программ : одиноч­ ная команда, серия команд в цикле и последовательность из четы­ рех команд. Теперь перейдем к более интересной части: как мы мо­ жем писать собственные программы на JavaScript и как вьmолнять их вне браузера? Как написать компьютерную программу? Давайте рассмотрим шаги по созданию и выполнению компью­ терной программы, которая считывает и выводит свои данные в текстовую консоль (окно ввода и вывода текста) и из нее. Такие программы назьmаются консольными. Однако перед этим нам не­ обходимо установить и подготовить среду разработки, в которой мы будем писать и вьmолнять программы на JavaScript, описанные в теоретических и практических частях этой книги. Среда разработки {IDE) Как уже говорилось, для программирования нам нужна среда разр аботки - Integrated Development Environment (IDE). Это факти­ чески редактор программ, в котором мы пишем код программы, мо­ жем компилировать и выполнять его, видеть ошибки, исправлять их и запускать программу снова. • • • Для программирования на JavaScript мы используем среду Visual Studio Code, которая подцерживается на операцион­ ных системах Windows, Linux и Мае OS Х. Если мы программируем на Java, то используем IntelliJ IDEA, Eclipse или NetBeans. Если мы собираемся писать на Python, то можно использо­ вать среду PyCharm. Установка Visual Studio Code Начнем с установки Microsoft Visual Studio Code (версия 1.19, ак­ туальная на январь 2018 года). Visual Studio Code распространяется бесплатно компанией Мicrosoft и может быть загружена по адресу: https://code.visualstudio.com. Установка представляет собой типичную Windows-ycтaнoвкy с по-
Среда разработки 37 (IDE) мощью кнопок [Next], [Next] и [Finish]. Нет необходимости изме­ нять другие настройки установки. Далее подробно описаны шаги установки Visual сия 1.19.1). Studio Code (вер­ После загрузки установочного файла и его запуска поя­ вится следующее окно: х Welcome to the Visual Studio Code Setup Wizard Тhis 'll'iD instaO Microsoft V1SUal Studio Code on your computer. It is recommended that you dose all other applications before continuing. C1ick Next to continue, ог Cancel to exit Setup. ( Нажимаем [Next], затем нужно Next > ) Cancel согласиться с условиями исполь­ зования: >4 Setup - Visual Studio Code - х ~ Select Additional Tasks Which i!!dditional tasks should Ье performed? Select the adcitional tasks you would like Setup to perform wh~e instaltng Visual Studio Code, then dick Next. Additional icons: 0 Create а desktop icon Other: 0 0 0 0 Add "Open ,л;tt, Code • action Add to \J\findows Explorer file context menu •apen ,л;tt, Code" action to \•findows Explorer directory context menu Register Code as an editor fur supported file types дdd to РдlН (avaiaЫe after restart} --<6ack 1 Next > 1 Cancel
Глава 38 1. Начало работы в программировании Загрузится окно с панелью установки Visual Studio Code, и в ка­ кой-то момент нас спросят о предпочтениях в отношении дополни­ тельных настроек, которые зависят от нас. Вот, собственно, и все. Начинается установка Visual Studio Code, и после ее завершения мы почти готовы к работе. Наконец, после запуска VS Code появля­ ется экран, подобный приведенному ниже: ~ Welcome - Visual Studio Code f:ile f,dit ielection 114 \беw Welcome §о о Qebug Iasks !:J.elp rn ... х Staп Cuяomize Ne,v file Open folder... Clone Git repository ... Tools and languages lr,,e есе sur-ю о ev 5, пр\ TypeS lnstall keyЬoard shortcuts lrs.a '1е e,t>oard sI ortc..11s of Vim Recent Nc, х t olders Colortheme ~ ,е ,в ,,,11 ind your code look 1 Сейчас самое время сделать среду разработки как можно более приятной. Visual Studio Code - одна из немногих IDE с большими возможностями кастомизации. Чаще этот процесс осуществляет­ ся с помощью расширений. Список всех расширений можно най­ ти на официальном сайте https://marketplace.visualstudio.com. Об­ ратите внимание, что многие из этих расширений предназначены /JlIЯ работы с определенным языком программирования. Для начала мы рекомендуем установить два следующих рас­ ширения, так как они значительно повысят производительность при написании JavaScript-кoдa: • Beautify- https://marketplace.visualstudio.com/items?itemName= HookyQR. Beautify - это расширение, которое поможет вам сохранить ваш код чистым и аккуратным.
Среда разработки • 39 (IDE) JSНint - https://marketplace.visualstudio.com/items?itemName= dЬaeumer.jshint. Как мы уже говорили, JavaScript - интер­ претируемый язык, и ошибки в коде проявятся только по­ сле начала выполнения программы. Это расширение ищет ошибки и сообщает о возможных нарушениях во время на­ писания кода, до запуска программы. Установка производится либо напрямую по указанным ссылкам, либо путем выполнения следующих шагов в Visual Studio Code. 1. На панели слева откройте самую нижнюю вкладку- «Расши­ рения» (Extensions). 2. В строке поиска введите название расширения, которое вы хотите установить. 3. Из результатов выберите то, которое нам подходит. 4. Нажмите кнопку [Install]. 5. Перезапустите Visual Studio Code. ~ Extension: Вeautify- Visual Studio Code E•le t_dit S,election YJe,1 ~о о Qebug I,,sl<s !!elp i!i: Exumsion: Beautify EXТENSIONS MAIU(EТP\.ACE lьeautify 12 Bнutify ,о ф lml "'i\ HookyQR 3 IIDll l lml Q86К Beautify JS/JSX/ТS/ТSX Code S 4>; Beautify code in pla .. B•autify as/sass/... 7.2 Q 197< • Beautify css, sass and less code (exten. .. react•beautify ~ 3 ~ Х Beautify Ф2.2М *•S Beautify code in place for VS Code " х ~ Contributions 4 Changelog Depen, js-beautify for VS Code Вот и все. Мы готовы к работе с Visual Studio Code и JavaScript. Среды разработки онлайн Существуют альтернативные среды разработки, доступные он­ лайн, прямо в вашем веб-браузере. Эти среды не очень удо бны, но если у вас нет другого выбора, вы можете начать обучение с них, а Visual Studio Code скачать позже. Одним из таких примеров явля­ ется сайт JSBin - https://jsbin.com/?js,console.
Глава 40 ~ С Начало работы в программировании 1. https://jsbln.com/molegihovu/edit?js.console i НТМL CSS JavaSc "pt • JavaScript Console Console 1et 1eva = 20 ; 1et euro = 1eva / 1.95583 ; co11s01e.1og(euro); 1 Output Run ] • Clear j 10.22583762392437 > Кроме того, для быстрого тестирования можно использовать браузер, нажав [F12], но это, как правило, бьmает удобно, когда нуж­ но быстро протестировать несколько строк кода. Вот пример: Elements [Itl 6) ... top » .: Filter DefaL1lt lev, Sources Console 0 х О > let leva = 20; let euro = leva / 1.95583; console.log(euro); 10.22583762392437 VМ431:3 undefined > Пример: консольная программа «Hello JavaScript» Давайте вернемся к нашей консольной программе. Теперь, ког­ да у нас есть в ней Visual Studio Code, мы можем запустить ее и написать JS-код. Затем мы создадим новый файл JavaScript: [File] - [New file]. о4 Visual Studio Code File Edit Selection Nev, File Vie\·t Go Debug Help Ctr1+N 1 Nev, Windo,•, Tasks Ct, Sh~ ,.,_ Open File... Open Folder... (Ctrl+K Ctr1+O) ► Open Recent Save Ctrl• S
Пример: консольная программа «Hello JavaScript» 41 Далее необходимо сохранить наш файл с помощью коман­ ды [File] --+ обязательно сохранив его с расширением [Save], Мы также дадим ему осмысленное имя, например .js. helloJS: 114 SaveAs х > This РС > Deslctop > JS Organize • v .Р Search JS (.) New folder ,. lllame - ТhisPC Туре Date modif;ed J 3D Objects No ,tems match your search. • Desktop J'I Documents • Downloads J, Music V > ( file name:~ helloJS.js Save as type: Plain Text л V Hide Folders 11 Save Cancel 11 Написание программного кода Написание кода JavaScript не требует никакой дополнительной подготовки, кроме той, что мы уже сделали - создали файл с рас­ ширением . j s . Поэтому мы переходим непосредственно к написа­ нию нашей первой строки кода. Пишем следующую команду: console.log("Hello JavaScript!"); Вот как должна выглядеть наша программа в Visual Studio Code: Р(1 helloJS,js - Visual Studio Code file fdit S,election 'fje-,•, EXPU>RfR , OPEN EDIТORS ► о х !i<> Qebug Iasks 1:!elp JS helloJSJs 1 CD х console. log( "Hello JavaScript ! ") ;j XML DOCUMENТ F:1 Q OAO Ln 1, Col 34 Spaces: 4 UТF-8 CRlf JavaScnpt е
Глава 42 1. Начало работы в программировании Команда console. log( "Hello JavaScript ! ") означает выпол­ нение вьmода (log( ... )) в консоли (console) с сообщением Hello JavaScript! , которое мы должны заключить в кавычки, чтобы по­ яснить, что это текст. В конце каждой команды вим символ ;, JavaScript мы ста­ который указывает на то, что команда заканчива­ ется в этой точке (то есть не продолжается на следующей строке). Хотя последнее не является обязательным, это р екомендуемый ме­ тод форматирования кода, чтобы впоследствии избежать ошибок, которые потом трудно найти. Эта команда очень типична для программирования: мы даем команду найти объект (в данном случае консоль) и, используя его, выполнить какое-то действие (в данном случае вывести что­ то, что указано в скобках) . Если объяснять техническим языком, то мы вызываем метод log( . .. ) класса console и передаем ему в ка­ честве параметра текстовый литерал "Hello JavaScript ! ". Внимание: использованные ранее команды alert ( ... ) и prompt( ... ) работают только в веб-брауз ере и недоступны в кон­ сольных приложениях VS Code. Если вы попытаетесь их использо­ вать, то получите ошибку. Запуск программъ1 Для запуска программы нажмите [F S], и программа запустится. Результат будет вьmеден в консоль, которая для нашего удобства будет открыта прямо в нижней части Visual Studio Code: □ х Qebu9 I,,sks tlelp EXPLORfR JS , OPEN EDIIORS JS h, helloJS.js [D х console.log(•нe:]o )avaScript!•}; I 1 JS ► NO FOI.DER OPENED ► XML DOCUMENТ OROE ЕМS О!Г"Р\JТ with i "•ected. р __ ;ns<>ect 5 oeЬugg1ng w е DEBUG CONSOI.E oeЬugger .:1 о - TERVl"I.:... 1 .Ь ~-br •cause 1 s. s h . 11 1!: л Х 7 listening on ws://127.0.0.l : 33758/0dalldll-49fb • 42C8 -a8aa - 340d9d52bЬбd ! нello JavaScript 1! Результатом работы программы является текстовое сообщение: Hello JavaScript!
Пример: консольная программа «Hello JavaScript» 43 Сообщения Debugging wi th inspector protocol ... и Debugger listening оп ... дополнительно отображаются в верхних строках консоли Visual Studio Code после начала выполнения программы, предоставляя нам дополнительную информацию о выполнении, которую мы можем пока проигнорировать. Проверка программъ1 в системе Judge Проверка задач в этой книге автоматизирована и осуществля­ ется через Интернет, на сайте системы SoftUni Judge: https://judge. softuni.bg. Оценка заданий производится системой в режиме реаль­ ного времени. Каждое задание проходит серию тестов, и за каждый успешно пройденный тест начисляются предусмотренные за него баллы. Тесты, которые проводятся над заданиями, скрыты. Описанную выше программу можно проверить здесь: https:// judge.softuni.bg/Contests/Practice/Index/926#0. Любой код JavaScript, который мы хотим проверить в системе Judge, должен быть окружен следующими строками дополнитель­ ного кода: function solve ( ) { / / помещаем наш код здесь } То есть если мы хотим проверить только что написанную про­ грамму через систему, она будет выглядеть следующим образом: function solve ( ) { console . log( "Hello JavaScript "); } Поместите весь исходный код программы в черное поле и выбе­ рите код JavaScript, как показано здесь: 01. Hello JavaScript Позаолено ереме : 0.100 sec. 1JavaS«ipt code (Nod._ ПО3ВО/1fН3 naмer. 16.00 мв • nИ.Пргn, 1 Size limit 16.00 КВ Chec·ker: Trim О ("Позволено време" с болгарского переводится как «допустимое время», "позволена памет" - «допустимая память».)
Глава 44 1. Начало работы в программировании Отправьте решение для оценки с помощью кнопки [Отправи т ь] ("Изпрати"). Через несколько секунд система вернет результат в та­ блицу с отправленными решениями. При необходимости можно нажать кнопку [Refresh] в правом верхнем углу таблицы отправ­ ленных на пр оверку решений: Иэnратен" решен,1Я Точк,1 Изпа~звэно време и памет Памет: 100/100 7.18 MS Време: 0.015 s Памет: ХО / 100 7.22 МВ Време: 0.015 s ► Иэпраrено на 12:40:04 05.06.2017 ii\мf i'liii 13:13:3005.06.2017 1.1; i Фi о ►1 «Изпратени решения» переводится как «отправленные реше­ ния», « точки» - количество баллов, «исползвано время и памет» - «использованное время и память», « изпратено на » - дата отправ­ ки и, наконец, «детайли» переводится как «детали » . Система Judge отобразит в таблице отправленных решений один из следующих возможных результатов : • Количество баллов (от О до успешно компилируется 100), (без если представленный код синтаксических ошибок) и может быть протестирован. о Если решение правильное, все тесты выделены зеле­ ным цветом и мы получаем о 100 баллов. В неправильном решении некоторые тесты о тмечены красным, и мы получаем неполные б аллы или О бал­ лов. • Если программа неверна, мы получим сообщение об ошиб­ ке во время компиляции. Как зареrистрироватъся в Мы используем нашу SoftUni Judge? идентификацию (имя пользователя (usemame) + пароль (password)) с сайта softuni.bg (https://softuni.bg/). Если у в ас нет р еrистрации в SoftUni, пройдите ее. Это займет всего пару минут.
Выполнение кода в браузере с помощью HTML + JS 45 Выполнение кода в браузере с помощью HTML + JS Мы рассмотрели, как можно создать и запустить консольную программу. Теперь давайте посмотрим, каким образом можно на­ писать и потом скомпилировать ее в браузере . Все сайты, которые вы по сещаете, создаются подобным образом. На самом деле принцип очень похож на то, что мы только что сде­ лали. Разница в том, что при создании нового файла мы даем ему . j s, расширение не а . html. Затем все, что нам нужно сделать, это окружить наш код открывающим НТМL-тегом <sciprt > и закрывающим </script >. Ранее мы похожим образом ограждали наш код, чтобы его можно было протестировать в системе как теперь будет выглядеть наш код в 15) <> helloJS.html 1 EDIТORS el р □ х aeoog ~sks !:!elP EXPLORfR • OPEN Вот Visual Studio Code: 11(1 helloJS.html - ViSU.11 Studio Code f1le fdn ie!ecoon J!!O\• !i_o Judge. 2 3 S. > NO IOU>ER OPENIO [D х .•• <script> console. 1ов( "Hello ).>vaScript 1") ;j </script> > XML DOCUMENТ Ln 2. Col 38 оо до Spaces: 4 UTf-8 CRLF При таком подходе нам остается только найти файл НТМL @) helloJS. html там, где мы его сохранили, и дважды щелкнуть по нему. Он загру­ зится в браузере, но чтобы увидеть результат его вьmолнения, нам нужно будет нажать [F12], что приведет к загрузке консоли браузера. Мы задали команду для вывода в консоль, и вот что у нас вышло: ~ 6] 1Е] Э ! Elements top Х » Console "' Filter Default lev helloJS . html:2 Hello Ja vaSc r i pt ! > Console What's New х х
Глава 46 1. Начало работы в программировании Теперь, когда вы знаете, как вьшолнять программы, вы можете про­ тесгировать приведенные выше примеры программ, которые отобра­ жают уведомления для пользователя. Получайте удовольствие, вы­ полняя эти программы. Попробуйте изменить их и «поиграть» с ними. Замените команду console.log("Hello JavaScript" ); на console. occurred"); и запустите программу. Обратите вни­ error("Error мание, что программы с уведомлениями можно вьmо.JШЯть только через браузер, а при попытке вьmоJП-IИТЬ их через консоль программа выдаст ошибку. Это связано с тем, что консоль не имеет функциональ­ ности для оповещения через визуальные элементы, такие как alert. Типичные ошибки в программах на Одна из распространенных ошибок JavaScript путаница заглавных - и строчных букв, а они имеют значение при вызове команд и их правильной работе . Вот пример такой ошибки: function solve() { Coпsole.Log("Hello JavaScript"); } В приведенном выше примере и ее следует исправить на Console написана неправильно, console. Какая еще подобная оumбка до­ пущена в программе? Проблемой также может быть пропущенная кавычка или отсут­ ствие открывающей или закрывающей скобки. Это приводит к сбо­ ям в работе программы или к тому, что она вообще не запускается. Такое упущение трудно заметить в более громоздком коде. Вот при­ мер неправильной программы с такой ошибкой: function solve() { console.log("Hello JavaScript); } Эта программа выдаст ошибку после начала выполнения, и даже до этого код будет подсвечен отслеживающими его расширениями, чтобы обратить внимание программиста на допущенную им оumб­ ку (пропущенную закрывающую кавычку): 1 JS ~llcuSjs 1 • console . log(:нello JavaScript).J (js] Untera,inated string literal. (jshint] Unclosed string. (W112)
47 Что мы узнали из этой главы? Что мы узнали из этой главы? Прежде всего мы узнали, что такое программирование - это за­ дание команд на компьютерном языке, которые машина понима­ ет и может выполнять. Мы также узнали, что такое компьютерная программа - это серия команд, следующих одна за другой. Мы по­ знакомились с языком программирования JavaScript на базовом уровне и узнали, как создавать простые консольные и веб-програм­ мы с помощью Visual Studio Code. Мы увидели, как выводить дан­ ные в консоль с помощью команды скать нашу программу с помощью наш код в системе console. log( ...) и как запу­ [F5]. Мы узнали, как тестировать Judge от SoftUni. Отличная работа! Давайте приступим к упражнениям. Вы ведь не забыли, что программирование изучается с помощью написа­ ния кода и решения задач? Давайте решим несколько задач, чтобы закрепить полученные знания. Упражнения: первые шаги в программировании Итак, приступим к упражнениям. Сейчас мы напишем не­ сколько консольных программ, чтобы сделать еще несколько ша­ гов в программировании, а затем покажем, как можно создавать что-то более сложное - программы с графическим и веб-интер­ фейсом. Задача: консольная программа «Expression» Напишите консольную JavaScript-пporpaммy, которая вычисляет и выводит значение следующего числового выражения: (3522 + 52353) * 23 - (2336 * 501 + 23432 - 6743) * 3 Примечание: не допускается вычислять значение заранее (на­ пример, с помощью Windows Calculator). Рекомендации и подсказки Создайте новый файл JavaScript с именем expression.js. Затем нам нужно написать код, который вычислит приведенное в усло­ вии числовое выражение и выведет в консоль его значение. Мы пе-
Глава 48 1. Начало работы в программировании редаем приведенное выше числовое выражение в круглых скобках команде console.log( ...): JS expressionJs х console.log(( 3522 + 52353 ) ~ 23 ( 2336 * 501 + 23432 - 674 3 ) ~ 3 ) ; 1 2 Запустите программу с помощью [F5] и проверьте, совпадает ли результат с тем, что показан на картинке: !!J expression.js • JS8ook • Visu•I Studio Code о х File Edn Select!on V~w Go Oebug Tasi<s 1- elp ► DES.JG , • i;l9 [I] JS express1on.Js 1 2 VAR1A8LВ [I] х console.log (( 3522 + 52353) * 23 · ( 2336 * 501 + 23432 - 6743 ) х 3 );1 • WAT01 P ROB Ш.1 S JEBUG COII.SOLE Debuui - .tl 1 •~ecto prvtocol Ьecaus~ пос'~ ---~sr-~ •Jj jJ he •• n S.JS ~~ ~.1 8.3 э Debugger l istening on ws: //127.9.0.1:33938/1913d337 - Sf95 • CALL SТАСК -2275950 helloJS . j s: 1 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/926#1. Примечание: не забудьте заключить ваш код в функцию solve(): function solve( ) { / / ваш код } 02. Expression 1 f .·,, · 2 з } , :г 0<1~: { 1 ~о . . :,г( ( 3522 52 353} · 2 3 ( 2 336 · 501 2343 2 6743 } · 3 };
Упражнения : первые шаги в программировании 49 Результат тестирования в системе Judge выглядит примерно так: Allowed worklng tlme: 0.100 sec. Allowed memory: 16.00 МВ Size limit: 16.00 КВ Che<:ker: NumЬersChecker O С1 .. Time and memory used Points Submission date Memory: 11.25 МВ ✓ 100 / 100 - 08:25:37 16.03.2018 Time: 0.234 s ◄ о ► ► Задача: числа от С1 1 до 20 Напишите консольную программу на дит числа от Submit Submissions ... о ► ◄ JavaScript code (Nod... • JavaScript, которая выво­ 1 до 20 на отдельных строках в консоли. Рекомендации и подсказки Создайте новый файл JavaScript с именем nums1To20.js. В нем 20 команд console. log( ... ), каждую в отдельной стро­ ке, чтобы вывести числа от 1 до 20 одно за другим: мы напишем !О] nums1Тo20.js - JSBook - Visual Studio Code File Edrt Selecuon DEBJG ,1, ► VARIABLES Viev, • Go -f:;? Debug [I] о Tasks 1-elp m JS nums1Тo20.js х 1 2 3 х console .log( l ) ; console .log{ 2) ; console .l og{ З ) ; ;I console . l og{4 ) console .log( S) ; Теперь мы запускаем программу и проверяем, будет ли резуль­ тат соответствовать нашим ожиданиям: 1 2 20
Глава 50 1. Начало работы в программировании Многие из вас, вероятно, задаются вопросом, есть ли более ра­ зумный способ. Он действительно есть, но об этом позже. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/926#2. Получили ли вы 100 баллов? Если нет, подумайте, чего вам не хватает. А потом подумайте, можно ли написать программу бо­ лее разумным способом, чтобы не повторять одну и ту же коман­ ~ 20 раз. Поищите в Интернете информацию о «for loop JavaScript» (https://www.google.bg/search?q=for%2Bloop%2BJavaScript). Задача: треугольник из 55 звезд Н апишите консольную программу на JavaScript, которая дит треугольник из 55 звездочек, расположенных в 10 рядов: выво­ * ** *** **** ***** ****** ******* ******** ********* ********** Рекомендации и подсказки Создайте новый файл JavaScript с именем triangle0f55Stars. j s. В нем нам нужно написать код, который выводит треугольник из звездочек, например, с помощью 10 команд, как показано ниже: console.log("*" ) ; console.log('' ** '' ); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/926#3. Попробуйте улучшить решение так, чтобы в нем не было много повторяющихся команд. Можно ли это сделать с помощью цикла for? Смогли ли вы найти более разумное решение (например, с по-
Упражнения: первые шаги в программировании 51 мощью цикла) для предыдУЩей задачи? В этой задаче можно ис­ пользовать что-то п охожее, но немного сложнее (два цикла, один внутри дPyroro). Если у вас не получилось, не беда, мы будем изу­ чать циклы в следующих главах, и тогда вы вспомните эту задачу. Задача: площадь прямоугольника Напишите программу на JavaScript, которая, получив два числа а и Ь, вычисляет и выводит площадь прямоугольника со сторона­ ми а и Ь. Примеры ввода и вывода ь а 2 1 7 Площадь 1 14 а ь Площадь 12 5 60 а ь Площадь 7 1 8 ' 56 Рекомендации и подсказки Создайте новый файл JavaScript. На данный момент мы будем те­ стировать этот тип программы только в системе Judge, в которой есть механизм ввода данных в программу. Чтобы программа полу­ чила два числа, нам нужно объявить об этом, изменив ранее пре­ доставленный код (функцию ?Эj rнtany"" "·J- - JSBoo File Edit Selectton solve( )), который мы писали раньше: о osua St,dic Co-.s х V e,v Go Debug Taslcs 1-elp EXP10RE~ JS • OPEN EDITORS ectang eAtea~s • JSВOOK JS expressionjs ·> helloJS.html JS helloJS.js JS nums 1Тo20Js ---- re<tangleArea.js 1 2 3 4 х function solve d[a, b]D { // your code goes here } [I]
Глава 52 1. Начало работы в программировании Вы заметили изменения? Между круглыми скобками О мы по­ ставили дополнительные квадРатные скобки в свою очередь, описали, какие данные мы [], между которыми, ожидаем получить - в данном случае числа а и Ь . Осталось написать приведенную выше программу для вычисления площади прямоугольника и вывести результат ее вьmолнения в кон­ соль. Используйте ставшую уже привычной командУ console . log() и передайте ей произведение чисел а и Ь в круглых скобках. В про­ граммировании умножение выполняется с помощью оператора *. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/926#4. * Задание: квадрат из звездочек Н апишите консольную программу на чает целое число Nи JavaScript, которая полу­ выводит в консоль квадрат из N звездочек, как показано в примерах ниже. Примеры ввода и вывода Ввод 1 3 Вывод Ввод Вывод Ввод Вывод *** 4 **** 5 ***** * * * * * * ***** * * * * *** * * **** Рекомендации и подсказки Создайте новую консольную программу JavaScript: !!) stars.js • JSSook • V,suol Studio Code ~Ьug □ ~sks х JS stars.js 4 OPENIOITl">RS 1 funct ion solve( [n}) { 2 3 JS JS express,on~s 4 ~loJS.html S heOoJS.JS б 7 х h•lp } solve([3 ]); solve([4] ); solve([S}); [П
Консольные, графические и веб-приложения 53 Доработайте приведенную выше программу для печати квадРа­ та из звездочек. Может потребоваться использование циклов for. Поищите информацию в Интернете. Внимание: эта задача сложнее остальных, и она специально дана сейчас и помечена звездочкой, чтобы спровоцировать вас на поиск информации в Интернете. Это один из самых важных на­ выков, который необходимо развить при изучении программирова­ ния: искать информацию в Интернете. Это то, что вы будете делать каждый день, если будете работать программистом, поэтому не пу­ гайтесь, а попробуйте. Если у вас возникнут трудности, вы также можете обратиться за помощью на форум SoftUni: https://softuni.bg/ forurn. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/926#5. Консольные, графические и веб-приложения В консольных приложениях, как вы уже догадались, все опера­ ции чтения ввода и печати вывода вьmолняются через консоль. Входные данные, которые считываются приложением, вводятся там же, а выходные данные выводятся там же после или во время выполнения программы. Если консольные приложения используют текстовую консоль, то веб-приложения - веб-интерфейс пользователя. Для их вы­ полнения необходимы две вещи - веб-сервер и веб-браузер, при­ чем браузер играет главную роль в визуализации данных и вза­ имодействии с пользователем. Веб-приложения гораздо удобнее для пользователя, выглядят визуально гораздо лучше, управляются мышью и прикосновениями пальцев (на планшетах и телефонах), но за всем этим стоит программирование. Поэтому нам придется научиться программировать, и мы уже сделали первые, очень ма­ ленькие шаги. Графические (GUI) приложения имеют визуальный пользо­ вательский интерфейс, непосредственно на вашем компьюте-
Глава 54 1. Начало работы в программировании ре или мобильном устройстве, без необходимости использования веб-браузера. Гр афические приложения (десктопные приложения, или, другими словами, настольные приложения) состоят из одного или нескольких графических окон, содержащих определенные эле­ менты управления (текстовые поля, кнопки, картинки, таблицы и т. д.) , которые служат для диалога с пользователем в более инту­ итивной форме. Мобильные приложения на телефоне и планшете похожи: мы используем формы, текстовые поля, кнопки и другие элементы управления и управляем ими с помощью программного кода. Именно поэтому мы сейчас учимся писать код: в разр аботке программного обеспечения код присутствует везде. Упражнения: веб-приложения Сейчас мы создадим простое веб-приложение, чтобы получить представление о том, что мы сможем создавать по мере углубле­ ния в программирование и разработку программного обеспечения. Мы не будем вдаваться в подробности используемых приемов и конструкций с самого начала, просто посмотрим на макет и функ­ циональность того, что мы создали. Прогрессируя в своих знаниях, мы сможем создавать большие и сложные приложения и системы. Надеемся, приведенные ниже примеры зажгут ваш интерес и не от­ пугнут вас. Задача: неб-приложение « Сумматор чисел» Н апишите веб-приложение, которое вычисляет сумму двух чисел. Когда два числа вводятся в первые два текстовых поля и на­ жимается кнопка [Calculate], вычисляется их сумма, и результат отображается в третьем текстовом поле. Для нашего приложения мы будем использовать граммирования HTML, который в JavaScript позволяет создавать веб-приложения и веб-сайты в среде разработки HTML - сочетании с языком про­ Visual Studio Code. это язык разметки, используемый для описания ин­ формации, которая содержится на веб-сайте. Не вдаваясь в излиш­ ние подробности, отметим лишь, что HTML основан на использо­ вании комбинаций тегов для визуализации и передачи семантики
Упражнения : веб-приложения 55 содержимого. В одном из предыдущих примеров мы уже создали НТМL-страницу и использовали тег <script>. Обратите внимание, что мы собираемся создать веб-приложе­ ние. Это приложение, доступное через веб-браузер, как ваша люби­ мая почта или новостной сайт. Веб-приложение будет иметь сер­ верную часть часть (back-end), написанную на JavaScript, и клиентскую (front-end), написанную на HTML. Ожидается, что веб-прило­ жение будет выглядеть примерно так: С + j Calculate * (D sumator.html = J В отличие от консольных приложений, которые считывают и вы­ водят данные в текстовом виде в консоль, веб-приложения имеют пользовательский веб-интерфейс. Веб-приложения загружаются с некоторого интернет-адреса (URL) через стандартный веб-брау­ зер. Пользователи записывают входные данные на странице, ото­ бражаемой веб-браузером, данные обрабатываются на веб-сервере, и результаты снова отображаются на странице в веб-браузере. Как уже говорилось, мы будем использовать HTML и JavaScript для на­ шего веб-приложения. Другие технологии, позволяющие создавать веб-приложения - это, например, технология ASP.NET МVС, техно­ логия РНР и т. д. Эти технологии по зволяют легко создать общую структуру приложения - на стороне сервера и на стороне клиента. Давайте приступим к реализации нашего приложения. В VS мы создадим новый НТМL-файл, который назовем sumator. ht ml : ~ sumator.html - JSBook - V-1Sual Studio Code File Edit Selection Viev, Go EXPLORER _. OPEN EDITORS о Debug Tasks Code х relp <> sumator.html х .L <> sumator.html Мы напишем следующий код в созданном файле: r:п •••
Глава 56 1. Начало работы в программировании 1 !О.) wrmtor.html · JS8cck • V,su•I Studio Code Fil• Eds Selection v_, Go O.Ьug То,Ь □ [D о sumэ.torJ'rtml х 1 2 3 4 S б 7 8 9 10 11 12 13 14 15 16 х 1-•lp <ntml> <Ьоdу> <input type="number " id="firstllumber" /> + <inpu-t type;"number" id::•secondNшaber" /> :.: <input type="number " id="result" /> <br /> <input type="button" id= "calculateButton" value="Calculate" /> <script> function calculate() { let firstNumber = parseint(document. getElementByid("firstNu11tber"). value); let secondllumber = parselnt(document. getElementByld("secondtJumber") . value); document.getElementByld("result") . value = firstNumber + secondNumber; 17 18 } 19 20 21 22 23 let calculate8utton = document . getElementByid("calculateButton") ; calculateButton . addEventlistener ("click", ca l culate); </script> </body> Этот код создает веб-форму HTML с тремя текстовыми полями и одной кнопкой. Указано, что нажатие на кнопку зовет действие [Calculate] вы­ calculate. Давайте подробнее рассмотрим код, кото­ рый мы только что написали. Первые две строки объявляют, что мы собираемся описать НТМL-страницу с помощью тегов <html> и <body>, которые объяв­ ляют начало тела нашей страницы - или основной ее части, кото­ рая будет выведена на экран. В последних двух строках у нас соот­ ветствующие закрывающие теги, которые объявляют конец поля. Вы можете заметить, что они отличаются от открывающих тегов наличием слеша перед названием - например, </body>. В теле нашей страницы мы используем НТМL-теги, чтобы опи­ сать то, что мы хотим вывести, а именно три поля, в которые мож­ но вводить числа. Для этого мы используем тег ber">. <input type="num- С помощью этого тега мы объявляем, что хотим иметь поле для ввода данных типа number. Дополнительный атрибут id исполь-
Упражнения : веб-приложения 57 зуется для указания уникального имени этого тега. Это имя совер­ шенно необязательно. Атрибут id понадобится нам позже, чтобы использовать именно этот конкретный НТМL-элемент: ~ sumator.html • JS8ook • Vosual Studio Code <> s1Jmator.html 1 2 з 4 5 6 7 8 22 23 24 25 . - Help [II х <html> <body> <input type="number" <input type="number" <input type="number" <br /> <input type="button" <script> ... </script> </body> </html> ... i d="firstNumber" /> + id ="secondNumber" /> = id ="result" /> id ="calculateButton" value=''Calculate" /> 1 Затем в строке е го тип х о File td~ Selection Vie-.v Go ~bug Tasks button. 7 мы объявляем еще один тег input, на этот раз Таким образом мы указываем, что хотим иметь элемент, на который можно нажать и который приведет к опреде­ ленным действиям. Теперь давайте посмотрим на код JavaScript, который мы напи­ сали: 9 10 11 12 13 function calculate() { let firstNumber = parseint(document.getElementByid("firstNumber").value); let secondNumber = parseint(document.getElementByid("secondNumber").value); 14 15 16 17 document . getElementByid("result") . value = firstNumber + secondNumber; } 18 19 let calculateButton = document.getElementByid("calculateButton"); 20 21 calculateButton . addEventlistener("click", calculate); Сначала мы объявляем функцию calculate( ), которая считывает информацию из первых двух текстовых полей (с нашей НТМL-стра­ ницы), затем вычисляет сумму и присваивает ее в качестве зна­ чения третьего поля. Функция продолжается с 9-й по 17-ю строку.
Глава 58 1. Начало работы в программировании О том, что такое функции, как они объявляются и как вызываются, мы узнаем чуть позже в этой книге. Давайте рассмотрим тело функции более подробно. В строке 10 мы объявляем переменную ние текстового поля с firstNumber, присваивая ей значе­ id=firstNumber. Функция parseint( ... ) га­ рантирует, что введенный текст будет преобразован в число. Затем аналогичным образом получаем значение второго текстового поля (с id=secondNumber). Наконец, используя тот же механизм, вместо того чтобы взять значение третьего поля с id=result , мы присваи­ ваем ему значение, помещая его в левую часть равенства. Затем в строках 19 и 20 мы обращаемся к нашей кнопке и указы­ ваем ей, чтобы она ожидала события нажатия да такое событие произойдет, выполнила (click) на нее, а ког­ функцию calculate(), которую мы объявили минуту назад. Другими словами, когда мы щелкнем мышью на нашей кнопке, будет вьmолнена функция calculate (). Приложение готово. Мы можем запустить его, найдя файл в фай­ ловой системе и открьm его. Оно загрузится в нашем браузере по умолчанию. Выглядит страшно? Не пугайтесь! Н ам предстоит еще много­ му научиться, чтобы достичь уровня знаний и умений, позволяю­ щих свободно писать веб-приложения, как в примере выше, и го­ раздо более крупные и сложные. Если у вас что-то не получается, ничего страшного, просто двигайтесь дальше. Со временем вы бу­ дете с улыбкой вспоминать, каким непонятным и захватьmающим было ваше первое знакомство с веб-программированием. Цель приведенного выше примера (веб-приложение) - не нау­ чить, а углубиться в программирование, зажечь ваш интерес к раз­ работке программного обеспечения и вдохновить вас на усердное обучение . Вам еще многому предстоит научиться, но ведь это инте­ ресно, не так ли?
Глава 2.1. Простые вычисления В этой главе мы рассмотрим следующие понятия и приемы про ­ граммирования: • Как работать с типами данных и переменными, которые нужны нам при обработке чисел и строк. • Как вывести результат на экран. • Как считывать пользовательский ввод. • Как выполнять простые арифметические операции: сложе­ ние, вычитание, умножение, деление, конкатенация строк. • Как окруrлятъ числа. Вычисления в программировании Компьютеры известны как устройства для обработки инфор­ мации. Все данные хранятся в памяти компьютера переменных. Пер еменные - (RAM) в виде это именованные обла сти памяти, в которых хранятся данные определенного типа , например , чис­ ла или текст. Каждая переменная в JavaScript имеет имя и зна­ чение. Вот как мы объявляем переменную, присваивая ей значение од­ новременно с объявлением: ~ Объявление , ! ~ L let ;, t coun Имя переменной = 5 ; -.::::::l J Значение (тип числа) l По сле обработки данные записываются обратно в переменные (то есть куда-то в память, выделенную нашей программой).
Глава 60 2.1. Простые вычисления Типы данных и переменные В программировании каждая переменная хранит значение определенного типа. типами данных могут быть, например: число, текст (строка), булевый тип, дата и т. д. Вот несколько примеров ти­ пов данных и значений для них: • numЬer - число: 1, 42, -5, 3.14, NaN, ... • string - текст (строка): 'Hi', 'Beer', ... • boolean - булевый тип (логический): true, false • Date - дата: Tue Jul 04 2017, ... В JavaScript есть три ключевых слова для объявления перемен­ var, const и let. Основное различие между let и var заклю­ чается в области существования переменной. const мы используем, ной. Это когда уверены, что значение, которое мы присваиваем перемен­ ной, не изменится. Чуть дальше в книге мы узнаем больше подроб­ ностей о диапазоне существования переменных, а пока мы будем использовать let для объявления новой переменной. Вывод результата на экран Чтобы вывести на экран текст, число или любой другой резуль­ тат, нам нужно вызвать встроенный метод con sole. log (). С его по­ мощью мы можем вывести значение переменной, а также непо­ средственно текст или число: console.log(42); // console.log('Hello! ' ); // let msg = 'Hello, JavaScript! '; console.log(msg); // вывод числа вывод текста вывод значения переменной Считывание пользовательского ввода - целое число Чтобы считать введенные пользователем данные в виде целого числа, нам нужно определить параметры (аргументы) нашей функ­ ции: function sum([argl, arg2]) { let parseint(arg2); } а= parseint(argl); let Ь =
Считывание пол ьзовательс кого ввода - целое число Обратите внимание, что параметры 61 и argl arg2 могут иметь дРуrой тип данных, который отличается от того, что нам нужно. Поэтому необходимо преобразовать их в подходящий. Если этого не сделать, то каждое число будет для программы просто текстом, с которым нельзя будет выполнять арифметические действия. Пример: вычисление сторонъ1 квадрата со стороной а В качестве пример а р ассмотрим следующую функцию, которая считывает целое число, умножает его на себя (возводит в квадр ат) и выводит р езультат умножения. Таким обр азом мы можем вычис­ лить площадь квадрата по заданной длине стороны : fu nction cal culateSquareArea ( [argl ] ) { let let area = а* а; console . l og( ' Square area = ' + area); а= parseint(argl ); } Если мы вызовем нашу функцию с параметром 3, то е сть calculateSquareArea ( [ з]) , то р езультатом выполнения кода будет Square area = 9. Вот как выглядит наш код в действии в консоли веб-бра­ узера: Elements [Ш Э Console ... top :• х Filter Default lev, О Sources 0 » > function calculateSquareArea ( [argl] ) { let а = parseint(argl ) ; let area = а * а; console . log( 'Square area = '+ area ) ; } undefined > calculateSq uareArea ( [S] ) Square area = 25 VM676:4 Если мы попьпаемся ввести недопустимые данные, например "hello", то получим сообщение об оnm:бке (исключении) во время вы­ полнения. Это нормально . Позже мы увидим, как можно отлавливать такие оnm:бки и возвращать пользователю более содержательные со­ общения.
62 Глава 2.1. Простые вычисления Как работает пример ? В перв ой строке function calculateSquareArea( [argl ]) { мы определяем нашу функцию, давая ей имя и указывая параме­ тры, которые ей понадобятся. В нашем случае у нас есть один пара­ метр, который будет представлять сторону квадрата. В следующей строке let а = parseint(argl); мы берем параметр argl и преобразуем его в целое число с помощью метода parseint(argl);. Результат записывается в переменную с именем а. Примечание: Если argl содержит дробное число, оно будет пре­ функции образовано в целое. Преобразование дробного числа в целое осу­ ществляется путем удаления цифр после точки (или запятой), на­ parseint(2.3) = 2, parseint(З.8) = 3. Следующая команда let а rea = а * а; записывает в новую пере­ менную с именем area результат умножения а на а. Следующаякоманда соnsоlе.lоg ( 'Squаrе area = ' + area); пример: выводит указанный текст, добавляя к нему вычисленную площадь квадрата, которую мы сохранили в переменной area. На самом деле приведенную выше программу можно немного упростить, например, так: function calculateSquareArea( [a]) { let area console . log('Square area = '+ area ); =а* а; } Приведенный выше код будет работать правильно, потому что переменная а будет пр еобразована в число при умножении. Когда на вход подается только одно число, можно опустить ква­ дратные скобки [], как показано ниже: function calculateSquareArea(a) { let area console.log('Square area = '+ area ); =а* а; } Код можно сократить еще больше, например, так: function calculateSquareArea(a) { console . log( ' Square area = '+а* а); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#0. Попробуйте все версии р ешения.
Считывание дробного числа 63 Считывание дробного числа Чтобы считать введенные пользователем данные в виде дРОбно­ го числа, нам нужно использовать функцию parseFloat( ... ): function sum([argl, arg2]) { let а= parseFloat(argl); let Ь = parseFloat(arg2); } В приведенном выше примере пар аметры argl и arg2 преобразу­ ются в дР Обные числа в пер еменных а и Ь. Пример: преобразование дюймов в сантиметры Напишем функцию, которая считывает дРОбное число в дюймах и преобразует его в сантиметры: function convertinchesToCentimeters([argl ]) { let inches = parseFloat(argl); let centimeters = inches * 2 .54; console.log('Centimeters = • + centimeters); } Давайте вызовем функцию и убедимся, что при передач е значе­ ния в дюймах мы получим правильный р езультат в сантиметрах: convertinchesToCentimeters([S]); // Centimeters = 12.7 Проверка в системе Judge Пр оверьте свое решение: https://judge.softu ni.bg/Contests/Practice/ Index/927#1. Считывание ввода - текст Как и в случае с другими типами данных, для считывания текста нам нужно определить аргумент нашей функции, а затем присв о ­ ить его переменной: function print([argl ]) { let text = argl; }
Глава 64 2.1 . Простые вычисления Пример: приветствие с использованием имени Давайте напишем функцию, которая принимает имя пользова­ теля и приветствует его текстом "Hello, (имя)". function sayHello([argl]) { let name = argl; console . log('Hello, ${пате}!'); } В этом случае выражение ${пате} заменяется значением пере­ менной name. Вот результат, если мы вызовем функцию с именем "Ivan": sayHello(['Ivan']); // Hello, Ivan! Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#2. Объединение текста и чисел При выводе текста, чисел и других данных мы можем объеди­ нять их с помощью шаблонов' variaЫe = ${variaЫe}' В программировании такие шаблоны назьmаются . placeholders. Обратите внимание, что для распознавания шаблона необходимо использовать апо строф , , а не обычные кавычки: function printinfo([firstName, lastName, age, town]) { console.log('You are ${firstName} ${lastName}, а ${age}years old person from ${town}.'); } Мы снова вызываем функцию с тестовыми параметрами и убеж­ даемся, что она работает: printinfo( [ 'Ivan', 'Ivanov', 20, 'Sofia']); Помимо переменных в шаблонах можно вьmолнять простые вы­ числения. Одну и ту же переменную можно использовать в качестве ша­ блона несколько раз. Вот пример:
Арифметические операции let а= 1; console.log( ' ${a} 65 +$ {а}= ${а+ а} ' ); Результат: 1 + 1 = 2 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#3. Арифметические операции Рассмотрим основные арифметические операции в программи­ ровании. Сложение чисел (оператор +) Мы можем складывать числа с помощью оператора let а= 5; let Ь = 7; let sum =а+ Ь; // результат +: 12 Вычитание чисел (оператор -) Вычитание чисел вьmолняется с помощью оператора -: function substractNumbers([argl, arg2]) { let а= parseint(a); let Ь = parseint(b); let result = а - Ь; console.log(result); } Проверим результат выполнения функции (на числах substractNumbers([10, З]); 10 и 3): // 7 Умножение чисел (оператор*) Умножение чисел выполняется с помощью оператора let а= 5; let Ь = 7; let product =а* Ь; / / 35 *:
2.1 . Простые вычисления Глава 66 Деление чисел (оператор /) Деление чисел выполняется с помощью оператора /. Примечание: деление на О не приводит к ошибке, а результатом будет+/- бесконечность или специальное знач ение бесконеч­ ности. Вот несколько примеров использования опер атор а деления: console.log(10 / 2.5); console . log(10 / 4); console.log(10 / 6); console.log(a / 0) ; console . log(-a / 0); console.log(0 / 0) ; // // // // // // // // 4 2. 5 1.6666666666666667 Infinity -Infinity NaN (Not а Number ) Результат: Результ ат: Результат: Результат: Результ ат: Результат: результат операции допустимым числовым не является значением Объединение текста и числа Оператор +, помимо сложения чисел, также используется для объ­ единения текста (слияния двух строк друг за другом). В программи­ ровании объединение текста с текстом или с числом называется конкатенацией. Вот как мы можем объединить текст и число с по­ мощью оператора + : let firstName = "Maria"; let lastName = "Ivanova"; let age = 19; let str = firstName + + lastName + @ console.log(str ) ; // Maria Ivanova@ 19 11 11 11 11 + age; Вот еще один пример : let а= 1.5; let Ь = 2. 5; let sum = '' The sum is: ''+а + Ь; console.log(sum) ; // The sum is: 1.52.5 Заметили ли вы что-либо странное? Может быть, вы ожидали, что числа а и Ь сложатся? На самом деле конкатенация работает сле­ ва направо, и приведенный выше результат абсолютно верен. Если мы хотим сложить числа, нам придется использовать круглые скоб­ ки, чтобы изменить порядок операций:
Числовые выражения 67 let а= 1.5; let Ь = 2.5; let sum = The sum is: +(а+ Ь); console.log(sum); // The sum is: 4 11 11 Числовые выражения В пр ограммировании мы также можем вычислять числовые вы­ ражения, например: let expr = (3 + 5) * (4 - 2); Действует стандартное правило о пр иоритете арифметических операций: умножение и деление всегда выполняются пе ред сло­ жением и вычитанием. Если в скобках стоит выражение, то оно выполняется первым, но все это мы знаем из школьной матема­ тики. Пример: вычисление Шiощади трапеции Напишем функцию , которая берет длины двух оснований тра­ пеции и ее высоту (по одному дробному числу в строке) и вычис­ ляет площадь трапеции по стандартной математич е ской фор­ муле: function printTrapezoidArea([argl, arg2, argЗ]) { let Ы = parseFloat(argl); let Ы = parseFloat(arg2); let h = parseFloat(argЗ); let area = (Ы + Ы) * h / 2; console.log( Trapezoid area = + area); 11 11 } Поскольку мы хотим, чтобы наша функция работала как с целы­ ми числами, так и с дробными, мы используем мы запустим функцию и введем з , parseFloat(). Если 4 и 5 для сторон соответственно, то получим следующий р езультат: printTrapezoidArea([З, 4, 5]); // Trapezoid area = 17.5 Проверка в системе Judge Проверьте свое решение: Index/927#4. https://judge.softuni.bg/Contests/Practice/
Глава 68 2.1 . Простые вычисления Округление чисел Иногда при работе с дробными числами нам необходимо при­ вести их к целочисленному формату. Такое приведение называет­ ся округлением. Язык JavaScript предоставляет нам несколько ме­ тодов округления чисел: • округление вверх, до следующего (больше­ Math. ceil( ... ) го) целого числа: let up = Math . ceil(45 . 15); // up = 46 • округление вниз, до предыдущего (мень­ Math. floor( ... ) - шего) целого числа: let down = Math.floor(45.67); // down = 45 • Math. t runc( ... ) - усечение десятичных знаков: let trunc = Math.trunc(45 .67); / / trunc = 45 • Math. round ( ...) - округление производится по основному правилу округления - если десятичная дробь меньше округляем вниз и наоборот, если больше 5, 5, округляем вверх: Math.round(5.439); // 5 Math.round(5.539); // 6 • . toFixed( [количество знаков после запятой]) - округле­ ние до ближайшего числа с количеством знаков после за­ пятой: (123.456 ).toFixed(2); (123) . toFixed(2); (123.456).toFixed(0); (123 .512).toFixed(0); //123.46 //123.00 //123 //124 Пример : периметр и площадь окружности Давайте напишем функцию, которая принимает радиус r окруж­ ности и вычисляет площадь и периметр круга/окружности. Формулы : • • Площадь = n: *r*r Периметр = 2 * n: * r
Округление чисел • 69 п::::: З.14159265358979323846 ... function calculateCircleAreaAndPerimeter([argl]) { let r = parseint(argl); console . log("Area = "+ Math.PI * r * r); // Math.PI - встроенная в JavaScript константа // для значения числа л console . log("Perimeter = "+ 2 * Math.PI * r); } Вызовем функцию с радиусом r = 10: calculateCircleAreaAndPerimeter((10]) Результат следующий: Area = 314 . 1592653589793 Perimeter = 62 .83185307179586 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#5. Пример: грани прямоугольника на плоскости Даны координаты двух противоположных уrлов прямоуrольни­ ка. Вычислите его площадь и периметр: О 10 20 30 40 50 60 70 60 50 . . - - --- 1 -- - ... - . = 50 * 30 = 1500 30 = 2*(50 + 30) = 160 п лощадь 40 п ериметр 30 20 - - ---- • 50 • 1 10 о ' '' ' •1 1 1 1 i -- - .. - . 1 ( 1 1 . •• 1 i 1 В этой задаче мы должны учесть, что если из большей коорди­ наты х вычесть меньшую координату х, то мы получим длину пря­ моуrольника. Аналогично, если из большей у вычесть меньшую у, мы получим ширину (высоту) прямоуrольника. Осталось перемно­ жить две стороны. Вот пример реализации описанной логики:
Глава 70 function calculateRectangleArea([argl, arg2, let xl = parseFloat(argl); let yl = parseFloat(arg2); let х2 = parseFloat(argЗ); let у2 = parseFloat(arg4); 2.1. Простые вычисления argЗ, arg4)) { // Вычислите длинны сторон прямоугольника: let width = Math . max(xl, х2) - Math.min(xl, х2); let height = Math.max(yl, у2) - Math.min(yl, у2); console.log(width * height); console.log(2 * (width + height)); } Мы используем метод из значений xl и х2, Math . max(xl, х2), чтобы найти большее и аналогично Math.min(yl, у2) , чтобы найти меньшее из двух значений. Выз овем функцию с тестовыми значениями из системы коор­ динат: calculateRectangleArea([60, 20, 10, 50)); / / 1500 / / 160 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#6. Что мы узнали из этой главы? Давайте подведем итоги того, что мы узнали из этой главы книги: • Считывание пользовательского ввода: о • Преобразование в число: о о • function sum( [ numberl, number2]) let num let num = = parseint(argl) parseFloat(argl). Выполнение вычислений с числами и использование соот­ ветствующих арифметических операторов о let sum = 5 + 3. [+, - , *, /, ()] :
Упражнения: простые вычисления • Вывод текста в соответствии с шаблоном: о • 71 conso l e . log('З + 5 = ${3 + 5}') . Различные типы округления чисел: trunc(), math .floor() и math . ceil (), math . .toFixed() . Упражнения: простые вычисления Давайте закрепим полученные в этой главе знания с помощью нескольких упражнений. Пустой JS-файл для решения нашей задачи в VS Code Visual Studio Code. В этом Начнем с создания пустого JS-файла в практическом занятии мы создадим новую папку и добавим но­ вый JS-файл для каждой задачи, чтобы организовать решения за­ дач в упражнениях. Запустите Visual Studio Code и создайте новый файл: [File] --+ [New File]: 114 Visual Studio Code Edit Selection New File Viev, Go Debug I Task.s Help Ctrl+N NewWindow C.r St , Open File... Open Folder... [Ctrl+K Ctrl+O) ► Open Recent Сохраните файл в меню ния клавиш [Ctrl + S]: ll4 Untitled- 1 Edit [File] - [Save] или с помощью сочета­ Visual Studio Code Selection View Go Debug с NewFile Nev,Window Tasks Help + Ctrl+Sh1ft+N Open File..• Open Folder... [Ctn-,.K Ctrl+O) Open Recent ► ! Save ! SaveAs... Ctrl+S С r S !.
72 Глава 2.1 . Простые вычисления Мы дадим нашему файлу осмысленное имя и расширение а затем нажмем [Save]: х ~SaveAs 1' Organ,ze • > This РС > Desktop > JS v (J Searcn JS р NewfOlder л Name 1111 ThisPC з . j s, Туре Date moo,fied 30 Obje<U No tems ma::ch your search. • Desl:top • Documents • Do-,vnl0,>ds J, Music ., < > File oame: )cakulateSquareArea.js ) Save м ty~ Plain Text л 11 Hide Folders Save II Cancel Задача: нахождение площади квадрата Первая задача по теме этой главы состоит в следующем: напиши­ те функцию, которая получает целое число а и вычисляет площадь квадрата со стороной а. Задача тривиально пр оста: вы берете число в качестве параметр а функции, умножаете его на себя и выводите результат в консоль. Рекомендации и подсказки Теперь у нас есть пр авильно названный пустой файл. Осталось только написать код для решения задачи. Для этого мы напишем следующий код: function calculateSquareArea([argl ]) { let а= parseint(argl); let area =а* а; console.log(area); } В коде опр еделена функция принимает один параметр argl . calculateSquareArea(), которая Поскольку ожидается, что пара­ метр будет целым числом, мы преобразуем его с помощью метода parseint(), а затем вычисляем площадь: мы выводим значение переменной area. area = а * а. Н аконец, Для пр оверки нужно вы-
Упражнения : простые вычисления 73 звать функцию с произвольным параметром в том же файле, а за­ тем запустить программу, нажав 7 [Ctrl + FS]: calculateSquareArea([ S] ) ; PROBLEMS Square area OUTPUT = DEBUG CONSOLE TERMINAL 25 Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/927#0. Вы должны набрать 100 баллов (полностью правильное решение): 01. Square Area Allowed working time: 0.100 sec. Allowed memory: 16.00 МВ Size limit: 16.00 КВ Checker: Numbers Checke1· О JavaScript code (Nod... • 1Su bmit ) Submissions ... ◄ о ► ►i Points ✓✓✓✓ 100 / 100 с, Time and memory used Memory: 11.16 МВ Submission date 15:16:4404.02.2018 - Time: 0.025 s Задача: из дюймов в сантиметры Напишите функцию, которая принимает число (не обязательно целое) и п ереводит ero из дюймов в сантиметры. Для этоrо она ум­ ножает дюймы на 2,54 (потому что 1 дюйм = 2,54 сантиметра).
Глава 74 2.1. Простые вычисления Рекомендации и подсказки Сначала создайте новый файл в папке с другими решени­ ями - Visual Studio Code в выберите [File] ➔ [New File]. Сохра­ ните файл под каким-нибудь подходящим именем, например convertinchesToCentimeters . js, и нажмите [Save]. Далее мы напи­ ш ем код программы: function convertinchesToCentimeters ( [argl ] ) { let inches = parseFloat(argl); let centimeters = inches * 2.54; console. log( 'Cent imeter s = • + centimeters); } Вызовите функцию с параметром мощью 2 и запустите программу с по­ [Ctrl + FS]: 7 convert inchesToCentimet ers([ 2)); PROBLEMS OUTPUT DEBUG CONSOLE TERMINAL centimeters = 5.08 Давайте протестируем программу с дробными числами, напри­ мер 4.5: 7 convertinchesToCentimeters([ 4 . 5 )); PROBLEMS Centimeters OUTPUT = DEBUG CONSOLE TERMINAL 11.43 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#1. Решение должно быть принято как полностью правильное: Submissions .. • • ► Points ..,..,., .., 100/ 100 ►i Time and memory used Submission date "1emory: 11.46 МВ 14:47:08 04.02.2018 Time:0.093s
Упражнения : простые вычисления 75 Задача: приветствие по имени Напишите функцию, которая принимает в качестве аргумента имя человека и печатает Hello, <name> !, где <name> - ранее вве­ денное имя. Рекомендации и подсказки Снова создайте новый файл в папке с другими решениями и со­ храните его под именем sayHello.js. Далее мы напишем код про­ граммы. Если у вас возникнут трудности, вы можете воспользоваться при­ мером кода, приведенным ниже: function sayHello([argl]) { let name = argl; console . log('Hell o, ${пате}!·, ) ; } Вызовите функцию со значением примера и запустите про­ грамму с помощью [Ctrl + FS], чтобы проверить, пр авильно ли она работает: 6 sayHello([' Ivan'J) ; pqoвLEMS DEBUG CONSOLE Hello, Ivan! Проверка в системе Ju.dge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#2. Задача: конкатенация текста и чисел Напишите функцию, которая получает в качестве аргументов (параметров) имя, фамилию, возраст и город и печатает сообщение You are <firstName> <lastName>, <age> - years old person from <town>. следующего вида : Указания и подсказки Аналогичным образом создайте новый файл и назовите его printinfo. j s. Код, который печатает сообщение, описанное в по-
Глава 76 2.1. Простые в ы числ ения становке задачи, намеренно размыт и должен быть дописан чита­ телем: fu nction print l nfo( [fi rstName, l ast Name , age, t O\•m]) { } Решение следует проверить локально, вызвав функцию с при­ мерными значениями и запустив программу с помощью [Ctrl + FS]. Проверка в системе Judge Проверьте свое решение: https://judge.softun.i.bg/Contests/Practice/ Index/927#3. Задача: площадь трапеции h и вычисляет площадь трапеции с основаниями Ы и Ы и высотой h. Формула для площади трапеции (Ы + Ы) * h / 2. На рисунке ниже из ображена трапеция со сторонами 8 и 13 и вы­ сотой 7. Ее площадь (8 + 13) * 7 / 2 = 73,5. Напишите функцию, которая принимает аргументы Ы, Ь2 и А в 8 с D 13 Рекомендации и подсказки Снова нужно создать в zoidArea. j s Visual Studio Code файл calc ulateTrape- и написать код, который считывает входные данные из параметров функции, вычисляет площадь трапеции и выводит
Упражнения : простые вычисления 77 ее на экран. Код на изображении намеренно размыт, чтобы чита­ тель мог подумать и дописать его самостоятельно: function calculateTrapezoidArea([argl, arg2 , let Ы = parseFloat (argl ) ; argЗ]) { console.log("Trapezoid area =" + area); } Проверьте решение локально, вызвав функцию и запустив ее с помощью [Ctrl + F5]. Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#4. Задача: длина (периметр) и площадь круга Напишите функцию, которая получает аргумент r, и выводит площадь и длину круга/окружности радиуса вычисляет r. Пример ввода и вывода 1 Ввод вывод Ввод Area = 28.2743338823081 Perimeter = 18.8495559215388 3 Вывод Area = 63.6172512351933 4. 5 Perimeter = 28 . 2743338823081 Рекомендации и подсказки Для расчетов вы можете использовать следующие формулы: • Area = Math.PI • Perimeter = 2 * r * r. * Math.PI * r. Проверка в системе Judge Пр оверьте свое решение : Index/927#5. https://judge.softuni.bg/Contests/Practice/
Глава 78 2.1. Простые вычисления Задача: площадь прямоугольника Прямоугольник задан координатами 1Ц3ух своих противополож­ ных углов (х2, у2) . Вычислите его площадь и периметр. (xl, yl) - Исходные данные принимаются в качестве параметра (аргумента) функции. Числа xl, yl, х2 и у2 задаются по одному в строке. Выходные данные выводятся в консоль и должны содержать две строки с одним числом в каждой строке - площадь и пери­ метр. О 10 20 30 40 50 60 70 60 50 - - ·- - -- - - - - - - - - . площадь= 50 * 30 = 1500 периметр = 2*(50 + 30) = 160 40 30 30 20 -- . - - --, _ _ _5_0_ __ 10 ' ' r' г ''' о Примеры ввода и вывода Ввод 60 20 10 50 вывод Ввод Вывод 30 1500 160 40 70 2000 180 -10 Ввод вывод 600 . 25 500.75 100.50 -200.5 350449.6875 2402 1 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#6. Задача: площадь треуголыmка Напишите функцию, которая принимает в качестве аргумента основание и высоту треугольника и вычисляет его площадь. Ис­ пользуйте формулу для площади треугольника : area = а * h / 2. Округлите результат до двух цифр после десятичной точки с по­ мощью функции area . toFixed(2).
79 Упражнения : простые вычисления Примеры ввода и вывода Ввод вывод 20 30 Triangle area = 300 7.75 8.45 Triangle area = 32.74 1 Ввод ВЫвод 15 35 Triangle area 1 . 23456 4 . 56789 Triangle area = 262.5 = 2.82 1 Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#7. Задача: конвертер - из градусов С в градусы 0 °F Напишите функцию, которая считьmает градусы Цельсия (0 С) и преобразует их в градусы Фаренгейта (°F). Найдите в Интернете под­ ходящую формулу для вьmоJПiения вычислений. Округлите резуль­ тат до двух знаков после десятичной точки. Вот несколько примеров: Примеры ввода и вывода Ввод ВЫвод 25 177 Ввод 0 Вывод 32 Ввод вывод - 5. 5 122 .1 Ввод вывод 32.3 190 . 14 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#8. Задача: конвертер - из радиан в градусы Напишите функцию, которая считывает угол в радианах и преобразует его в градусы (rad) (deg). Найдите в интернете подходящую
Глава 80 формулу. Число п в программах 2.1. Простые в ы числения JavaScript доступно через Math. PI. Округлите результат до ближайшего целого числа с помощью ме­ тода Math. round( .•• ) . Примеры ввода и вывода Ввод Вывод Ввод Вывод 3.1416 180 0.7854 45 6.2832 360 0.5236 30 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#9. Задача: конвертер - USD в BGN Напишите функцию для конвертации долларов США (USD) в бол­ гарские левы (BGN). Округлите результат до двух знаков после деся­ тичной точки. Используйте фиксированный курс между USD и BGN: 1 USD = 1,79549 BGN. Примеры ввода и вывода Ввод вывод 20 35. 91 BGN 1 Ввод Вывод Ввод Вывод 100 179. 55 BGN 12. 5 22. 44 BGN Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#10. Задача*: конвертер валют Напишите функцию для конвертации денежной суммы из од­ ной валюты в другую. Должны поддерживаться следующие валю­ ты : BGN, USD, EUR, GBP. Используйте фиксированные курсы об­ мена: Курс 1 BGN 1 USD 1.79549 1 EUR 1.95583 1 GBP 2.53405
Упражнения: простые вычисления На входе - 81 сумма для конвертации, валюта ввода и валюта вы­ вода. На выходе получается одно число - конвертированная сум­ ма по указанным курсам, округленная до двух цифр после десятичной точки. Примеры ввода и вывода Ввод 20 USD BGN Вывод Ввод 35 . 91 BGN 1 Ввод 100 BGN EUR Вывод Вывод 12.35 EUR GBP 9.53 GBP Ввод 51 . 13 EUR 1 Вывод 150 . 35 USD 138.02 EUR EUR Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/927#11. Задача** : Вычисление с датами - 1000 дней на Земле Напишите функцию, которая считывает дату рождения в форма­ те dd-MM-yyy, вычисляет дату, отстоящую на 1000 дней от этой даты рождения, и вьmодит ее в том же формате. Примеры ввода и вывода Ввод Вывод Ввод 1 вывод 25-02-1995 20-11-1997 14-06-1980 10-03-1983 07 -11- 2003 02-08-2006 01-01-2012 26 - 09-2014 Ввод вывод 30-12-2002 24-09-2005 Рекомендации и подсказки • Поищите информацию о типе Date в сти, обратите внимание на методы JavaScript и, в частно­ setDate( .. .), getDate(), getMonth() и getYear(). С их помощью вы сможете решить проблему, не прибегая к вычислению дней, месяцев и висо­ косных лет. • Не вьmодите в консоль ничего лишнего, кроме нужной даты!
82 Глава 2.1. Простые вычисления Проверка в системе Judge Проверьте свое решение: https://judge.softun.i.bg/Contests/Practice/ Index/927#12. Графические приложения с числовыми выражениями Чтобы отработать действия с переменными и вычислениями с операторами и числовыми выражениями, мы сделаем кое-что ин­ тересное: разработаем веб-приложение с графическим интерфей­ сом пользователя (GUI), с вычислениями с дробными числами. Веб-приложение ***: конвертер из BGN в EUR Создайте веб-приложение, которое вычисляет значение в евро (EUR) денежной суммы, указанной в левах (BGN). При изменении значения в левах необходимо автоматически пересчитать эквивалент в евро. Используйте обменный курс BGN/ EUR: 1,95583. По аналогии с первой главой мы будем использовать JavaScript, HTML и CSS для нашего приложения. 1. Первым шагом будет создание папки, в которой мы будем хра­ нить все файлы, необходимые для нашего приложения. 2. Затем в папке нужно создать НТМL-файл: html> <html xmlns="http://www.w3.org/1999/xht ml"> <head> <met a charset="utf-8"> <title>BGN to EUR Converter< / title> </ head> <!DОСТУРЕ index. html
Графические приложения с числовыми выражениями 83 <body> <form class="content-form"> <h2 class="title">BGN t o EUR Converter</h2> <section class="items"> <label for="bgn" class=" currency"> <span class=''item-currency''>BGN: </span> <input class="currency-value" type="number" id="bgп" value="0" /> </label> <label for=''euro'' class=''currency''> <span class="item-currency">EUR: </span> <input class="currency-value" type="text" id="euro" readonly /> </label> <input class="primary-Ьtn" type="button" value="Convert!" /> </section> </form> </body> </ht ml> Обратите внимание, что каждый НТМL-элемент должен иметь определенное содержание. Например, в теге <body> всегда должен находиться основной код, который вы пишете, а в теге <title> - заголовок страницы. 3. Теперь у нас есть структура страницы, нам нужно добавить JavaScript-фaйл с самой логикой. Мы создадим новый файл и назо­ вем его converter . j s: function eurConverter() { let bgn = document.getElementByid("bgn") . value; l et eur = (bgn / 1.95583).toFixed(2); document.getElementByid(''euro'').value = eur; } 4. Когда у нас есть логика приложения, нам нужно найти способ указать, где ее использовать. Для этого нам нужно внести два изме­ нения в существующий файл index. html. Во-первых, мы добавим следующую строку сразу под тегом ti tle, который является связующим index. html и converter . j s: звеном меЖдУ файлами <script src="converter.js" t ype="text/javascript"></script > А во-вторых, находим и заменяем поле i nput на тип button с по­ мощью следующего кода. Таким образом мы установим функцию
Глава 84 eurconverter( ), которая [Convert!]: 2.1 . Простые вычисления будет вызываться при нажатии на кнопку <input class=''primary-btn'' type=''button'' oncli ck="eurConverter()" value="Convert ! " /> Если мы запустим файл index.html из этой папки, у нас должно получиться рабочее приложение, которое конвертирует BGN в [ С С) EUR: (D index.htмl BG:\' to EUR Con,1erter EUR: 2.56 1 BG:\': 5 Convert! Давайте сделаем его красивее. Создайте новый файл с р асширением 5. css . css используется для стилизации элементов в файл index . html и именем HTML. и добавьте следующую строку в тег index. Откройте <head >: <li nk rel="st ylesheet" href="index.css" type= "text/c ss" /> В файле index. css мы разместим следующий код (мы определя­ ем стили для отдельных НТМL-элементов): body { font -family: 'Lato', sans-seri f; color: #FFFFFF; } .content-form { width: 50%; margin: 5% auto; background: #234465; padding : Spx 10рх 10рх ; border-radius: 15рх; box - shadow: Spx Spx 10рх #808080, Spx Spx set; } . currency-value { border: попе; padding: Spx; border-radius: Spx; } 10рх #6793cl in-
Графические приложения с числовыми выражениями 85 . title { text-align: center; .item-currency { font-weight: 700; } . currency { margin: auto; padding-bottom: 15рх; } .items { display: flex; flex-direction: column; justify-content: flex-start; } .primary-btn { margin: auto; border: none; padding: 10рх 30рх; border-radius: 10рх; background-color: #ffa000; color: #FFFFFF; font-weight: 700; } 6. Запустите файл index . html, и вы увидите что-то вроде этого (если мы ничего не напутали): о С\ ЗGN to EUR Convener С О L х (D index.html * о х
Глава 86 2.1 . Простые вычисления Веб-приложение***: поймай мышь! Когда вы наводите курсор мыши на изображение, оно перемеща­ ется в случайную позицию. Это создает ощущение, будто изображе­ ние ускользает от курсора, и его трудно поймать. Когда изображе­ ние «схвачено», на экране появляется приветствие. Вот как может выглядеть готовое приложение : о D Catch the mouse! I С Ф х Х index.html х Эта страница отправляет подсказку Congratu'ations, You \.Vin! _ Не отображать дополнительные диалоги с этой страницы. ок Подсказка: напишите обработчик для события mouseover и пере- местите изображение в случайную позицию. • • • Используйте генератор случайных чисел Math. random( ). Позиция изображения задается свойством style. position. Чтобы « поймать мышь», напишите функцию для события onclick. Вот несколько более подробных рекомендаций: 1. Создайте новую папку catch-the-mouse, в которой мы будем хранить файлы веб-приложения. 2. В этой папке создайте два файла: index. html и арр. тура папки должна выглядеть следующим образом: j s. Струк­
Графические приложения с числовыми выражениями 87 • 1 catcn-the-mous" Home Share « > О > ~ Documents Desktop о х о View JS • catcn -th.,-mous" " V ~ Searcn catcn -tne-mous" ,Р Name Date modifi~ Туре 91 app.js 2/4.2018 5:19 РМ 2/4 12018 5:19 РМ JavгScnpt > ... Downloads > JI Music index.ntml Sourc Cnrome HTML ,; Pictures l!JI Videos _ local Disk (С:) _ local Disk (D:) 'У < 2 items 3. Вы можете помочь себе, используя приведенный ниже код. Файл i ndex. html должен выглядеть следующим образом: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/ xhtml"> <head> <meta charset="utf-8" / > <title>Catch the mouse!</title> <script src="app.js" type="text/javascript"></script> </head> <body> <img id="image" style="position:absolute;top:30%;left:30%; width:10%; height:auto; "src="images/mouse.jpg" /> </body> </html> Файл app . js должен выглядеть следующим образом: function chaseMouse() { let img = document.getElementByid("image"); img.style . position = "absolute"; img.style . left = (Math.random() * 300) + ''рх''; img.style . top = (Math.random() * 300) + ''рх''; } function catchMouse() { alert( ''Congratulations, You Win!'') }
Глава 88 4. Найдите mouse . jpg . 2.1. Простые вычисления изображение в Интернете и добавьте его , назвав его Протестируйте приложение, открыв папку проекта в проводни­ ке и запустив файл index. html: ..- 1 catch·the-mouse Hom, Shor, « Desktop @ Documents " Downlo•ds J! Music - Pictures х Vi,w JS > c•tch-the-mouse ,., о 8 V v ~ S.arch catch-the-mouse Name Date modified ~ •pp.js р Туре 2, .ЩО18 S:26 РМ JavoScnpt Sour1 index.html 2/4 12018 5:29 РМ ChromeHTML В mouse.jpg 2/4/2018 5:28 РМ JPG File liJ Videos ';., Loc•I Disk (С:) _ 3 items Local Disk (О:) .., < 1 item selюed 342 bytes 5. Завершите работу приложения. Если у вас возникли трудности, обратитесь на форум https://softuni.bg/forum. SoftUni:
Глава 2.2. Простые вычисления - экзаменационные задачи В предыдущей главе мы познакомились с тем, как передать чис­ ло в функцию и как вывести результат в консоль. Мы рассмотрели основные арифметические опер ации и и кратко упомянули о ти­ пах данных. В этой главе мы отработаем и закрепим полученные знания, рассмотрев несколько более сложных задач, задаваемых на экза­ менах. Обзор: чтение, вывод чисел и вычисления Прежде чем мы перейдем к решению задач, давайте вспомним наиболее важный материал, изученный в предыдущей главе. Нач­ нем с создания функции, которая считывает число. Чтение целого числа Нам нужна функция, которой передается один параметр (аргу­ мент) argl. (например В ней мы создадим переменную для хранения числа num), а также метод parseint( ... ), который преобразует текст в число: function readNumber(argl) { let num = parseint(argl); } Чтение дробного числа Аналогично чтению целого числа, но на этот раз мы будем ис­ пользовать метод let num = parseFloat( ...): parseFloat(argl );
Глава 90 2.2. Простые вычисления - Вывод текста по шаблону Placeholder экзаменационные задачи (placeholder) представляет собой выражение, которое при выво­ де будет заменено определенным значением. Чтобы шаблон ра­ ботал, необходимо использовать обратные (косые) кавычки (апо­ строфы) · .. :.Метод console . log( ... ) подцерживает вывод текста по шаблону, при этом аргументы для печати задаются в виде${ ... }: let firstName = "Ivan"; let lastName = "Ivanov"; let age = 19; let town = "Sofia" ; console.log('You are ${firstName} ${lastName},a ${age}-years old person from ${town}. '); // You are Ivan Ivanov, а 19- years old person from Sofia. Арифметические операторы Вспомним основные арифметические операторы для вычис­ лений. Оператор + let result 3 + 5; // результат 8 3 - 5; // результат -2 3 * 5; // результат 15 = Onepamop- let result = Оператор * let result = Оператор / let result2 = 5 / 2; // результат 2. 5 (дробное деление) Конкатенация При использовании оператора + между переменными типа string (или между текстом и числом) выполняется так называемая конкатенация (объединение строк): let firstName = "Ivan"; let lastName = "Ivanov";
Экзаменационные задачи 91 let age = 19; let str = firstName +" "+ lastName +" is" + age + "years old"; // Ivan Ivanov is 19 years old Экзаменационные задачи Теперь, когда мы вспомнили, как считывать и выводить числа в консоль и как производить с ними вычисления, можно перехо­ дить к решению задач. Мы решим несколько задач из вступитель­ ного экзамена для поступления в SoftUni. Задача: аудитория w Помещение разделено на две части - Аудитория имеет прямоугольную форму размером тров, без колонн внутри. l на ме­ ле­ вую и правую, с коридором примерно посередине. В левой и пра­ вой частях стоят ряды парт. В задней части зала находится большой дверной проем. В передней части зала находится трибуна с подиу­ мом для лектора. Одно рабочее место занимает 70 на 40 70 на 120 см (стол см + стул 70 на 80 см и место для прохода). Коридор имеет ширину не менее 100 см. Было подсчитано, что из-за входной двери (проем которой составляет 160 см) теряется ровно 1 рабочее место, а из-за трибуны (размер которой составляет 160 на 120 см) - ровно два рабочих места. Напишите программу, которая считывает размеры аудитории и рассчитьmает количество рабочих мест в ней для описанной пла­ нировки (см. рисунок на следующей странице). Входные данные Программа считьmает два числа (аргумента), по одному в строке: 1 (длина в метрах) и w (ширина в метрах). Ограничения: з s. w s. l s. 100. Въmод данных Выведите в консоль целое число: количество мест в аудитории.
92 Глава 2.2. Простые вычисления - экзаменационные задачи Примеры ввода и вывода Ввод Вывод 15 8 .9 129 Чертеж L [I] Коридор: примерно 1 м -.--, ....... ~ 8.4 5 .2 39 Кор и дор: 1 м Пояснения к примерам В первом примере длина аудитории составляет 1500 см. В нем 12 рядов (12 * 120 см= 1440 + 60 см остатка). Ши­ рина зала составляет 890 см. Из них 100 см приходится на коридор посередине . На оставшихся 790 см можно разместить 11 парт в ка­ ждом ряду (11 * 70 см= 770 см+ 20 см остаток). Количество мест= 12 * 11 - 3 = 132 - 3 = 129 (у нас 12 рядов по 11 мест в каждом= 132 ми­ нус 3 места для трибуны и дверного проема). Во втором примере длина аудитории составляет 840 см. В ней можно разместить 7 рядов (7 * 120 см = 840, без остатка). Ширина аудитории составляет 520 см. Из них 100 см приходится на коридор можно разместить
Задача:аудитория 93 420 см можно разместить по 6 парт в ка­ ждом ряду (6 * 70 см =420 см, без остатка). Количество мест =7 * 6 - З =42 - 3 =39 (у нас 7 рядов по 6 мест =42 минус 3 места для трибуны посередине. На оставшихся и дверного проема). Рекомендации и подсказки Сначала попробуйте решить задачу самостоятельно. Если у вас не получается, обратитесь к рекомендациям и подсказкам. Идея решения Как и в любой другой задаче по программированию, важно по­ лучить представление о решении до того, как вы начнете писать код. Давайте внимательно посмотрим на постановку задачи. От нас требуется написать программу, которая вычислит количество ра­ бочих мест в аудитории, причем это количество зависит от длины и ширины помещения. Обратите внимание, что на вход нам будут поданы метры, а информация о том, сколько места занимают ра­ бочие места и коридор, дана в сантиметрах. Для выполнения вы­ числений нам нужно будет использовать одни и те же единицы измерения, и неважно, будем ли мы переводить ширину и длину в сантиметры или остальные данные в метры. В представленном решении выбран первый вариант. Далее нам нужно рассчитать, сколько парт рядом и сколько ря­ дов парт поместится. Количество парт рядом мы можем рассчитать, вычтя из ширины пространство, необходимое для коридора (100 см), и разделив остаток на 70 см (длина рабочего места). Количестов рядов мы наЙДем, разделив длину на 120 см. Обе операции могут дать ве­ щественное число с целой и дробной частью, но нам нужно хранить в переменной только целую часть . Наконец, умножим количество ря­ дов на количество столбцов и вычтем из него З (места, которые теря­ ются из-за входной двери и трибуны). Это даст нам искомое значение. Выбор типов данных Из примера вводимых данных видно, что на вход нам может быть передано вещественное число с целой и дробной частью, но по­ скольку в JavaScript есть только один примитивный тип для чисел (Number), это не будет проблемой. Выбор типа для последующих пе-
94 Глава 2.2. Простые вычисления - экзаменационные задачи ременных зависит от выбранного нами метода решения. Как и лю­ бая другая задача по программированию, эта таюке имеет более од­ ного метода решения. Решение Пришло время перейти к решению. Мысленно мы можем разделить его на три части : • • • Считывание вводимых данных. Выполнение вычислений. Вывод результатов в консоль. Первое, что нам нужно сделать, это считать вводимые дан­ ные. Мы создаем функцию, которой передаем два аргумента, сохраняем их parseFloat( ... ) значения в двух переменных, используя метод для преобразования заданного строкового (тексто­ вого) значения в дробное число: function numberOfSeats ([argl,arg2] ) { let length = parseFloat(argl); let width = parseFloat(arg2); } Приступим к вычислениям. Особенность заключается в том, что после выполнения деления нам достаточно сохранить целую часть от результата в переменной . Ищите в Интернете ! Когда у нас есть идея, как решить проблему, но мы не знаем, как написать ее на языке JavaScript, или когда мы сталкиваемся с про блемой, которая, как мы предполагаем, есть у многих других людей, самый простой способ справиться с ней поискать информацию в Интернете. В данном случае мы можем попробовать следующий поиск: «JavaScript как получить целую часть двойного числа». Мы обна­ ружили, что одна из возможностей заключается в использов ании метода Math. trunc ( ... ) . Приведенный ниже и должен быть доработан читателем: код намеренно размыт
Задача: овощной рынок С помощью 95 console . log( ...) мы выводим результат в консоль: Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/928#0. Задача: овощной рынок Садовод-огородник продает урожай со своего огорода на овощ­ ном рынке. Овощи он продает по цене N левов за килограмм, а фрук­ ты - по цене м левов за килограмм. Напишите программу, которая вычисляет доход от урожая в евро (при условии, что один евро ра­ вен 1,94 лева). Входнъ1е даннъ1е Функции передается четыре параметра: • Цена за килограмм овощей - • • Цена за килограмм фруктов • Общее количество килограммов фруктов - - число с плавающей точкой. число с плавающей точкой. Общее количество килограммов овощей - Ограничения: все числа будут варьироваться от целое число. целое число. 0.00 до 1000.00 Вывод даннъ~х Выведите в консоль одно дробное число: выручку от продажи всех фруктов и овощей в евро. Примеры ввода и вывода Ввод 0.194 19.4 10 10 Вывод Ввод 101 1 1.5 2.5 10 10 Вывод 20.6185567010309 Пояснение к первому примеру: • Стоимость овощей. 0,194 лв * 10 кг = 1,94 лв.
Глава 96 • • 2.2. Простые вычисления - экзаменационные задачи 19,4 лв. * 10 кг= 194 лв. Итого: 195,94 лв. = €101. Стоимость фруктов. Рекомендации и подсказки Сначала мы приведем некоторые идеи, а затем конкретные ука­ зания по решению задачи и существенную часть кода. Идея решения Сначала рассмотрим наше условие. В данном случае нас просят вычислить, сколько составляет общий доход от продажи урожая. Он равен сумме прибыли от продажи фруктов и овощей, и мы мо­ жем вычислить его, умножив цену за килограмм на их количество. Входные данные указаны в левах, а выводимые - в евро. По усло­ вию 1 евро равен 1,94 лева, поэтому, чтобы получить требуемое вы­ ходное значение, нужно разделить сумму на 1,94. Выбор типов данных После того как мы прояснили нашу идею решения задачи, мож­ но переходить к выбору подходящих типов данных. Рассмотрим входные данные: даны два целых числа для общего количества ки­ лограммов овощей и фруктов соответственно, переменные, кото­ рые мы объявим для хранения их значений, можно преобразовать в число с помощью parseint ( ... ).Для цен на фрукты и овощи указа­ но, что будут переданы два дРобных числа, то есть переменные бу­ дут преобразованы методом parseFloat( ... ). Решение Пришло время перейти к решению . Мысленно мы можем разделить его на три части: • • • Считывание входных данных. Выполнение вычислений. Вывод результатов в консоль. Чтобы считать вводимые данные, мы объявляем пер еменные, при этом стараемся называть их так, чтобы бьmо понятно, какие значения содержат переменные. С помощью методов и parseFloat( ... ) parseint ( ...) мы преобразуем указанное текстовое значение в целое и дробное число соответственно.
Задача: укладка плитки 97 Далее проводим необходимые расчеты: let vegTotal = vegPrice * vegPerkg; let fruitTotal = fruitsPri ce * fruitsPerkg; В условии задачи не указано специальное форматирование вы­ вода, поэтому нам нужно просто вычислить запрашиваемое значе­ ние и вывести его в консоль. Как в математике, так и в програм­ мировании деление имеет приоритет перед сложением. Однако в данной задаче мы должны сначала вычислить сумму двух полу­ ченных значений, а затем разделить на 1,94. Чтобы отдать предпо­ чтение сложению , мы можем использовать круглые скобки. С по­ мощью console . log( ... ) выводим результат в консоль: console . log((fruitTotal + vegTotal) / 1 . 94); Проверка в системе Ju.d ge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/928#1. Задача: укладка плитки На площадке перед многоквартирным домом необходимо уло­ жить плитку. Площадка имеет форму квадрата со стороной тров. Ширина плитки составляет W метров, а длина L N ме­ метров. На площадке есть скамейка шириной М метров и длиной О ме­ тров. Под нее не нужно класть плитку. Каждая плитка укладывает­ ся за 0,2 минуты. Напишите программу, которая, считав размеры детской площад­ ки, плитки и скамейки, вычисляет, сколько плиток нужно для по­ крытия площадки, и рассчитывает время, необходимое для уклад­ ки всей плитки. 20 м имеет площадь 400 кв. м. Скамейка шириной 1 м и длиной 2 м занимает площадь 2 кв. м. Плитка шириной 5 м и длиной 4 м имеет площадь 20 кв. м. Пример : детская площадка шириной
Глава 98 2.2. Простые вычисления Площадь, которую нужно покрыть, равна ется 398 / 20 = 19,90 0,2 = 3,98 минуты. - экзаменационные задачи 400 - 2 = 398 кв. м. Требу­ плитки. Необходимое время составляет 19,90 * Входнь1е даннъ1е Функции передается пять аргументов: • • • • • N -длина стороны площадки в интервале [1 .. . 100]. W - ширинаплиткивинтервале [0 . 1 ... 10 . 00]. L -длина одной плитки в интервале [0, 1 . . . 10, 00]. М-ширина скамьи в интервале [0 ... 10]. О - длина скамьи в интервале [0 .. . 10]. Вывод даннъIХ Выведите в консоль два числа: • • количество плиток, необходимых для ремонта время укладки Каждое число должно быть выведено с новой строки и округле­ но до второго знака после десятичной точ:ки. При.меры ввода и вывода Ввод Вывод 20 5 4 1 2 19.9 3.98 Ввод 40 0 .8 0 .6 3 5 Вывод 3302.08 660.42 Пояснение к первому примеру: • • • • • • = 20 * 20 = 400. Площадь скамейки = 1 * 2 = 2. Площадь покрытия = 400 - 2 = 398. Площадь плитки = 5 * 4 = 20. Требуется плитки= 398 / 20 = 19,9. Требуется времени = 19,9 * 0,2 = 3,98. Общая площадь
Задача: укладка плитки 99 Рекоменда ции и подсказки Давайте сделаем рисунок, чтобы прояснить условие задачи. Он может выглядеть следующим образом: 1 1 1 1 1 1 1 1 1 1 1 1 1W L 1 1 1 1 N 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - о ~ м , скамейка N 1 1 1 ПЛОЩА!]КА Идея решения Необходимо рассчитать количество плиток, которые нужно уло­ жить, а также время, за которое это будет сделано. Чтобы рассчи­ тать количество плиток, необходимо вычислить площадь, которую нужно покрыть, и разделить ее на площадь одной плитки. По ус­ ловию площадка квадратная, поэтому общую площадь мы найдем, умножив длину одной из ее сторон на длину другой: N * N. Затем вычисляем площадь, занимаемую скамейкой, также перемножая две ее стороны м * о. Вычтя площадь скамейки из площади всей площадки, мы получим площадь, подлежащую ремонту. Площадь одной плитки мы вычисляем, умножая одну ее сто­ рону на другую w * L. Как уже отмечалось, теперь нам нужно разд елить площадь, которую необходимо покрыть, на площ адь одной плитки. Это даст нам нео бходимое количество плиток. Ум­ ножаем его на 0,2 (время, за которое , по условию, кладется одна плитка). Таким образом, у нас уже есть необходимые выходные значения.
Глава 100 2.2. Простые вычисления - экзаменационные задачи Выбор типов данных Длина стороны площадки, ширина и длина скамейки будут зада­ ны в виде целых чисел, поэтому для хранения их значений мы мо­ жем объявить переменные, преобразованные с помощью метода parseint( ...) . Для ширины и длины плитки нам будут даны веще­ ственные числа (с целой и дробной частью), поэтому для них мы бу­ дем использовать метод parseFloat( ... ). Решение Как и в предыдущих задачах, мы можем мысленно разделить решение на три части: • • • Считывание вводимых данных. Выполнение вычислений. Вывод результатов в консоль. Первое, что нужно сделать, это просмотреть исходные данные для решения задачи. Важно внимательно отнестись к порядку их считывания. Мы создаем необходимые переменные для хране­ ния вводимых данных и используем методы parseint( ... ) и parse- Float( ... ) для преобразования заданного строкового значения в це­ лое или дробное число соответственно: / / Длина площадки let n = parseint(argl); / / Ширина плитки let w = parseFloat(arg2); / / Длина плитки let 1 = parseFloat(argЗ); / / Ширина скамейки let m = parseint(arg4); / / Длина скамейки let о= parseint(argS); Инициализировав переменные и сохранив в них соответствую­ щие значения, мы приступаем к вычислениям. Приведенный ниже код намеренно размыт, чтобы читатель мог самостоятельно напи­ сать его:
Задача: конверсия валют 101 Вычислим значения, которые нам нужно вывести в консоль. Не­ обходимое количество плиток получается путем деления площади, которую нужно покрыть, на площадь одной плитки. В условии задачи указано округление результата до второго зна­ ка после десятичной точки. Поэтому мы не можем просто вывести значения с помощью console. log( ... ). Мы воспользуемся методом Math. round ( ... ) , который округлит полученное число до ближайше­ го целого. Чтобы не потерять два знака после десятичной точки, мы применим метод к числу, умноженному на лим результат на 100, а затем разде­ 100: let tilesCount = areaWithTiles / tileArea; let time = tilesCount * 0.2; console.log(Math.round(tilesCount * 100) / 100); console.log(Math.round(time * 100) / 100); Проверка в системе Ju.dge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/928#2. Задача: конверсия валют Некоторое время назад Петр купил биткоины. Теперь он отпра­ вится в путешествие по Европе, и ему понадобятся евро. Кроме бит­ коинов у него есть еще китайские юани. Петр хочет обменять свои деньги на евро для поездки. Напишите программу, которая вычис­ лит, сколько евро он сможет купить по следующим курсам: • • • • 1 биткоин = 1168 левов. 1 китайский юань= 0,15 доллара. 1 доллар = 1,76 лева. 1 евро = 1,95 лева. Комиссия обменного пункта составляет от О до 5 процентов от ко­ нечной суммы в евро. Входнъ1е даннъ1е В функцию передается три аргумента: • Количество биткоинов-целое число в диапазоне [0 ... 20].
Глава 102 • 2.2. Простые вычисления - экзаменационные задачи Количество китайских юаней-дРобное число в диапазоне [0.00 ... 50 000.00]. • Комиссия - дРОбное число в диапазоне [0 . 00 . . . 5. 00]. Вывод даннъ~х На консоль необходимо вывести одно число - результат обмена валюты. Результат следует округлить до второй цифры после деся­ тичной точки. Примеры ввода и вывода Ввод Вывод Ввод 569 . 67 20 5678 2.4 1 5 5 Вывод Ввод вывод 7 12442 . 24 50200.12 10659.47 3 Пояснение: • • 1 биткоин = 1168 левов 5 юаней= 0,75 доллара • • 0,75 доллара= 1,32 лева 1168 + 1,32 = 1169,32 лева= 599,651282051282 евро • • Комиссия: 5% от 599.651282051282 = 29.9825641025641 Результат: 599.651282051282 - 29.9825641025641 = 569.668717948718 евро Рекомендации и подсказки Прежде чем приступить к написанию кода, давайте еще раз по­ думаем, как можно решить задачу. Идея решения Мы видим, что нам будет дано количество биткоинов и количе­ ство китайских юаней. Значение результата указано в евро. В усло­ вии таюке указаны курсы валют, с которыми нам нужно работать. Мы заметили, что можем конвертировать в евро только сумму в ле­ вах, поэтому сначала мы должны вычислить общую сумму, которой владеет Пешо, в левах, а затем рассчитать нужную стоимость в евро. Поскольку нам предоставлена информация о курсе биткоина по отношению к леву, мы можем вьmолнить эту конвертацию на-
Задача: конверсия валют 103 прямую . С дРуrой стороны, чтобы получить стоимость китайского юаня в левах, нам сначала нужно перевести его в доллары, а затем конвертировать доллары в левы. Наконец, мы сложим два получив­ шихся значения и вычислим, скольким евро они соответствуют. Последний шаг - вычислить, сколько составит комиссия, и вы­ честь полученную сумму из общей. В кач естве комиссии мы полу­ чим реальное число, которое будет представлять собой определен­ ный процент от общей суммы. Разделим полученное число на 100, чтобы вычислить процентное значение. Умножим его на сумму в евро и вычтем полученный результат из этой же суммы. Полу­ ченную сумму выведем в консоль. Выбор типов данных Биткоины представлены в виде целого числа, поэтому для их значения мы можем объявить переменную, преобразованную с по­ мощью метода parseint( ... ). В качестве количества юаней и комис­ сии мы получим дРОбное число, по этому используем для них метод parseFloat( ... ). Решение Теперь, когда мы имеем представление о решении задачи и вы­ брали типы данных, с которыми будем работать, пора приступать к написанию кода. Как и в предыдущих задачах, мы можем разде­ лить решение на три части: • • • Считывание вводимых данных. Выполнение вычислений. Вывод данных в консоль. Объявите переменные, которые мы будем использовать, опять же тщательно выбирая осмысленные имена, которые подскажут, какие данные они содержат. Инициализируем их значения: созда­ ем переменные, в которых будем хранить строковые аргументы, передаваемые функции, преобразуя их в целые или дРОбные зна­ чения: let bitcoins = parseint(argl); let yuans = parseFloat(arg2); let commission = parseFloat(argЗ) / 100;
Глава 104 2.2. Простые вычисления - экзаменационные задачи Выполняем необходимые вычисления: let bitcoinsToleva = bitcoins * 1168; let yuansToDollars = yuans * 0.15; let dollarsToleva = yuansToDollars * 1.76; Наконец, вычисляем значение комиссии и вычитаем его из суммы в евро. Обратим внимание на то, как это можно записать: euro -= commission * euro - это сокращенный вариант написа­ ния euro = euro - (commission * euro). В данном случае мы ис­ пользуем комбинированный оператор присваивания-=, который вычитает значение операнда справа из значения операнда слева. * имеет более высокий приоритет, чем -=, по­ этому сначала выполняется выражение commission * euro, а затем Оператор умножения его значение вычитается. Наконец, нам остается вьmести результат в консоль. Обратите вни­ мание, что требуется округление числового значения до второго зна­ ка после десятичной точки. В отличие от предьIДУЩей задачи, здесь, даже если число целое, оно всегда должно иметь два знака после за­ пятой (например, 5. 00). Для этого мы можем использовать метод to- Fixed ( ...).С его помощью мы можем преобразовать число в текст, со­ хранив определенное количество знаков после десятичной точки: euro -= commission * euro; console.log(euro.toFixed(2)); Отметим то, что справедливо для всех задач такого типа: запи­ санное таким образом решение задачи получается подРобным. По­ скольку условие в общем случае несложное, теоретически можно написать большое выражение, в котором мы вычисляем результат непосредственно после получения вводимых данных. Например, такое выражение будет выглядеть следующим образом: let euro = ((bitcoins * 1168) + (yuans * 0 . 15 * 1 .76)) / 1 . 95 - (commission * ((bitcoins * 1168) + (yuans * 0.15 * 1 . 76)) / 1.95 ); Этот код даст правильный результат, но его трудно читать. Нам будет нелегко разобраться, что он делает, содержит ли ошибки, а если содержит, то как их исправить . Лучше написать несколько
Задача: ежедневная прибыль 105 простых выражений вместо одного сложного и записать их резуль­ таты в переменные с соответствующими именами. Такой код будет понятным, его будет легче читать и корректировать. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/928#3. Задача: ежедневная прибыль Иван - программист в американской компании, работает из дома в среднем ларов в день. В N дней в месяц и зарабатывает в среднем М дол­ конце года Иван получает премию, равную 2,5 ме­ сячным зарплатам. С заработанной за год суммы у него удерживает­ ся 25 % налогов. Напишите программу, которая вычислит, сколько составляет чистый средний заработок Ивана в день в евро. Предпо­ ложим, что в rо-ду ровно 365 дней. В функцию будет подаваться курс доллара по отношению к леву. Входнъ1е данные В функцию передаются три аргумента: • • Рабочие дни в месяце - целое число в диапазоне Заработанные деньги в день - [5 ... 30]. целое число в диапазоне [10.00 . .. 2000.00]. • Курс доллара по отношению к леву вещественное число в интервале /1 доллар = Х левов/ - [0. 99 ... 1. 99]. Вьmодимъ1е даннь1е В консоль выведите одно число - среднюю прибыль в день в ле­ вах. Отформатируйте результат до второй цифры после десятичной точки. Примеры ввода и вывода Ввод 21 75.00 1.59 ВЫвод Ввод 74 . 61 15 105 1.71 1 вывод Ввод вывод 80.24 22 199.99 1.50 196.63 '
Глава 106 2.2. Простые вычисления - экзаменационные задачи Пояснение: • Заработная плата за • • • Годовой доход= • Средняя прибыль в день= Налог = 25 % от 1 месяц= 21 * 75 = 1575 долларов. 1575 * 12 + 1575 * 2,5 = 22837,5 доллара. 22837,5 = 5709,375. Чистый годовой доход= 17128,125 доллара = 27233,71875 лева. 27233,71875 / 365 = 74,61 лева. Рекомендации и подсказки Сначала проанализируем задачу и выясним, как ее решить. За­ тем выберем типы данных и, наконец, напишем код решения. Идея решения Сначала вычислим, сколько составляет месячная зарплата Ива­ на. Для этого умножим количество рабочих дней в месяце на ко­ личество денег, которые он зарабатывает в день. Умножим по­ лученный результат сначала на составляет его зарплата за 12, 12 месяцев, чтобы вычислить, сколько а затем на 2,5, чтобы вычис­ лить бонус. Сложив два получившихся значения, мы вычислим его общий годовой доход. Из него нужно вычесть сделать, умножив общий доход на 0,25 25 %. Это можно и вычтя полученнь1й ре­ зультат. По заданному курсу мы переводим доллары в евро, затем делим результат на количество дней в году, которое, как мы пред­ полагаем, равно 365. Выбор типов данных Рабочие дни в месяце заданы в виде целого числа, поэтому для их значения мы можем объявить переменную, в которой преобразуем в число с помощью метода parseint( ... ). Для заработаннь~х денег, как и для курса доллара по отношению к леву, мы получим веще­ ственное число, поэтому для них используем ра rse Float ( ... ) . Решение И снова, когда мы имеем представление о том, как решить за­ дачу, и продумали типы даннь~х, с которыми будем работать, при­ ступаем к написанию программы. Как и в предыдущих задачах, мы можем разделить решение на три части :
Задача: ежедневная прибыль • • • 107 Считывание вводимых данных. Вьmолнение вычислений. Вывод результатов в консоль. Объявим переменные, которые мы будем использовать, опять же стараясь выбрать подходящие имена. Затем создадим перемен­ ные, в которых будут храниться переданные функции параметры (аргументы), преобразуя строку в целое или дробное число с помо­ щью parseint( ... ) / parseFloat( ... ) : Далее выполняем расчеты: let let let let let monthSalary = workDays * moneyPerDay; yearSalary = (monthSalary * 12) + (monthSalary taxes = yearSalary * 0.25; netSalary = yearSalary - taxes; salaryinleva = netSalary * currencyRate; * 2.5 ); Мы также можем написать выражение, которое используем для расчета общего годового дохода, без скобок. Поскольку умно­ жение является более приоритетной операцией, чем сложение, оно будет выполнено первым. Однако при использовании больше­ го количества операторов рекомендуется писать круглые скобки, поскольку так код легче читать и меньше вероятность допустить ошибку. Наконец, нам осталось вывести результат на экран. Обратите внимание, что требуется округлить его до второго знака после деся­ тичной точки. Мы можем использовать метод. toFixed( ... ) также, как и в предыдущей задаче: console.log((salaryinLeva / 365).toFixed(2)); Проверка в системе Judge Проверьте свое решение : Index/928#4. https://judge.softuni.bg/Contests/Practice/
Глава 3.1. Простые проверки В этой главе мы рассмотрим условные операторы в JavaScript, которые можно использовать для того, чтобы заставить нашу про­ грамму выполнять различные действия в зависимости от усло­ вия. Мы объясним синтаксис условных операторов для проверок (if и if-else) на подходящих примерах и посмотрим, в каком ди­ апазоне находится переменная (ее область видимости). Наконец, мы рассмотрим методы отладки для инкрементного отслеживания пути, пройденного нашей программой во время ее выполнения. Операторы сравнения В программировании мы можем сравнивать значения с помощью сле.цующих операторов: • • • • • • Оператор < (меньше) Оператор > (больше) Оператор <= (меньше или равно) Оператор >= (больше или равно) Оператор=== (равно) Оператор ! ==(неравно) При сравнении результатом является булево значение, или false, true в зависимости от того, является ли результат сравнения истинным или ложным. Важно отметить, что в операторов сравнения == JavaScript также и различия используется другой тип ! =. Их применение без глубоко­ го понимания приводит к проблемам и неожиданным результатам, поэтому на данном этапе обучения мы их рассматривать не будем. Более подробную информацию о различиях между двумя типа­ https:// developer.rnozilla.org/en-US/docs/Web/JavaScript/Reference/Operators. ми операторов сравнения и различия можно получить здесь:
Операторы сравнения 109 Примеры сравнения чисел let а= 5; let Ь = 10; console. l og(a console.log(a console.log(a console. l og(a console. l og(a console.log(a < Ь) ; // True > 0); // True > 100) ; // False < а); // False <= 5); // True === 2); // False Примеры ср авнения пер еменных типа let а= "book"; let Ь = "page"; console.log(a --- Ь); console.log(a !=== Ь); console. l og(a --- ''book''); console.log(a === '' ВооК ); console.log(b !== ''paGe'' ) ; string (строка) //False //True //True //False //True Важно и то, являются JП:1 буквы в нашем тексте заглавными или стр очными. ЕСJП:1 ср авниваемые значения не полностью иден­ тичны, то полученный результат в сегда будет False. Операторы сравнения В JavaScript для сравнения данных можно использовать следую ­ щие опер аторы: Оператор Обозначение Проверка на равенство --- Проверка на разл и ч и е .-- Больше > Больше ил и равно Ме ньше Меньше ил и на которых работает оператор ч и сла, строки , числа, даты , даты 1-- >= < равно Типы данных, <= друг и е с равниваемые типы
Глава 11 0 3.1 . Простые проверки Простые проверки В программировании мы часто проверяем заданные условия и выполняем различные действия в зависимости от результата проверки. Для этого используется проверка i f, которая имеет сле­ дующий вид: if ( Boolean expression ) { / /тело ус л овного оператора } Пример : от1m:чная оценка При вызове функции мы вводим в качестве аргумента оценку и пр оверяем, является ли она отличной ( ~5 . 50). function isExcellent( n) { let grade = parseFloat(n); if (grade >= 5.50) { console . log( '' Excellent!'' ) ; } } Протестируйте код примера локально . Попробуйте ввести раз­ личные оценки, например 4.75, 5.49, 5.50 и 6.00. Для оценок мень­ 5.50 программа ничего не выведет, а для оценок 5.50 или боль­ ше выведет "Excellent!" (« Отлично ! ») . Вызовите функцию, набрав ее ше имя, а затем введите значение выборки в круглых скобках: isExcellent(S.60); // Excellent ! Проверка в системе Judge Протестируйте пример программы: https://judge.softuni.bg/ Contests/Practice/Index/929#0. Проверки с помощью оператора Оператор if может также содержать if-else else для вьmолнения опре­ деленного действия, если булево выражение, указанное в начале if ( Boolean expression), возвращает отрицательный результат
Фигурные скобки (false). {} после if / else 111 В таком виде условная конструкция называется if-else и ведет себя следующим образом: если результат условия положи­ тельный (true) - мы выполняем одни действия, а если отрица­ тельный (false)-дPyrиe. Формат утверждения в JavaScript выгля­ дит следующим образом: if (boolean condition) { // тело условного оператора; } else { // тело оператора else; } Пример: отличная оценка или нет Как и в примере выше, мы вводим оценку и проверяем, является ли она отличной, но пишем результат в обоих случаях: function excellentOrNot(n) { let grade = parseFloat (n); if (grade >= 5.50) { console.log(''Excellent!''); } else { console.log("Not excellent . "); } } Проверка в системе Ju.dge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#1. Фигурные скобки { } после if / else Когда в теле оператор а if содержится только одно утверждение, фигурные скобки, обозначающие тело условного оператора, можно опустить. Когда мы хотим въmолнить блок кода (группу команд), фигурные скобки обязательны. Если их опустить, будет выполнена только первая строка после оператора i f. Хорошая практика - всегда ставить фигурные скобки, потому что это делает ваш код более читабельным и упорядоченным.
Глава 11 2 3.1 . Простые проверки Вот пример, в котором отсутствие фигурных скобок приводит к путанице: let color "red"; = if (color === "red") console.log(''tomato''); else if (color === "yellow") console.log(''banana''); console . log(''bye''); Выполнение приведенного выше кода выведет в консоль следу­ ющий результат: PROBLEMS OUTPUT DEBUG CONSOLE ТERMINAL Debugging wi th inspector pro"v-.v.1. oecause r~ode. js node --inspe• -"~ 4 :i est . js Debu er listening on ws://127.0.0.1:40193/ Зеб083 tomato Ьуе С фигурными скобками код становится более понятным: let color = "red"; if (color === "red") { console . log ('' tomato''); } else if (color === "yellow" ) { console . log(''banana''); console.log(''bye''); } В консоль будет выведено следующее сообщение: PR1..,BLEMS vUiPLJ1 OEBUG CO/\JSOLE itRM NAL Debugging ,1i th inspector r,, vtv"v.l oecause flode. js ПО(~ ~ ~ ~ L ~ k 4q_ 5 t~ ~3 r listening on ws://127.0.0.1:48585/ 54729cd Пример : четное или нечетное Напишите функцию, которая проверяет, является ли целое чис­ ло четным (even) или нечетным (odd).
Фигурные скобки {} после if / else 113 Задача может быть решена с помощью оператора ратора i f-else и опе­ %, который возвращает остаток при делении двух чисел: function isEven(argl) { let num = parseint(argl); if (num % 2 === 0) { console.log("even"); } else { console.log(''odd''); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#2. Пример: большее число Напишите функцию, которая считывает два целых числа и вы­ водит большее из них. Наша первая задача простой оператор - i f-else считать два числа. Затем, используя в сочетании с оператор ом больше ( >), мы выполняем проверку. Часть кода намеренно скрыта, чтобы чи­ татели могли проверить, чему они научились за это время: function greaterNumber([arg1, arg2]) { let numl = parseint(argl ) ; let num2 = parseint (arg2) ; } Проверка в системе Judge Пр оверьте свое решение : Index/929#3. https://judge.softuni.bg/Contests/Practice/
Глава 11 4 3.1. Простые проверки Время жизни переменной У каждой переменной есть область, в которой она существует, называемая областью действия переменной (variahle scope). Так­ же этот феномен может называться временем жизни переменной. Эта область определяет, где переменная может быть использова­ на. В языке JavaScript существует два способа инициализации пе­ ременных: с помощью ключевого слова var или let. Важно знать разницу между ними, чтобы избежать нежелательных результатов при создании функций. Переменные, инициализированные с помощью ключевого слова var, обладают свойствами глобальных переменных. Они характери­ зуются тем, что к ним можно обратиться в любом месте, независимо от того, в какой части кода они были объявлены. При использова­ нии ключевого слова let переменная приобретает свойства локаль­ ной переменной. Это означает, что область ее действия начинается со строки, в которой мы ее определили, и заканчивается первой за­ крывающей фигурной скобкой } (в функции, в операторе i f и т. д.). Поэтому важно знать, что любая переменная, инициализированная с помощью ключевого слова let в теле оператора i f , будет недоступ­ на за его пределами, если мы не определим ее далее в коде. В примере ниже, в последних строках, мы попытаемся вызвать определенные переменные. Мы сможем вывести myMoney, потому что она объявлена в начале нашей функции, перед оператором i f, что делает ее доступной в любом месте функции. Также можно бу­ дет вывести тора salary, потому что, хотя она объявлена в блоке опера­ i f , она является глобальной переменной (поскольку она опре­ делена через var) и может быть использована в любом месте. Когда мы попытаемся вывести переменную bonus, инициализированную в операторе i f, мы получим ошибку, потому что область действия этой переменной заканчивается с первой закрывающей фигурной скобкой }, которая в данном случае является оператором i f: let myMoney = 500; let payDayDate = 07; let todayDate = 10; if (todayDate >= payDayDate) { var salary = 1000;
Серия проверок 115 let bonus = salary * 0. 15; myMoney = myMoney + salary + bonus; } console .log(myMoney); console.log(salary); console.log(bonus); Использование менных - / / 1650 / / 1000 / /Error ключевого слова var для создания пере­ это практика, которая раньше была основным спо­ собом определения, но теперь это нецелесообразно. Поэтому во всех примерах в этой книге мы будем использовать ключевое слов о let. Важно отметить, что существует и третий способ инициали­ зации переменных - с помощью ключевого слова const. Эти пе­ ременные имеют ту же область видимости, что и переменные, определенные с помощью чие - let, но имеют одно существенное отли­ они приобретают характеристики константной переменной. Это означает, что после первоначальной инициализации их значе­ ние не может быть изменено или переопределено. Серия проверок Иногда нам необходимо выполнить серию проверок, прежде чем решить, какие д ействия будет выполнять наша программа. В таких случаях мы можем последовательно применять опера­ тор i f-else i f ... -else. Для этого мы используем следующий формат: if (условие) { / / тело условного оператора; } el se if (condition2 ) { / / тело оператора else; } else if (conditionЗ ) { / / тело оператора else; } else { // } тело оператора else;
Глава 116 3.1 . Простые проверки Пример: числа от 1 до 9 на английском языке Выведите число в диапазоне от 1 до 9 на английском языке (чис­ ло передается в качестве параметра (аргумента) при вызове функ­ ции). Мы можем считать число, а затем вывести соответствующее английское слово, проведя ряд проверок: function numberlto9([argl]) { let num = parselnt (argl ) ; if (num === 1) { console . log( "one" ) ; } else if (num === 2) { console.log( "two" ) ; } else if (num === З) { console.log( ''three'' ) ; } / / TODO: добавить остальные проверки else { console.log( '' number too big '' ); } } Логика программы в приведенном выше примере последова­ тельно сравнивает входное число из функции с цифрами от 1 до 9, причем каждое последующее сравнение вьmолняется только в том случае, если предыдущее сравнение не было истинным. В итоге, если ни одно из условий нее условие if не вьmолняется, вьmолняется послед­ else. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#4. Упражнения: простые проверки Чтобы закрепить полученные знания об условных операторах и if i f-else, решим несколько практических задач. Задача: бонуснъ1е очки Дается целое число - количество очков. К нему добавляются бо­ нусные очки в соответствии с правилами, описанными ниже. На-
Упражнения : простые проверки 117 пишите функцию, которая вычисляет бонусные очки для этого чис­ ла и общее количество б онусных очков. • • Если число до Если число 100 включительно, то бонусные очки равны 5. больше 100, то бонусные очки составляют 20 % от числа. • Если число больше бонусные очки составляют 1000, 10 % отчисла. • Дополнительные бонусные очки (начисляются отдельно от предыдущих бонусных очков): -> + 1 очко. о За четное число о За число, оканчивающееся на 5 -> + 2 очка. Примеры ввода и вывода 1 Ввод Вывод 20 6 26 1 Ввод 175 вывод j Ввод 37 212 2703 Вывод 270. 3 2973.3 Ввод вывод 15875 1589.5 17464.5 Рекомендации и подсказки Мы можем рассчитать основные и дополнительные бонусные очки с помощью серии проверок if-else-if-else . Для основных бонусных очков у нас есть три случая (когда введенное число до от 100, 100 до 1000 и больше 1000), а для дополнительных бонусных оч­ ков - еще два случая (когда число четное и нечетное): function scoreCalculator([argl]) { let num = parseint (argl); let bonusScore = 0; if ( num > 1000) { bonusScore = num * 0.10; } else { / / TODO: добавьте сюда оставшуюся логику программы ..• } if (num % 10 === 5) { bonusScore += 2; } else {
118 Глава // T0D0: 3.1 . Простые проверки добавьте сюда оставшуюся логику программы ••• } console. log("Bonus score: "+ bonusScore) ; console.log("Total score : "+ (num + bonusScore)); В от как будет выглядеть результат при вызо ве функции со зна­ чением 175: PROBLEMS OUTPUT DEBUG CONSOLE TERMINAL Debugging ,-1ith inspector protocc.,,. u"._.зuse l~ode. js v node ect ~ -.1808 test.js Debugger listening on ,-1s://127.0.0.1:12808/233Ьбс78 вonus score: 37 Total score: 212 Обратите внимание, что для этого задания Judge настроен на иг­ норирование всего, что не является числом, поэтому мы можем вы­ водить не только числа, но и уточняющий текст. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#5. Задача: суммирование секунд Три спортсмена финишируют через некоторое количество се­ кунд (от 1 до 50). Напишите программу, которая по сле вв ода време­ ни каждого из спортсменов вычисляет их суммарное время в фор­ мате «минуты:секунды ». Секунды должны вьmодиться с ведущим нулем (2 -> «02», 7 -> «07», 35 -> «35»). Примеры ввода и вывода Ввод Вывод 35 45 2 : 04 Ввод Вывод 22 7 44 34 50 50 49 14 12 10 2 : 29 1: 03 0:36
Упражнения: простые проверки 119 Рекомендации и подсказки Сначала сложите три числа, чтобы получить общее количество секунд. Поскольку 1 минута == 60 секунд, нам нужно вычислить ко­ личество минут и количество секунд в диапазоне от О до • Если результат находится в диапазоне от О до дим О минут • • • + вычисленное количество 59, 59: мы выво­ секунд. Если результат находится в диапазоне от 60 до 119, выводим 1 минуту+ вычисленные секунды минус 60. Если результат находится в диапазоне от 120 до 179, выве­ дите 2 минуты + вычисленные секунды минус 120. Если количество секунд меньше 10, перед ними выводится ведУЩий ноль. function sumSeconds([argl, arg2, argЗ]) { let firstCompetitor = parseint(argl); // TODO: считать данные второго и третьего let seconds thirdCompetitor let minutes участника = firstCompetitor + secondCompetitor + = 0; if (seconds > 59) { minutes++; seconds = second - 60; } if (seconds > 59) { minutes++; seconds == second - 60 } if (seconds < 10) { console. log(minutes + ":0" + seconds); } else { console.log(minutes + + seconds) ; ff • 11 } } Проверка в системе Judge Проверьте свое решение: Index/929#6. https://judge.softuni.bg/Contests/Practice/
Глава 120 3.1 . Простые проверки Задача: конвертер единиц измерения Напишите функцию, которая преобразует расстояние между следующими восемью единицами измерения: km, ft, yd m, mm, cm, mi, in, ( м, мм, см, мили, дюймы, км, футы, ярды). Используйте соответствия из таблицы ниже: Единица ввода 1 Единица вывода meter (m) 1000 1 meter (m) 1 meter (m) millimeters (mm) 100 centimeters (cm) 1 0 . 000621371192 miles (mi) 1 meter (m) 39 . 3700787 1 meter (m) 0 . 001 kilometers (km) 1 meter (m) 1 meter (m) inches (in) 3 . 2808399 1. 0936133 feet (ft) yards (yd) Входные данные состоят из трех частей: • Первая: номер преобразования. • • Вторая: входная единица измерения. Третья: выходная единица (для результата). Примеры ввода и вывода Ввод Вывод 12 km ft 39370.0788 Ввод Вывод 150 mi in Ввод 450 yd km 9503999.99393599 Вывод 0.41147999937455
Отладка - простые операции с отладчиком 121 Рекомендации и подсказки Считав входные toLowerCase ( ) данные, мы можем добавить метод к показанию единиц измерения, что сделает все бук­ вы строчными. Как видно из таблицы в условии, мы можем кон­ вертировать только между метрами и какой-либо другой единицей измерения. Поэтому сначала нам нужно считать число, которое нужно преобразовать в метры. Поэтому нам необходимо выпол­ нить ряд проверок для определения того, какая единица измерения вводится и какую нам надо вьmести: function metricConverter([argl, arg2, arg3]) { let size = parseFloat(argl); let sourceMetric = arg2.toLowerCase(); let destMetric = arg3.tolowerCase(); if (sourceMetric === "km") { size = size / 0.001; } // Провер и ть остальные единицы: mm, cm, ft, yd, ... if (destMetric === "ft ") { size = size * 3.2808399; } // Провер и ть остальные единицы: mm, cm, ft , yd, ... console . log(size + '' '' + destMetric); } Проверка в системе Ju.dge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/929#7. Отладка - простые операции с отладчиком К данному моменту мы написали много кода, и в нем часто встречались ошибки, верно? Сейчас мы покажем инструмент, кото­ рый можно использовать для более легкого поиска ошибок. Что такое отладка? Отладка - это процесс «подключения» к вьmолнению програм­ мы, который по зв оляет нам отслеживать процесс вьmолнения шаг
122 Глава 3.1 . Простые проверки за шагом. Мы можем отслеживать строка за строкой, что происхо­ дит с нашей программой, какой путь она проходит, какие значения имеют определенные переменные на каждом шаге отладки и мно­ гое другое, что позволяет нам находить ошибки (баrи). ei1 ~ VARIABLES ~ 1 2 Block ~ • this: global numl: 15 3 4 5 function sumNums ([argl, arg2)) { let numl = parsei nt(argl); let num2 = parseint (arg2); let result = numl + num2 ; console . log(result) ; 6 num2: 20 7 result: 35 Отладка в 8 } Visual Studio Code Добавьте точку останова, а затем запустите программу в режиме отладки, нажав кнопку [FS]. Программа будет выполняться до тех пор, пока не достигнет точки останова. Затем мы пер еходим на сле­ дующую строку с помощью кнопки [F10]. Упражнения: простые проверки Давайте закрепим полученные в этой главе знания с помощью нескольких упражнений. Создадим пустой файл Visual Studio Code Запускаем Visual Studio Code. Создаем новый файл [File] - [New File]: о4 Visual Studio Code File 1 I Edit Selection New File View Go 1 Ne1,v Windo,•1 Debug Tasks Help Ctrl+N Ctr,+Shift+N Open File... Open Folder... [Ctrl+K Ctrl+O] Open Recent ►
Упражнения : простые проверк и 123 В результате мы получим новый файл, который в данный мо­ мент является « анонимным» для нашей системы. Чтобы сделать наш код правильно распознаваемым, нам нужно как файл JavaScript: [Fi le] - сохранить его [Save] : о4 Visual Studio Code File I Ed it Selection 1 View Go Debug Tasks Hel p Ne.v File Ne'vV WindO\f\/ Ctrl+Shift+N Open File... Open Folder... [Ct1·l+K Ctrl+O] Ореп ► Recent Save Ctrl +S Сtг1 + Sn1rt+ S Save As... Save AII {Ctrl·K S] После этого появится окно, где нужно указать имя нашего ф айла, который должен иметь расширение . j s: х ~SaveAs +- v 1' Organize • > This РС > Deslctop > JS v (.) р Searct, JS f) Newfolde, Date mocПied Name 111 This РС J 3D Objects ;'.о Туре Size 1te-ms match your search. • Deslctop ~ Documents • Downloads J, Music _ PiC1Ures 8 Videos local Disk (С:) 1 V < > File name: myfirstfunction.js Save as IYP'!' JavaScript л H,de folders I j Save Ij Can<el
Глава 124 3.1 . Простые проверки Задание: проверка отличной оценки Первое задание в упражнениях по этой теме написать функ­ - цию JavaScript, которая принимает оценку (число с плавающей точ­ кой) и печатает "Excellent!" («Отлично!»), если оценка 5.50 или выше. Примеры ввода и вывода Ввод 6 1 вывод Ввод Excellent! 5.5 1 вывод Excellent ! Ввод I 5. 49 Вывод ( нет вывода) Рекомендации и подсказки Создайте новый файл с помощью храните [File] - [New File]. Затем со­ ero ([File] - [Save]) как фaйлJavaScript с расширением. js. Для решения задачи напишем следующий код: function isExcellent(n) { let grade = parseFloat(n); if (grade >= 5.50) { console.log(''Excellent!''); } } Запустите проrрамму с помощью [Ctrl + F5], чтобы проверить ее с разными вводимыми значениями: isExcellent ( S.60); PROBLEMS OUTPUT DEBUG CONSOLE ТERMINAL Dt.:bw~.:. .. b w.i ... h inspector ,...-,., ---1 -"'1..ause Node.j'.> " nc · spect brk=123'54 t Debuaaer listening оп ws : //127.0 . 0.1:12354/52Ы64e5 IExcellent ! 1 Для значений выше 5.50 получаем результат "Excellent!": isExcellent ( S); PROBLEMS OUTPU T DEBUG CONSOLE ТERM INAL Debugging 1-1ith inspector JJГvlo ... ol Le"ause Node . js node --inspect-brk=44626 test . js Debugger listening оп ws://127.0.0.1:44626/8af48e3 Debugger attached. Waiting for the debugger to disconnect ...
Упражнения : простые проверки Для значений ниже 125 5.50 - вывода нет. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#0. Excel lent Resu lt Allowed w orking time: 0.100 sec. Allow ed memory: 16.00 МВ Size limit: 16.00 КВ Checker: Case-lnsensitive Q JavaScript code (Nod... ., Points Time and memory used ✓✓✓✓✓✓ Memory: 11.21 МВ 100 / 100 Time: 0.056 s Submit Submission date 23:28:33 18.12.2017 - Задача: отличная оценка или нет Следующее задание в этой главе - написать функцшо JavaScript, котор ая принимает оценку (число с плавающей точкой) и выводит "Excellent!", если оценка 5.50 или выше, или "Not excellent." в про­ тивном случае. Примерный ввод и вывод Ввод Вывод Ввод 6 Excellent! 5 1 Вывод Ввод Вывод Not Excellent . 5 . 49 Not excellent . Рекомендации и подсказки Сначала мы создаем новый файл JavaScript, затем напишем код программы. Вам может помочь данный пример кода: function excellent0rNot(n) { let grade = parseFloat(n);
Глава 126 3.1 . Простые проверки if (grade >= 5.50) { console.log( '' Excellent! ''); } else { console.log(''Not excellent."); } } Далее мы вызыва ем функцию, передавая ей параметры приме­ ра, и проверяем, правильно ли она работает: excellentOrNot(4 . 25); excel lentOrNot(S.60); PROBLEMS OUTPUT DEBUG CONSOLE TERMINAL Debugging 1-1ith inspector t" -~о ... о~ k~aJSe r~ode. js V n-~e __ :~sner+_hrk-3536 tes ~ DebuPPer listening on ws://121.0.0 . 1:зsзб/f4ffcc2a Not excellent .1 1 Excellent ! 1 Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/929#1. Points Time and memory used Submission date Memory: 11.20 МВ Time: 0.025 s 15:42:5119.12.2017 - Задача: четное или нечетное Н апишите программу, которая принимает целое число и выво­ дит, является ли оно четным (even) или неч етным (odd). Примеры ввода и вывода Ввод 2 1 вывод Ввод вывод Ввод Вывод Ввод Вывод even 3 odd 25 odd 1024 even Рекомендации и подсказки И снова мы создаем новый файл JavaScript. Проверить, являет­ ся ли число четным, можно с помощью опер атора %, который вер-
Упражнения: простые проверки 127 нет остаток при делении целого числа на 2 следУЮщим образом: let isEven = (num % 2 == 0). Осталось только запустить программу с помощью [Ctrl + FS] и протестировать е е : l isEven {42); 1 PROBLEMS OUTPUT DEBUG CONSOLE TERMINAL Debugging with inspector protoco1 oecause tlode . js node inspect brk-20036 test.js ~ er listening оп ws://127.0.0.l:20036/ee90abf ~ Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#2. Задача : найти большее число Напишите программу, которая принимает два целых числа и вы­ водит большее из них. Примеры ввода и вывода Ввод 5 Вывод 5 3 Ввод 3 5 1 Вывод Ввод Вывод 5 10 10 10 Ввод -5 5 вывод 5 Рекомендации и подсказки Как обычно, сначала нам нужно создать новый файл Для решения задачи i f-else. нам понадобится всего лишь JavaScript. оператор Как вспомогательный вы можете использовать код, пред­ ставленный на картинке, который намеренно размыт, чтобы чита­ тель мог сам подумать, как его выполнить: function greaterNumber([argl, arg2)) { let num1 = parse!nt(arg1); let num2 = parseint(arg2);
Глава 128 3.1 . Простые проверки } Закончив с реализацией решения, мы вызываем функцию, пе­ редав ей пар аметры образца, запускаем программу с помощью [Ctrl + FS] и те стируем ее : greaterNumber (['' S'"," 3'']); PROBLEMS OUiPUi DEBUG CONSOLE Debugging with inspectur pro~vco~ u~cou пос@ brk-2~~ 0 7 s(.j Debu er listenin on ws: //127.0.0 . 1:20 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#3. Задача: написание чисел до 9 на английском Напишите функцию, которая принимает целое число в диапазо­ не [0 ... 9] и выводит его на английском языке. Если число выходит з а пр еделы диапазона, она выв одит сообщение «число слишком ве­ лико». Примеры ввода и вывода Ввод вывод Ввод ВЫвод 5 f i ve 1 one l Ввод вывод 9 nine I Ввод 10 ВЫвод number 1 too Ьig Рекомендации и подсказки Мы можем использовать серию операторов смотреть i f -el se, чтобы рас­ 11 возможных случаев. Проверка в системе Judge Проверьте свое решение: Index/929#4. https://judge.softuni.bg/Contests/Practice/
Упражнения : простые проверки 129 Задача: угадать пароль Напишите функцию, которая принимает пароль (случайный текст) и проверяет, совпадает ли вводимый вами пароль с фразой «sЗcrЗt!P@ssw0rd». Если совпадает, выводит «Welcome», а если не со­ впадает, то «Wrong password!». Примеры ввода и вывода Ввод Вывод qwerty Wrong password! Ввод вывод s3cr3t!p@ss Wrong password! Ввод ВЫвод s3cr3t!p@ss Wrong password! Рекомендации и подсказки Используйте операторы i f-else. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#8. Задача: число между 100 и 200 Напишите функцию, которая принимает в качестве параме­ тра целое число и проверяет, меньше ли оно или больше 200. 100, между 100 и 200 Выведите соответствующие сообщения, как пока­ зано в примерах ниже. Примеры ввода и вывода Ввод вывод Ввод 95 Less than 100 120 вывод Between 100 \ and 200 Ввод 1 210 вывод 1 Greater than 200
Глава 130 3.1 . Простые проверки Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#9. Задача: одинаковые слова Напишите функцию, которая принимает в качестве параметров два слова и проверяет, одинаковые ли они. Для этой задачи давайте считать, что нет различия между заглавными и строчными буква­ ми. Выводить «yes» или «no». Примеры ввода и вывода Ввод вывод Hello Hello yes 1 Ввод вывод Ввод Вывод Ввод вывод SoftUni softuni yes Soft Uni по beer vodka по Рекомендации и подсказки Перед сравнением слов рекомендуется перевести их в нижний регистр, чтобы размер букв (верхний/нижний регистр) не влиял на работу программы: word = word . toLowerCase() . Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#10. Задача: информация о скорости Н апишите функцию, которая принимает в качестве параме­ тра скорость (число с плавающей точкой) и выводит информацию 10 (включительно) выведите «slow». Для скоростей свыше 10 и до 50 выведите «average». Для скоростей свыше 50 и до 150 - «fast». При скорости свыше 150 и до 1000 «ultra fast». При более высоких скоростях - «extremely fast». о скорости. Для скоростей до Примеры ввода и вывода Ввод вывод Ввод вывод 8 slow 126 fast 49.5 average 160 ultra fast
Упражнения : простые проверки Ввод вывод 3500 extremely fast 131 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#11. Задача: площади фигур Напишите функцию, которая принимает размеры геометриче­ ской фигуры и вычисляет ее площадь. Существует четыре типа фи­ гур: квадрат, прямоугольник, круг и треугольник. Первым аргументом (параметром) функции является тип фи­ гуры (square, rectangle, circle, triangle). Если фигура • число - квадрат, то следующим аргументом будет длина его стороны. Если фигура • - прямоугольник, то в качестве следующего аргумента передаются два числа Если фигура • - Если фигура - длины его сторон. круг, то в качестве следующего аргумента передается одно число • - - радиус круга. треугольник, то в качестве следующих аргу­ ментов передаются два числа - длина его стороны и длина его высоты. Округлите результат до трех цифр после десятичной точки. Примеры ввода и вывода Ввод Вывод Ввод 1 вывод 1 square 5 Ввод ci rcle 6 rectangle 25 Вывод 7 2.5 Ввод 17.5 1 вывод triangle 113.097 4.5 20 45
Глава 132 3.1 . Простые проверки Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#12. Задача: время + 15 минут Н апишите функцию, которая принимает в качестве параме­ тров часы и минуты 24-часового дня и вычисляет, сколько време­ ни будет через 15 минут. те всегда находятся в диапазоне от О до hh : mm. Часы Результат должен бьпь выведен в форма­ всегда находятся в диапазоне от О до 23, а минуты 59. Часы записываются одной или двумя цифрами. Минуты всегда записываются двумя цифрами и, при необходимости, с ведущим нулем. Примеры ввода и вывода Ввод 1 46 Вывод Ввод 1 2:01 1 0 1 01 1 Вывод Ввод Вывод 0:16 23 59 0:14 Рекомендации и подсказки Добавьте 15 минут и выполните несколько проверок. Если мину­ ты превышают 59, увеличьте часы на 1 и уменьшите минуты на 60. Аналогично рассмотрите случай, когда часы превышают 23. При выводе минут проверьте наличие ведущего нуля. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#13. Задача: 3 одинаковых числа Н апишите функцию, которая принимает в каче стве аргументов три числа и выводит, одинаковы ли они (yes / no). Примеры ввода и вывода Ввод 5 5 5 Вывод Ввод yes 5 4 1 1 5 вывод Ввод Вывод 1 по 1 2 3 по
Графическое веб-приложение 133 Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/929#14. Задача * : запись числа от О до 100 словами Напишите функцию, которая преобразует число в диапазоне [0 ... 100] в текст на английском языке. Примеры ввода и вывода Ввод Вывод Ввод Вывод 25 twenty fi ve 42 forty two Ввод Вывод 6 six 1 Рекомендации и подсказки Сначала проверьте однозначные числа, и если число однознач­ ное, выведите для него соответствующее слово. Затем проверьте двузначные числа. Рассматривайте их как две части: левая часть (десятки = число / 10) и правая часть (единицы = число % 10). Если число состоит из трех цифр, оно должно быть равно 100 и может рассматриваться как особый случай. Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/929#15. Графическое веб-приложение Выполнив несколько упражнений на условные операторы (про­ верки), займемся чем-то более интересным: создадим графическое приложение с веб-интерфейсом для конвертации валют. Используя знания из этой главы, мы будем выбирать одну из нескольких до­ ступных валют и вьшолнять соответствующие вычисления по раз­ ным курсам относительно выбранной валюты. Задача**: конвертер валют Давайте рассмотрим, как создать графическое (GUI) приложение для конвертации валют. Приложение будет выглядеть примерно так, как показано на рисунке:
Глава 134 3.1 . Простые проверки Currency Converter BG~ - 10 • EUR 10 Л8. : 19. Для визуализации мы будем использовать веб-браузер, отобража­ ющий НТМL-страницы. Мы создадим новую страницу и построим структуру, внешний вид и функциональность нашего приложения. Как обычно, мы создаем новый файл, затем сохраняем его с име­ нем Currency-Converter, . html. 1 но на этот раз добавляем расширение ~ SaveAs х ..., 1' Organize • > > Desktop > JS Тhis РС С) р Search New folder А Name 1!11 This РС J v 3D Obj ects Date modified Туре No items match your search. • Desktop ~ Documents • Downloads File aame: V > ( l!curтency-Converter.html! Save as type: JavaScript л Hide Folders V 11 ~ave 11 Cancel Откройте только что созданный файл и добавьте структуру доку­ мента в виде НТМL-кода: <!DОСТУРЕ html> <html> <head> <meta charset="utf-8"> <met a name="viewport" content="width=device-width, initialscale=l">
Графическое веб-приложение 135 <meta http-equiv= " x-ua-compatiЫe" content="ie=edge"> <title>Currency Converter</title> <st yle> /* enter CSS styling here */ </ style> </head> <body> <main id=''conventer-window''> <hl>Currency Converter< / hl> <form name= '' conventer ''> <input type="number" placeholder="Enter number" min="0" id="cash-input" onkeyup="convert()" onchange="convert ( ) "> <span>BGN &#8594; </span> <select onchange=''convert() '' id= ''curr ency-options''> <option selected disaЫed>Select currency</option> <option value=''eur''>EUR< / option> <option value="usd">USD< / option> <option value=''gbp''>GBP< / option> </ select> <br /> <input type="text " name="result" id="result" disaЫed> </form> </ main> <script> / / Enter JavaScript functionality here </ script> </body> </html> Сохраните файл и откройте его в веб-браузере: С О CD Currency-Converter.html Currency Converter ,_ [E_n_te_r_nu_m_Ьe_r_ _ _ _J B GN -+ , Select currency • 1
Глава 136 3.1 . Простые проверки Мы уже создали структуру html-документа, но ее можно визуаль­ но улучшить, добавив дополнительные стили. Для этого мы доба­ вим следующий код в раздел <style> нашего НТМL-документа: body { background-color: #fff; } main { margin: 200рх auto; height: 250рх; width: 500рх; background-color: #е7е7е7; border: lpx solid Ыасk; border -radius: 20рх; box-shadow: Зрх Зрх Зрх gray; } hl { text-align: center; color: #000; text-shadow: lpx lpx lpx #000; } form { width: 400рх; margin:20px auto; text-align : center; } span { font-weight:bold; font-size: lбрх; } input[type=number], input[type=text] , select { width: 140рх; padding: 8рх 10рх; margin: 20рх 0; display: inline-Ыock; border: l px solid #ссс; border-radius: 10рх; box-sizing: border-box;
Графическое веб-приложение 137 outline: none; text-align: center } input[type=text] { width: 80%; margin-top:20px; background-color: #7ЬеЬ80; padding: 12рх 10рх; color:Ыack; font-weight: bold; font-size: 15рх; } input:focus { border: 2рх solid #26а5е0; } Теперь наше приложение имеет более привлекательный вид. Осталось только добавить функциональность. Она добавляется в раздел <script> в нашем НТМL-документе. Для обработки собы­ тий мы будем использовать следующий код JavaScript: function convert(){ let х = document.getElementByid("cash-input").value; let е = document.getElementByid("currency-options"); let selected = e.options[e.selectedindex].text; let result; if (selected === "EUR") { result = х +" "+ "лв. = "+ (х * 1.95583).toFixed(2)+ " "+ selected; document.getElementByid("result").value = result; } else if (selected === ''USD'' ) { result = х +" "+ "лв . = "+ (х * 1.63760) . toFixed(2)+ " "+ selected; document.getElementByid("result") . value = result; } else if (selected === ''GBP '' ) { result = х +" "+ "лв . = "+ (х * 2.22920) . toFixed(2)+ " "+ selected; document.getElementByid(''result'').value = result; } }
Глава 138 Приведенный выше код берет сумму 3.1 . Простые для проверки конвертации cash-input и выбранную валюту для результата из поля currency-options. Затем с помощью условного оператора, в соот­ из поля ветствии с выбранной валютой, сумма делится на обменный курс (который жестко фиксируется в исходном коде). Наконец, генери­ руется текстовое сообщение с результатом (округленным до двух цифр после десятичной точки) и записывается в зеленое поле resul t. Протестируйте! Если у вас возникли проблемы с приведенными примерами, об­ ратитесь на форум SoftUni: https://softuni.bg/forurn.
Глава 3.2. Простые проверки - экзаменационные задачи В предыдущей главе мы рассмотрели условные JavaScript, в операторы которые можно использовать для вьmолнения раз­ личных действий в зависимости от некоторого условия. Мы также рассказали о том, что такое область видимости (область действия) переменной (scope), и о том, как постепенно отслеживать выпол­ нение нашей программы (это называется отладкой). В этой главе мы попрактикуемся в работе с логическими проверками, рассмо­ трев несколько экзаменационных задач. Для этого давайте сначала вспомним, как строится логическая проверка: if (boolean expression) { / / тело условного оператора; } else { / / тело оператора else; } Конструкция проверки • • условие if включает в себя: if; булево выражение - переменную булева типа (Boolean) или булево логическое выражение (выражение, возвраща­ ющее • true/ false); тело оператора, которое содержит произвольный блок ис­ ходного кода; • часть else и его блок исходного кода (необязательно). Экзаменационные задачи После того как мы вспомнили правила применения условных операторов, давайте решим несколько задач, чтобы получить прак­ тический опыт работы с оператором i f-else.
Глава 140 3.2. Простые проверки - экзаменационные задачи Задача: транспортные расходы Студенту необходимо проехать n километров. Он может выбрать один из трех видов транспорта: • Такси. Начальная плата: 0,70 BGN (BGN - международное обозначение болгарских левов). Стоимость проезда в днев­ ное время О, 79 ВGN/км. Ночной тариф - • • 0,90 лв/км. Автобус. Стоимость проезда днем/ночью: 0,09 ВGN/км. Мо­ жет использоваться на расстояниях не менее 20 км. Поезд. Тариф днем/ночью: 0,06 ВGN/км. Может использо­ ваться на р асстояниях не менее 100 км. Напишите программу, которая принимает количество киломе­ тров n и время суток (день или ночь) и находит и рассчитывает сто­ имость самого дешевого транспорта из трех. Исходные данные Из консоли считываются две строки: • Первая строка содержит число тров - • n- целое число в диапазоне Вторая строка содержит слово («ночь ») - количество киломе­ [1 ... 5000]. «day» (« день») или «night» путешествие днем или ночью. выходные данные Выведите в консоль самую низкую цену за указанное количество километров. Примеры ввода и вывода Ввод 5 day Ввод 25 day Вывод 4 . 65 вывод 2 . 25 Ввод 7 night Ввод 180 night вывод 7 вывод 10.8 Рекомендации и подсказки Мы считаем исходные данные и, в зависимости от расстояния, выберем самый дешевый транспорт. Для этого мы будем использо­ вать несколько проверок.
Задача: транспортные расходы 141 Обработка входных данных В условии задачи дана информация о вводе и выводе. Соответ­ ственно, первая часть решения будет содержать объявление и ини­ циализацию двух переменных, в которых мы будем хранить значе­ ния вводимых данных: fuпctioп traпsportPrice([distaпce, dayOrNight ] ) { Прежде чем пристуmпь к проверке, нам нужно объявить еще одну переменную, в которой мы будем хранить стоимость перевозки: let price = 0; Проведение проверок и соответствующих вычислений После того как мы объявили и инициализировали вводимые пе­ ременные, а также переменную, в которой мы будем хранить цену, нам нужно реnшть, какие условия задачи следУет проверить в пер­ вую очередь. Из условия следУет, что стоимость проезда на любом из двух средств передвижения (автобус и поезд) не зависит от того, день это или ночь, а вот стоимость проезда на такси зависит. По этой причине первой проверкой будет именно то, день сейчас или ночь, чтобы узнать, какой тариф будет использоваться для такси. Для это­ го мы объявляем еще одну переменную, в которой будем хранить значение тарифа такси: let taxiRate = 0; Чтобы рассчитать стоимость проезда в такси, мы воспользуемся условным оператором if-else: if (dayOrNight === ''day '' ) { taxiRate = 0 . 79; } else { taxiRate = 0.90; } По сле этого можно переходить к расчету стоимости перевоз­ ки. Ограничения, присутствующие в постановке задачи, касают­ ся расстояния, которое студент хочет проехать. По этой причине мы будем использовать оператор if-else, чтобы найти стоимость транспорта в зависимости от заданного расстояния:
Глава 142 3.2. Простые проверки - экзаменационные задачи if (distance < 20) { price = 0.70 + (distance * taxiRate ) ; } else if (distance < 100) { price = distance * 0.09; } else { price = distance * 0.09; } Сначала мы проверим, не меньше ли расстояние, которое 20 километров, поскольку из условия ясно, что при расстоянии меньше 20 километров студент может воспользо­ ваться только такси. Если условие проверки истинно (true), мы при­ нужно проехать студенту, своим соответствующее значение переменной, хранящей значение стоимости перевозки (price). Это значение равно начальному тари­ фу, который мы добавим к его стоимости, умноженной на расстоя­ ние, которое должен проехать студент. Если условие переменной не является истинным (false ) , то сле­ дующим шагом наша программа проверяет, не является ли рассто­ яние меньше 100. Мы делаем это потому, что из условия очевидно, что автобус может использоваться в качестве средства передвиже­ ния в этом диапазоне. Стоимость одного километра для автобуса ниже, чем для такси. Поэтому, если результат проверки равен true, то в теле блока транспорта else-if мы должны присвоить переменной цены (price) значение, равное результату умножения стои­ мости проезда на автобусе на расстояние. Если и эта проверка не даст результата true, то нам остается при­ своить переменной, которая отвечает за стоимость транспорта, в теле оператора else значение, равное результату умножения расстояния на стоимость проезда на поезде. Это делается потому, что поезд явля­ ется самым дешевым видом транспорта на данном расстоянии. Вывод выходных данных После того как мы проверили расстояние и вычислили самую низкую цену перевозки, мы должны вывести ее на экран. В поста­ новке задачи нет требований к тому, как должен быть оформлен ре­ зультат, поэтому мы выведем только переменную: console.log(price ) ; Проверка в системе Judge Проверьте свое решение: Index/930#0. https://judge.softuni.bg/Contests/Practice/
Задача: трубы в бассейне 143 Задача: трубы в бассейне Бассейн объемом V имеет две трубы, из которых он наполняется. Каждая труба имеет определенный расход (измеряемый в литрах воды, проходящих через трубу за один час). Рабочий одновременно включает две трубы и уходит на время N часов. Напишите програм­ му, которая выводит состояние бассейна на момент возвращения рабочего. Входн ые данные В функцию передаются четыре числа (аргумента): • Первая строка содержит число v - объем рах - целое число в диапазоне [1 ... 10000]. • Вторая строка содержит число провода в час - • расход первого трубо­ Pl - целое число в диапазоне [1 ... 5000]. В третьей строке записано число Р2 -расход второго трубо­ провода в час - целое число в диапазоне • бассейна в лит­ Четвертая строка содержит число н ботника - [1 ... 5000]. часы отсутствия ра­ число с плавающей точкой в диапазоне - [1.0 ... 24.00]. Выходные да нные Вьmедите на экран одно из двух возможных состояний: • На сколько заполнился бассейн и какая труба внесла сколь­ ко процентов. Приведите все проценты к целому числу (без округления): о "The pool is («Бассейн [х]% заполнен full. Pipe 1: на [ х ]% . Pipe 2: [z]%." 1: [у] % . Труба 2: [у]%. Труба [z]%»). • Если бассейн переполнился - на сколько литров он пере­ полнился за указанное время, число с плавающей точкой: о "For [х] hours the pool overflows with [ у] liters . " («За [х] часов бассейн переполняется на [у] литров » ). Обратите внимание, что при округлении до целого числа проис­ ходит потеря данных, и нормальным является тот факт, что сумма процентов составляет не 100 %, а 99 %.
Глава 144 3.2. Простые проверки - экзаменационные задачи Примеры ввода и вывода Ввод 1000 100 120 1з вывод 1 The pool is 66% full. Pipe 1: 45%. Pipe2: 54%. Ввод 100 100 100 2.5 1 вывод 1 For 2. 5 hours the pool overflows with 400 liters. Рекомендации и советы Для решения задачи мы считаем входные данные, выполним не­ сколько проверок и вычислений и выведем результат. Обработка входных данных function poolPipes([volume, pipel, pipe2, hours]) { Следующим шагом будет объявление и инициализация перемен­ ной, в которой мы вычислим, сколько литров было заполнено в бас­ сейне за время отсутствия работника. Мы произведем вычисления, сложив значения расхода воды в двух трубах и умножив их на коли­ чество часов, которые даны нам в качестве входных данных: let water = Выполнение проверок и форматирование вывода После того как мы получили знач ение количества воды, прошед­ шей п о трубам, следующим шагом будет сравнение этого количе­ ства с объемом самого бассейна. Мы сделаем это с помощью простой проверки i f-else, в которой условием будет то, меньше ли количество воды, чем объем бассей­ на. Если проверка возвращает true, то нам нужно вывести строку, содержащую отношение количества воды, прошедшей по трубам, к объему бассейна, а также отношение количества воды из каждой трубы к объему бассейна. Соотношение должно быть выражено в процентах, поэтому все значения, которые были вычислены, будут умножены на 100. Зна-
Задача: СОННЫЙ кот Том 145 чения будут вставлены с помощью placeholder, а поскольку суще­ ствует условие форматирования результата в процентах до двух цифр после запятой без округления, мы воспользуемся методом Math. trunc ( ... ) : if (water <= volume) { console.log( "The pool is ${Math.trunc( Pipe 1: ${Math.trunc( Pipe 2: ${Math.trunc( )}% full. ) }%. ) }%" ); } else { console.log( "For ${ hours } hours t he pool overflows with ${wate r - volume} liters . · ); } Однако если проверка возвращает false, это означает, что коли­ чество воды больше объема бассейна, поэтому он переполнился. И снова вывод должен быть в виде одной строки, но на этот раз он содержит только два значения - часы, когда работник отсут­ ствовал, и количество воды, которое является разницей между на­ бранной водой и объемом бассейна. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/930#1. Задача: сонный кот Том Кот Том любит спать целыми днями, но его хозяин играет с ним в свое свободное время, тем самым мешая ему спать. Для того что­ бы Том хорошо высъmался, норма его игры должна составлять 30 ООО минут в год. Время игр Тома зависит от выходных дней его хозяина: • • 63 минуты в день. Во время выходных хозяин играет с ним 127 минут в день. Когда хозяин на работе, он играет с Томом Напишите программу, которая принимает количеств о въrходньrх дней и выводит, может ли Том хорошо выспаться и на сколько коли-
Глава 146 3.2. Простые проверки - экзаменационные задачи чество часов его сна отличается от нормы для текущего года, предпо­ лагая, что в годУ Пример: 20 365 дней. выходных дней -> 345 рабочих дней (365 - 20 = 345). Фактическое время на игры составляет 24 275 минут (345 * 63 + 20 * 127). Отличие от нормы - 5725 минут (30 ООО - 24 275 = 5725), или 95 часов 25 минут. Входные данные Программа принимает целое число (аргумент) - количество вы­ ходных дней в интервале [0 ... 365]. Вывод данных В консоль должны быть выведены две строки. Если игровое время Тома превышает норму для текущего года: • о В первой строке выведите «Тот will run away» («Том сбежит»). о Во второй строке выведите отличие от нормы в формате «{Н} hours and {М} min utes for play» ( «На {Н} часов и {М} минут больше на игры»). • Если игровое время Тома ниже нормы для текущего года: о В первой строке выведите: «Тот sleeps well» («Том высыпается»). о Во второй строке выведите отличие от нормы в формате «{Н} hours and { М} minutes less for play» часов и {М} минут меньше на игры»). Примеры ввода и вывода Ввод Вывод Тот sleeps well 95 hours and 25 minutes less for play 20 Ввод Вывод 1 113 тоm will run away 3 hours and 47 minutes for l play («На {Н}
Задача: СОННЫЙ кот Том 147 Рекомендации и подсказки Чтобы решить задачу, мы считаем входные данные, выполним несколько проверок и вычислений и вьmедем результат. Обработка входных данных и соответствующие вычисления Из постановки задачи видно, что входные данные - это целое число в диапазоне [0 ... 365]. function sleepyCatTom( [holidays]) { Чтобы решить задачу, сначала нужно подсчитать, сколько всего минут хозяин Тома играет с ним. Из условия видно, что кроме вы­ ходных сонный кот должен играть и в р абочие дни своего хозяина. Число, которое мы получили из консоли, это количество выходных дней. Следующим шагом мы используем это число, чтобы вычислить, сколько рабочих дней у хозяина, потому что без них мы не сможем получить общее количество минут для игры. Поскольку общее ко­ личество дней в го-ду равно 365, а количество выходных дней рав­ но х, это означает, что количество рабочих дней р авно 365 - х. Разницу мы запишем в новую переменную , которую будем исполь­ зовать только для этого значения: let workingDays = Теперь, когда у нас есть количество рабочих дней, мы можем рас­ считать игровое время Тома в минутах. Его значение равно резуль­ тату умножения рабочих дней на 63 минуть~ (в условии указано, что в рабочие дни время игры составляет 63 минуты в день), при­ бавленному к результату умножения выходных дней на 127 ми­ нут (в условии указано, что в выходные дни время игры составляет 127 минут в день). l et totalPlayMinutes = В условии вывода задачи мы видим, что нам нужно вьmести разницу между двумя значениями в часах и минутах. Для этого мы вычтем из общего времени игры норму в 30 ООО минут и запи­ шем полученную разницу в новую переменную. Затем мы разде­ лим это целое число на 60, чтобы получить часы, а чтобы узнать количество минут, воспользуемся вычислением остатка с опера-
Глава 148 тором на %, 3.2. Простые проверки - экзаменационные задачи снова разделив переменную, в которой записана разница 60. Здесь следует отметить, что если полученная сумма игрового времени Тома меньше 30 ООО, то при вычитании из нее нормы по­ лучится число с отрицательным знаком. Чтобы нейтрализовать данную проблему, в дальнейшем при нахождении разности мы бу­ дем использовать метод Math. abs ( ... ): let difference = Math.abs( let hours = let niinutes = ); Проведение проверок Время игры теперь подсчитано, что подводит нас к следующе­ му шагу - сравнению времени игры Тома с нормой, которая опре­ деляет, сможет ли кот хорошо выспаться. Для этого мы используем проверку if-else, в части с if мы должны проверить, не превыша­ ет ли время игры 30 ООО (норма). Обработка вывода Какой бы результат ни выдала проверка, нам нужно вьmести, сколько составляет разница в часах и минутах. Мы сделаем это с помощью placeholder ( $ ) и переменных, в которых мы вычисли­ ли значения часов и минут, отформатир овав их в соответствии с ус­ ловием вывода: if (t otalPlayMinutes > 30000) { console . log("Tom will run away"); console.log('${Math. floor(hours)} hours and ${Math. floor(minutes)} minutes more for play'); } else { console.log(''Tom sleeps well ''); console. log('${Mat h. floor(hours) } hours and ${Math. floor(minutes)} minutes less for play'); } Проверка в системе Judge Проверьте свое решение: Index/930#2. https://judge.softuni.bg/Contests/Practice/
Задача: сбор урожая 149 Задача: сбор урожая С виноградника площадью х кв. м 40 % урожая идет на произ­ 1 кв . м виноградника получают У кг винограда. Для производства 1 литра вина требуется 2,5 кг винограда. Желаемое количество вина для продажи - z литров. водство вина. С Напишите программу, которая вычисляет, сколько вина мож­ но произвести и достаточно ли этого количества. Если достаточно, то остаток делится поровну между работниками виноградника. Входные данные Входные данные, которые считывает программа, состоят из че­ тырех строк (аргументов): • Первая строка: х кв. м - площадь число в интервале [10 ... 5000]. виноградника - целое • Вторая строка: У винограда на квадратный метр - веще­ ственное число в интервале [О,00 • Третья строка: требуется апазоне • ... 10,00]. z литров вина - целое число в ди­ [10 ... 600]. Четв ертая строка: количество работников в диапазоне - целое число [1 ... 20]. Входные дан.ные В консоль должно быть выведено следующее сообщение: • Если количество произведенного вина меньше требуе­ мого: о «It will Ье количество} зима! Нужно а tough winter! More liters wine needed. » ( (( Это больше {недостающее {недостающее будет кол ичес тво} суровая литров вина»). Результат должен быть округлен до меньшего це­ лого числа. • Если произведенного вина больше, чем требуется: о «Good harvest this year ! Total wine: { общее количество вина} li ters. » ( ((Хороший урожай в этом году! Общее
Глава 150 3.2. Простые проверки - экзаменационные задачи количество вина} :литров»). Результат должен быть окру­ глен до меньшего целого числа. о liters left -> {вино на 1 работника} liters per person . » ( « {Осталось вина} литров-> {Вино на 1 работника} литров на человека»). Оба результата «{Осталось} должны быть округлены до большего целого числа. Примеры ввода и вывода Ввод 650 2 175 3 Ввод 1020 1. 5 425 4 Вывод 1 Good harvest this year! Total wine: 208 liters. 33 liters left -> 11 liters per person Вывод It will Ье а tough winter! More 180 liters wine needed. Рекомендации и советы Для решения задачи мы считаем входные данные, вьmолним несколько проверок и вычислений и выведем результат. Обработка входных данных и соответствующие вычисления Сначала нам нужно считать входные данные: function harvest( [vineyardArea, grapePerSquare, neededliters, workers]) { Для решения задачи нам нужно вычислить, сколько литров вина мы получим на основе исходных данных. Из условия задачи видно, что для вычисления количества вина в литрах нам снача­ ла нужно узнать, какое количество винограда в килограммах будет получено с данного урожая. Для этого мы объявим переменную , ко-
Задача: сбор урожая 151 торой присвоим значение, равное 40 о/о от результата умножения площади виноградника и количества винограда, получаемого с од­ ного квадратного метра. После того как мы произвели эти расчеты, мы готовы вычис­ лить количество вина в литрах, которое будет получено из этого урожая. Для этого мы объявляем еще одну переменную, в кото­ рой будем хранить это количество. Из условия мы делаем вывод, что для ее вычисления нам нужно разделить количество вино­ града в кr на 2,5: let harvestPerVine = let wine = Выполнение проверок и форматирование вывода данных Теперь мы произвели необходимые расчеты, и следующим ша­ гом будет проверка, которая выяснит достаточно ли полученных литров вина. Для этого мы воспользуемся условным оператором типа i f-else, а в условии пров ерим, больше ли литров вина из уро­ жая или равно необходимому количеству литров. Если проверка вернет true, то из условия задачи видно, что в пер­ вой строке должно быть выведено количество вина, которое мы по­ лучили из урожая. Чтобы выполнить условие, это значение нужно округлить до меньшего целого числа, при выводе которого мы вос­ пользуемся методом щью Math. floor( ...) и выведем в консоль с помо­ placeholder. Вторая строка требует вьmода результатов, округленных до старшего целого числа, что мы и сделаем с помощью метода Math.ceil( ... ). Нам нужно вывести следующие значения: количе­ ство оставшегося вина и количество вина на одного работника. Оставшееся количество вина равно разнице между полученными и необходимыми литрами вина. Значение этого количества мы вы­ числим в новой переменной, которую объявим и инициализируем в теле блока i f, перед тем как вывести первую строку. Количество вина на одного рабочего мы вычислим, разделив оставшееся вино на количество рабочих. ) { if ( let i-,ineleft =
Глава 152 3.2. Простые проверки - экзаменационные задачи console.log ( · Good ha rvest t hi s year! Tot a l 1-1ine: ${1'1 ath.floor( ) } l ite rs . · ) ; console.log ( . ${Nath.ceil( ${1,1ath. ceil ( )} liters left -> )} l iter s per person. ') ; } Если проверка возвращает false, из условия задачи видно , что нам нужно вывести разницу между требуемыми литрами и ли­ трами вина, полученного из этого урожая. Также по условию нам надо, чтобы результат был округлен до меньшего целого числа, что мы и сделаем с помощью метода el s e { console .log (' I t wi l l More ${Math . f l oor ( Ье а Math. floor( ... ): tough wi nter! )} liters wi ne needed . ") } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/930#3. Задача: компания П-компания получает запрос на разработку проекта, требующе­ го определенного количества часов. У компании есть определенное количество дней. В течение 10 % дней сотрудники находятся на обу­ чении и не могут работать над проектом. Нормальный рабочий день в компании составляет 8 часов. Проект важен для компании, и каж­ дый сотрудник должен работать над проектом в нерабочее время по 2 часа в день. Количество часов должно быть округлено до меньшего целого числа (например, 6,98 часа округляется до 6 часов). Н апишите программу, которая вычисляет, сможет ли компания завершить проект в срок и сколько ча сов не хватает или остается. Входные данные Программа считывает три строки (аргумента) : • В первой строке указываются требуемые часы ло в диапазоне [О ... 200 ООО]. целое чис­
Задача: компания • 153 Вторая строка - количество дней, имеющихся в распоря­ жении компании - ... 20 ООО]. Третья строка - это количество всех сотрудников - целое число в диапазоне [О ... 200). • целое число в диапазоне [О Выходные данные Для вывода строки в консоль : • Если времени достаточно: left . » ( «да! {оставшиеся • «Yes !{оставш и еся Необходимо hours { сколько hours часы} часов осталось»). Если времени недостаточно: часов не хват ило} часы} «Not enough time ! { сколько nееdеd.»(«Недостаточно времени! часов не хват ило} часов»). Примеры ввода и вывода Ввод вывод 90 7 3 Yes! 2 hours left. Ввод вывод 99 3 1 Not enough time! 72 hours needed Рекомендации и советь~ Для решения задачи мы считаем входные данные, выполним не­ сколько проверок и вычислений и въmедем результат. Обработка входных данных Чтобы решить задачу, сначала нужно считать входные данные : function firm([projectHours, availaЬleDays, workers ]) { Вспомогательные расчеты Следующий шаг - вычисление количества рабочих часов пу­ 8 (каждый день работник трудит­ Рабочие дни равны 90 % дней из-за тем умножения р абочих дней на ся по 8 часов) на количество. обучения. Дополнительное р абочее время равно результату умно-
Глава 154 3.2. Простые проверки жения количества работников на - экзаменационные задачи 2, и оно также умножается на ко­ личество дней, имеющихся в распоряжении фирмы. Из постанов­ ки задачи видно, что есть условие округления часов до меньшего целого числа, что мы и сделаем с помощью метода let let let let Math. floor( ...): workDays = overtimeHours = \~orkHours = totalHours = Проведение проверок После того как мы произвели все необходимые расчеты и полу­ чили количество рабочего времени, необходимо проверить, хва­ тило ли этих часов для вьmолнения проекта или остались допол­ нительные. Если времени достаточно , то мы выводим результат, который требуется по условию задачи, а именно разницу между рассчитан­ ным рабочим временем и требуемым для завершения проекта . Если времени недостаточно, мы выводим на экран количество дополнительных часов, необходимых для завершения проекта, ко­ торое равно разнице между часами, необходимыми для создания проекта, и получившимся общим количеством рабочих часов: if ( ) { console. l og("Yes!${ } else { console.log( 'Not enough time!${ } hours needed. ') ; } hours left . ' ) ; } Проверка в системе Judge Проверьте свое решение: Index/930#4. https://judge.softun.i.bg/Contests/Practice/
Глава 4.1. Более сложные проверки В этой главе мы рассмотрим вложенные проверки в которые позволяют программе содержать условные JavaScript, операторы, внутри которых вложены другие условные операторы. Мы назы­ ваем их вложенными, потому что помещаем оператор другого оператора if. if внутри Мы также рассмотрим более сложные логи­ ческие условия на соответствующих примерах. Вложенные проверки Довольно часто логика программы требует использования про­ верок i f или i f-else, которые содержатся друг в друге. Такие про­ верки называются вложенными if или if-else. Как следует из на­ звания «вложенные», это утверждения if или if-else, которые вложены в другие утверждения i f или else: if (условиеl) if { ( условие2) // { набор команд; } else { // набор команд; } } Вложение более трех условных операторов друг в друга не счита­ ется хорошей практикой, и его следует избегать, особенно оптими­ зируя структуру/алгоритм кода и/или используя другой тип услов­ ного оператора, о котором мы поговорим позже. Пример : обраще1П1е по возрасту и полу В соответствии с введенным возрастом (вещественное число) и полом (m/0 (м/ж) на экран будет выведено обращение:
156 • «Mr. » - мужчина (пол «m», то Глава 4.1. есть «rnale», мужской) - 16 и Более сложные проверки более лет. • • «Master» - юноша (пол «m») в возрасте до 16 лет. «Ms. » -женщина (пол «f», «fernale», женский)-16 и более лет. • «Miss» -девушка (пол «f ») в возрасте до 16 лет. Примеры ввода и вывода Ввод вывод Ввод 17 m вывод Ввод Вывод Mr. 25 f Ms . Ввод Вывод 13 . 5 m Master Решение Можно заметить, что результат работы программы зависит от нескольких вещей. Сначала нам необходимо проверить, какой пол введен, а затем проверить возраст. Соответственно, мы будем использовать несколько блоков if-else. Эти блоки будут вложен­ ными, то есть результат выполнения первого из них будет опреде­ лять, какой из остальных выполнить далее: TRUE TRUE г age < 16 gender FALSE = "f " TRUE FALSE age < 16 FALSE ·'Miss" После считывания входных данных из консоли необходимо вы­ полнить следующий пример программной логики:
Вложенные проверки 157 function personalTitles([argl, arg2]) { let age = Number(argl); let gender = arg2; if (age < 16) { if (gender === 'm') { console . log("Master"); } el se if (gender === 'f') { console.log(''Miss'' ); } } else { if (gender === 'm') { console.log(''Mr."); } else if (gender === 'f') { console . log("Ms . "); } } } Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#0. Пример: маrазШI в микрорайоне Пр едприимчивый болгарин открывает в нескольких городах ма­ газины с разными ценами на следующие товары: продукт / город coffee water beer sweets peanuts . Sofia 0.50 0 . 80 1.20 1.45 1 . 60 Plovdiv Varna 0.40 0.45 0 . 70 1 .10 1 . 35 1 . 55 0 . 70 1 . 15 1.30 1 . 50 Рассчитайте цену по заданному городу (строка), товару (строка) и количеству (вещественное число). Примеры ввода и вывода Ввод coffee Varna 2 Вывод Ввод 0.9 peanuts ilovdiv Вывод 1. 5 Ввод I Вывод beer Sofia 1 6 1 7. 2 Ввод water Plovdiv 3 вывод 2. 1
Глава 158 4.1. Более сложные проверки Решение Мы переводим все буквы в нижний регистр с помощью мето­ да . tolowerCase( ), чтобы сравнение товаров и городов не зависело от регистра: let product = argl.tolowerCase(); let town = arg2.toLowerCase(); let quantity = Number(argЗ); if (town === "sofia") { if (product === ''coffee'') { console.log((0.50 * quantity).toFixed(2)); //TODO: завершите самостоятельно фрагмент программы ... } } else if (town === "provdiv") //TODO: завершите самостоятельно фрагмент программы ... else if (t own === "varna") //TODO: завершите самостоятельно фрагмен т программы ... Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#1. Более сложные проверки Давайте рассмотрим, как можно выполнять более сложные логи­ ческие проверки. Мы можем использовать логическое «И» (&&), ло­ гическое «ИЛИ» ( 11 ), логическое отрицание (!)и круглые скобки ( () ). Логическое « И » Как мы видели, в некоторых задачах нам нужно выполнить сра­ зу несколько проверок. Но как быть, если для вьmолнения кода не­ обходимо, чтобы выполнялось больше условий, и мы не хотим де­ лать отрицание блоками (else) для каждого из них? Вариант с вложенными i f допустим, но код будет выглядеть очень неопрятно - его будет трудно читать и подцерживать. Логическое «И» (оператор &&) означает одновременное выпол­ нение нескольких условий. Работает следующая таблица истин­ ности:
Более сложные проверки 159 а Ь а ь true true true true false false false true false false false false Как р аботает опер атор Оператор && && &&? принимает несколько булевых (условных) выраже­ ний, имеющих значение true или false, и возвращает нам в каче­ стве результата одно булево выражение. Использование этого опе­ ратора вместо нескольких вложенных блоков if делает код более читабельным, аккуратным и простым в отладке. Но как это работа­ ет, когда мы ставим несколько условий друг за другом? Как мы ви­ дели выше, логическое « И» возвращает true только тогда, когда принимает в качестве аргументов выражения со значением true. Соответственно, когда у нас есть последовательность аргументов, логическое «И» проверяет, либо пока не закончатся аргументы, либо пока не встретит аргумент со значением f alse. Пример: let let let let а = ь = = d = с true; true; false; true; let result = а && Ь && / / false ( так как d не с && d; проверяется) Программа будет вьmолнятъся следующим образом: она начи­ нает проверку с аргумента а, считывает его и сообщает, что он име­ ет значение true, затем проверяет ь. После того как программа сообщила, что а и ь возвращают t rue, она проверяет следующий аргумент. Она доходит до с и сообща­ ет, что переменная имеет значение false. Как только програм­ ма сообщает, что аргумент с имеет значение false, она оценива­ ет выражение до с, независимо от того , какое значение имеет При этом проверка как false. d. d пропускается, и все выражение оценивается
Глава 160 4.1. Более сложные проверки Пример: точка в прямоугольнике Проверьте, находится ли точка {х, { xl, yl} - { х2, у } внутри прямоугольника у2}. Входные данные считываются из консоли и со­ стоят из шести строк: десятичные числа xl, yl, х2, у2, х и у (при этом должно быть обеспечено, что xl < х2 и yl < у2) . Пример ввода и вывода Ввод Визуализация Вывод о -5 2 2 . 12 Inside 3 (Внутри) 8 10 12 8 . .'' - -- - 1 1 • -1 х, у 1 1 3 -- - - - -1 6 xl; yl -3 - - - - -3 4 1 5 1 1 1 1 -- -- х2,у2 1 1 Решение Точка является внутренней по отношению к прямоугольнику, если одновременно выполняются следующие четыре условия: • • • • Точка находится справа от левой стороны прямоугольника. Точка находится слева от правой стороны прямоугольника. Точка находится внизу от верхней стороны прямоугольника. Точка находится вверху от нижней стороны прямоугольника. let xl = Number(argl); let yl = Number(arg2); let х2 = Number(argЗ); let у2 = Number(arg4); let let х = Number(argS); у= Number(argб); >= xl && х <= х2 && у>= yl && console . log(''Inside''); } else { console.log("Outside") if } (х у<= у2) {
Логическое «ИЛИ» 161 Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#2. Логическое « ИЛИ» Логическое «ИЛ И » (оператор 11) означает, что вьmолняется хотя бы одно из нескольких условий. Как и оператор &&, логическое «ИЛИ» принимает несколько аргументов булевого (условного) типа и возвращает true false. или Легко догадаться, что значение true мы получаем всякий раз, когда хотя бы один из аргументов имеет значение true. Типичным примером логики этого оператора явля­ ется следующий. В школе учитель говорит: «Иван или П етр должны вымыть до­ ску». Для того чтобы это условие было выполнено (до ска была вы­ мыта) , можно, чтобы ее вымыл только Иван, только Петр или оба. а or а ь Ь True True True True False True False True True False False False Как работает оператор 1 1 ? Мы уже узнали, что тако е логическо е «ИЛИ». Но как оно реализу­ ется на практике? Как и в случае с логическим « И», программа пр о­ веряет слева направо указанные аргументы. Для того чтобы полу­ чить из выражения имел значение true, необходимо, чтобы только один аргумент true, поэтому проверка продолжается до тех пор, пока не встретится аргумент с таким значением или пока не закон­ чатся аргументы. Приведем пример оператора 11 в действии: bool ean а = false; bool ean ь = true; bool ean с = false; bool ean d = true; bool ean result = а 11 ь 11 с 11 d; // true (так как с и d не проверяются)
Глава 162 4.1. Бол ее слож н ые проверки Программа проверяет а , сообщает, что оно имеет значение f alse, и продолжает работу. Достигнув ь, она сообщает, что ь имеет зна­ чение ки с true, и все выражение получает значение true без провер­ и d, поскольку их значения не изменят результат выражения. Пример : фрукт или овощ Давайте проверим, является ли продукт фруктом или овощем. К фруктам (fruit) относятся banana, apple, cherry, lernon и grapes. Овощами (vegetahle) являются tornato, cucurnher, pepper и carrot. Все остальные - «неизвестно » (unknown). Пр имер ввода и вывода Ввод вывод banana fr uit tomato vegetaЫe kiwi fr uit java unknown Решение Н ам нужно использовать несколько условных провер ок с логи­ ческим «ИЛИ» l et s = ( 1 1): argl; if (s === " Ьапа п а " 1 1 s === "apple " 1 1 s === "kiwi " "cherry" 1 1 s === "lemoп " 11 s - - - "grapes ") { console.log(''fruit ''); } else if (s === "tomato " 11 s - - - "cucumber" 11 s 11 s === ''carrot '' ) { 11 s "pepper" co n sole.log (" vegetaЫe" ) ; }else { c oпsole . l og ("un k n own" ) ; } Проверка в системе Judge Проверьте свое решение: Index/931#3. https://judge.softuni.bg/Contests/Practice/
Логическое отрицание 163 Логическое отрицание Логическо е отрицание (оператор !) означает, что условие не вы­ полняется. а true !а ' false Оператор ! принимает в качестве аргумента булеву перемен­ ную и меняет ее значение на противоположное (истина становит­ ся ложью, а ложь - истиной). Пример: недопустимое число Число считается допустимым, если оно находится в диапазоне [100 ... 200] или равно О. Выведите сообщение «invalid», если число недопустимо . Примеры ввода и вывода Ввод Вывод 75 invalid 150 (нет вывода) 220 invalid Решение let num = Number (argl) ; let inRange = (num >= 100 && num <= 200) 1 1 num === 0; if (!inRange) { console . log("invalid"); } Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#4. Оператор круглых скобок () Как и другие операторы в программировании, операторы && и 11 подчиняются правилам приоритета, в данном случае && имеет
Глава 164 больший приоритет, чем 4.1. Более сложные проверки 11- Оператор ( ) используется для измене­ ния приоритета оператор ов и оценивается первым, как и в матема­ тике. Использование круглых скобок таюке делает код более чита­ бельным и считается хорошей практикой. Более сложные логические условия Иногда условия могут быть достаточно сложными и тр е бовать длинного булева выражения или ряда проверок. Рассмотрим не­ сколько таких примеров. Пример: пр1П1адлежностъ точки стороне прямоугольника Н апишите программу, которая пр ов еряет, находится ли точка {х , у} на одной из сторон прямоугольника {х1 , у1 } - {х2, у2}. Входные данные считываются из консоли и состоят из шести строк: десятичные числа х1, xl < х2 и yl < х2, у2, х и у (при этом необходимо, чтобы yl, у2). В ыведите ся на одной из сторон) или «Border» («Сторона» ) (точка находит­ «Inside / Outside» («Внутри/снаружи ») (в противном случа е). О 2 4 6 8 10 12 1 _, -5 -3 -- - xl j yl - - -1 1► х, у 1 3 5 ---- . х2, у2 1 1 1 1 Примеры ввода и вывода Ввод 2 -3 12 3 12 -1 Вывод Ввод Вывод Border 2 -3 12 3 8 -1 Inside/ Outside
Более сложные логические условия 165 Решение Точка лежит на одной из сторон прямоугольника, если: • х совпадает с xl или х2 и в то же время у находится между yl И у2. • у совпадает с yl или у2 и в то же время х находится между xl и х2. if (((х === xl 1 1 х === х2) && (y>=yl) && (у<= yl l I у=== у2) && (х>=х1) && (х <= х2))) { console . log( "Border"); у2)) 11 ((у=== } let let let let onleftSide = (х === х1) && (у>= yl) && (у<= у2); onRightSide = (х === х2) && (у>= yl) && (у<= у2); onlowerSide =(у=== у1) && (х >= х1) && (х <= х2); onUpperSide =(у=== у2) && (х >= х1) && (х <= х2); if (onleftSide 1 1 onRightSide console.log("Border"); 11 onlowerSide 11 onUpperSide) { } Второй способ с дополнительными булевыми переменными длиннее, но он гораздо понятнее первого , не так ли? При на­ писании булевых терминов рекомендуется делать их легкими для чтения и понимания. При необходимости мы используем дополнительные переменные с осмысленными именами. Име­ на булевых переменных должны подсказывать, какое значение в них хранится. Осталось дописать код, чтобы выводить «Inside/Outside», если точка не находится на одной из сторон прямоугольника . Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/931#5. Пример : фруктовый магазин Фруктовый магазин в будние дни продает фрукты по следую­ щим ценам:
Глава 1 66 Фрукт Цена banana apple orange grapefruit kiwi pineapple grapes 2.50 1.20 0.85 1.45 2.70 5.50 3.85 4.1. Более сложные проверки В выходные дни цены выше: Фрукт Цен а banana apple orange grapefruit kiwi pineapple grapes 2.70 1.25 0.90 1.60 3.00 5.60 4.20 Напишите программу, которая считывает из консоли назва­ (banana / apple / ... ) (банан / яблоко / ...), день недели (Monday / Tuesday / ... ) (понедельник/ вторник/ ...), количество (де­ ние фрукта сятичное число) и вычисляет цену в соответствии с ценами в та­ блицах, приведенных выше. Выведите результат, округленный до двух цифр после десятичной точки. Если указаны неверный день недели или неверное название фрукта, выведите сообщение «error» («ошибка»). Примеры ввода и вывода Ввод orange 1 sunday з Ввод grapes Saturday 10 . 5 Вывод Ввод 1 kiwi Monday 2.70 Вывод 6.75 2. 5 вывод Ввод tomato Monday 2 . 10 0.5 1 Вывод error
Более сложные логические условия 167 Решение if (day === "saturday" 11 day === "sunday" ) { if (fruit === ''banana'' ) price = 2. 70; else if (fruit === "apple") price = 1.25; / / TODO: добавьте здесь обработку для остальных фруктов } else if (day === "monday" 11 day === "tuesday" 11 day === "wednesday" 11 day === "thursday" 11 day === "friday") { if (fruit === "banana") price = 2. 50; / / TODO: добавьте здесь обработку для остальных фруктов } Проверка в системе Judge Пр оверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/931#6. Пример: комиссионное вознаграждение Компания устанавливает следующие комиссионные для своих продавцов в зависимости от города, в котором они работают, и объ­ ема продаж Город Sofia Varna Plovdiv s: 0 <= s <= 500 500 < s <= 1000 5 % 4.5 % 7 % 7.5 % 5.5 % 8 % 1000 < s <= 10000 s > 10000 8 % 12 % 13 % 10 % 12 % 14.5 % 1 1 Напишите программу, которая считывает название города (строка) и объем продаж (десятичное число) и вычисляет р азмер комиссионного вознаграждения. Результат должен выводить­ ся с округлением до двух цифр после десятичной точки. Если го­ род или объем продаж неверны ( отрицательное число), выведи­ те error «ошибка». Примеры ввода и вывода Ввод Sofia 1500 вывод Ввод Plovdiv 120.00 1 '--------'------' 1499. 99 Вывод 27.50 Ввод Kaspichan -50 вывод error 1
Глава 168 4.1. Более сложные проверки Решение При считывании входных данных мы можем перевести назва­ ние города в нижний регистр (с помощью метода Изначально мы устанавливаем комиссию в - 1. . toLowerCase( )). Она будет изменена, если город и диапазон цен будут найдены в таблице комиссий. Для расчета комиссии в зависимости от города и объема продаж нам пона­ добится несколько вложенных проверок i f, как в примере кода ниже: let commission = -1; if (town === ''sofia'' ) { if (sells >= 0 && sells <= 500) commission = 0.05; else if (sells > 500 && sells <= 1000) commission = 0.07; // TODO: провер ка другого ценового диапазона } else if (t own === "varna") // TODO: провер и ть диапазон цен else if (town === "plovdiv") // TODO: проверить диапазон цен if (commission >= 0) { commission = sells * commission; console.log(commission.toFixed(2)); } else console . log(''error''); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#7. Хорошей практикой является использование блоков, которые мы заключаем в фигурные скобки { дУется делать отступ после } после i f и else. Также рекомен­ if и else на одну табуляцию, чтобы код бьто легче читать. Конструкция Конструкция ков if-else. switch-case switch-case работает как последовательность бло­ Когда работа нашей программы зависит от значения переменной, вместо последовательных проверок с помощью бло­ ков if-else можно использовать конструкцию switch-case. Она применяется для выбора из списка возможных вариантов. Кон­ струкция сравнивает значение с определенными и вьmолняет действие в зависимости от результата . константами
switch-case Конструкция 169 Переменная, которую мы хотим сравнить, помещается в круглые скобки после оператора switch и называется селектором. Здесь тип должен быть сопоставимым (числа, строки). Сравнение начинает­ ся последовательно с каждого значения, которое идет после case. При совпадении выполнение кода начинается с соответствующего break. При отсутствии совпаде­ умолчанию (default), если таковой места и продолжается до оператор а ния выполняется оператор по существует: swit ch (selector) { case значение 1: набор операторов; break; case значение 2: набор операторов; break; case значение З: набор операторов; break; default : набор операторов; break; } Пример: день недели Напишем программу, которая выводит день недели (на англий­ ском языке) в соответствии с введенным числом если введен неверный день . Примеры ввода и вывода Ввод Вывод 1 7 -1 Monday Sunday Error Решение let5 num = Number(argl); switch (num) { case 1: console. l og("Monday"); break; (1 ... 7) или «Error»,
Глава 170 4.1. Более сложные проверки case 2: console . log("Tuesday"); break; case 7: console.log("Sunday"); break; default: console . log("Error"); break; } Хорошей практикой является размещение тех меток case, кото­ рые обрабатъmают наиболее часто встречающиеся ситуации, первыми, а выражения case, которые обрабатьmают менее часто встречающиеся ситуации, оставляйте в конце, перед выражени­ defaul t. Еще одна хорошая практика - располагать метки case в порядке возрастания, независимо от того, являются ли они ем целочисленными или символьными. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#8. Несколько операторов в В switch-case JavaScript у нас есть возможность использовать несколько опе­ раторов case, когда им нужно выполнить один и тот же код. При таком способе записи, когда наша программа найдет совпадение, она вьmолнит следующий встретившийся код, поскольку после со­ ответствующей метки break: switch (selector) { case значение 1: case значение 2: case значение З: код; break; case значение 4: case значение 5: код; break; default: код; break; } case нет кода для выполнения и оператора
Что мы узнали из этой главы? 171 Пример: вид животного Напишите программу, которая выводит класс животного в соот­ ветствии с его названием: • • dog - > mammal (собака-> млекопитающее) crocodile, tortoise, sпake-> reptile (крокодил , черепаха , змея-> рептилия) • others -> uпkпоwп (другие-> неизвестный вид) Примеры ввода и вывода Ввод вывод tortoise reptile Ввод Вывод Ввод dog mammal elephaпt 1 вывод uпkпоwп Решение Мы можем решить эту задачу с помощью конструкции switch- case с несколькими метками следующим образом: swit ch (animal) { case "dog": console.log(''mammal''); break; case ''crocodile'': case ''tortoise'': case "snake": coпsole.log(''reptile''); break; default: console.log(''unknown''); break; Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#9. Что мы узнали из этой главы? Вспомним новые конструкции и приемы программирования, которые мы изучили в этой главе.
Глава 172 4.1. Более сложные проверки Вложенные проверки if ( условиеl) if { (условие2) // набор } el se { // набор { операторов; операторов; } } Более сложнъ1е проверки с помощью if ((х === left 11 console . log( ... ); Конструкция х === right) && у>= &&, top && 11, ! и О у<= bottom) switch-case switch (selector) { case значение 1: конструкци я; break; case значение 2: case значение 3: конструкц и я; break; default: конструкция ; break; } Упражнения: более сложные проверки Теперь давайте потренируемся работать с боле е сложными про­ верками. Решим несколько практических задач. В кинозале кресла расположены в форме прямоугольника с ко­ личеством r рядов и с мест в ряду. Существует три типа киносеан­ сов с билетами разной стоимости: • Premiere (премьера) - премьерный показ, цена 12.00 BGN.
Упражнения : более сложные проверки 173 Norrnal (обычный) - стандартный показ, цена 7.50 BGN. Discount (скидка)- показ для детей, школьников и студен­ тов по льготной цене 5.00 BGN. • • Напишите пр ограмму, которая принима ет на вход тип показа (строка), количество рядов и количество мест в ряду (целые чис­ ла) и вычисляет общий доход от билетов при полном зале. Результат должен быть выведен в том же формате, что и в примерах ниже - с округлением до двух цифр после десятичной точки. Примеры ввода и вывода Ввод Premiere 10 12 вывод 1440 . 00 1 Ввод Normal 21 13 вывод 2047 . 50 1 Рекомендации и советы При считывании входных данных мы можем конвертировать стр оки в нижний регистр (с помощью метода . toLowerCase( )). Мы создаем и инициализируем переменную, в которой будет хранить­ ся рассчитанная нами выручка . В другой переменной мы вычис­ ляем полную вместимость зала. Используем конструкцию case, switch- чтобы р ассчитать выручку в зависимости от типа показа и вывести результат в консоль в заданном формате (ищите нуж­ ный функционал JavaScript в интернете). Пример кода (части кода размыты, чтобы стимулировать само­ стоятельное мышление): l et projection l e t r ows = l et col umns l et full = let income = a r gl .to l owerCase () ; = = swi t ch ( projection ) {
Глава 174 4.1. Более сложные проверки case " premiere" : income = br eak ; } ); con s ole.log ( Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#10. Задача:волейбол Влад - студент, живет в Софии и иногда ездит в свой родной го­ род. Он очень любит волейбол, но в будние дни занят и играет толь­ ко по вь~ходньIМ и праздникам. Влад играет в Софии каждую субботу, когда он не на работе и не ездит в родной город, а также в 2/3 празд­ ничнь~х дней. Раз в год он ездит в свой родной город, где по воскре­ сеньям играет в волейбол со своими старьIМИ друзьями. Влад не бы­ вает на работе 3/4 вь~ходнь~х, когда он находится в городе. Отдельно отметим, что в високосные годы Влад играет в во­ лейбол на 15 % больше, чем обычно. Предполагается, что в году есть ровно 48 выходных дней, подходящих для игры в волейбол. Напишите программу, которая вычисляет, сколько раз Влад играл в волейбол в течение года. Результат округлите до ближай­ шего целого числа (например, 2.15 -> 2; 9.95 -> 9). Входные данные: • Первая строка содержит слово или • «leap» (високосный год) «normal» (обычный год с 365 днями). Вторая строка содержит целое число р - количество празд­ ничнь~х дней в году (которые не являются субботой или вос­ кресеньем).
Упражнения : бол ее сложные проверки • 175 Третья строка содержит целое число h- количество выход­ ных, когда Влад ездит в свой родной город. Примеры ввода и вывода Ввод Вывод leap 45 Ввод Вывод 11 Вывод normal 5 2 normal Ввод 3 38 2 1 Ввод Вывод leap 44 41 0 1 6 Рекомендации и подсказки По умолчанию мы считыва ем данны е из консоли и, чтобы из­ бежать ошибок ввода, переводим текст в нижний регистр с по­ мощью метода . toLowerCase( ). Последовательно мы вычисляем выходные, проведенные в Софии, время игры в Софии и общее время игры. Наконец, мы проверяем, является ли год високос­ ным, производим дополнительные вычисления, если это необхо­ димо , и выводим результат в консоль, округлив его до ближайше­ го целого числа (ищите в Интернете класс JavaScript с подобной функциональностью). Пример кода (части кода размыты, чтобы стимулировать само стоятельное мышление и решение): let year = a r gl . t olo1-rerCase() ; let l1olidays = let weekendsHome = let s ofiaWee kends = let pl aySofia = let playTotal =
Глава 17 6 4.1. Бол ее слож н ые проверки ) { if ( playTotal = } else if ( pl ayTot al = ) { } console.log(playTotal); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#11. Задача* : принадлежность точки фигуре Фигура состоит из шести блоков размером h * h, расположенных так, о 4 2 6 • 10 как показано на рисунке . Левый нижний угол фигуры нахо­ дится в позиции {О, О}. Правый верх­ ,. 8 h 6 ~ • ,. ний угол фигуры находится в позиции {2*h, 4*h}. даны при На рисунке координаты 4 • h h = 2. Н апишите h V ~ 2 программу, принимает целое число динаты точки { х, • которая h и коор­ у} (целые числа) о h h и выводит, находится ли эта точка внутри фигуры фигуры (outside) или на одной из сторон фигуры Примеры ввода и вывода Ввод Вывод 2 outside 3 10 Ввод 2 3 1 1 Вывод inside h h (inside), (border). вне
Упражнения : более сложные проверки Ввод Вывод 2 2 2 Ввод вывод 2 6 0 border 177 border 1 Ввод Вывод 2 outside 0 Ввод вывод 15 13 outside 155 6 Ввод Вывод 15 29 Ввод Вывод 15 inside outside 37 18 37 1 Рекомендации и советь~ Примерная логика решения задачи (не единственно верная) : • Мы можем разделить фигуру на два прямоугольника с общей стороной (см. рисунок). • Точка является внешней по от­ о 2 одновременно находится вне обоих прямоугольников. • h :············: Rectangle2 : :' 8 : 6 1------1 ; ~ (h Rectanglel • ры 2 если она располо- угольников (без учета их сторон) или лежит на их общей стороне. ( h 4 о j h :·········· •........ ·•·········: . •• жена внутри одного из прямо- • • Точка находится внутри фигу­ (inside), 6 • 10 ношению кфигуре (оutsidе), если она 4 • • • • • • • • • ,1' • ] h ...._______ ., · ·,·······:·,········.·,·······~·~ h h h В пр отивном случае точка лежит на стороне прямоугольни­ ка (border).
Глава 178 4.1. Более сложные проверки Пример кода (части кода размыты, чтобы стимулировать само­ стоятельное мышление и решение): let h = let х = let у= let outRectanglel = let outRectangle2 = let inRectanglel = let inRectangle2 = let commonBorder = if ( ) { console.log(''outside'') } else if ( ) { console .log(''inside"); } else { console .log(''border''); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/931#12. Упражнение: графическое приложение с более сложными проверками В этой главе мы узнали, как можно создавать проверки с нетри­ виальными условиями. Теперь давайте применим эти знания, что­ бы создать нечто интересное: настольное приложение, визуализи­ рующее точку и прямоугольник. Это замечательная визуализация для одной из задач в упражнениях. Задача* : точка и прямоугольник - графическое (GUI) Задача состоит в том, чтобы р азработать графиче ское приложе­ ние (GШ) для визуализации точки и прямоугольника . Приложение должно выглядеть примерно так:
Упражнение: графическое приложение с более сложными проверками f i,Ф№@IN File Edll Vie-.v W1nd0\V 179 Help Recta11g!e Х 1: 1 Recншgle У 1: Rectangle Х2: 1 39 Rec1a11gle У2: 19 Poiot Х: 25 Роiш У: 10 ~ - - - - -' Oraw! 1 Starus: I.oside Элементы управления слева задают координаты двух углов пря­ моугольника (вещественные числа) и координаты точки. Приложе­ ние графически отображает прямоугольник и точку и показывает, находится ли точка внутри прямоугольника прямо­ угольника Прило­ (Outside) или на одной из его (Inside), вне сторон (Border). жение перемещает и масштабирует координаты прямоугольника и точки так, чтобы они были как можно больше, но помещались в окне предварительного просмотра в правой части приложения. Внимание : это приложение значительно сложнее предьщущих графических приложений, которые мы разрабатьmали до сих пор, поскольку требует использования функций рисования работы с (Canvas), HTML, JavaScript и GUI-фреймворка (Electron). Ниже приведены пошаговые инструкции по созданию приложения: 1. Сначала создадим отдельную папку для проекта нашего при­ ложения с подходящим именем, например «Point-in - Rectangle». Electron, рабочий фреймворк для создания графи­ ческих приложений (GUI) на JavaScript. Выполним следующую кон­ сольную команду (Command Prornpt / Bash): 2. Установим npm install -g electron 3. В папке проекта создайте JavaScript-фaйл с именем ma in. j s, на­ жав [Ctrl + N] в VS Code. Затем сохраните новый файл, набрав [Ctrl + Shi ft + S] и введя желаемое имя файла. 4. Код, описанный в файле main. j s, управляет событиями и соз­ дает новые окна в приложении. Он должен выглядеть следующим образом:
Глава 180 4.1. Более сложные проверки const path = require('path'); const url = require('url ' ); const { арр, BrowserWindow} = require('electron'); let win; function createWindow ( ) { win = new BrowserWindow({width: 750, height: 300, false}); win.loadURL(url.format({ pathname: path . join( dirname, 'index.html'), protocol: 'file: ' , slashes: true resizaЫe: }) win.on( ' closed', () => { win = null; }) ; } app . on('ready ' , createWindow); app . on('window-all - closed', ( ) => { app . quit(); }); app.on('activate', () => { if (win === null) { createWindow(); } }); 5. Создадим новый НТМL-файл с именем екта. Тег <ti tle> index. html в папке про­ является обязательным для каждого html-доку­ мента и определяет его заголовок. Введем его и напишем and Recta ngle»: <!DОСТУРЕ html> <html lang="en" > <head> <meta charset ="UTF-8"> <title> Point and Rectangle</tit le> </head> <body> </body> </html> «Point
Упражнение: графическое приложение с более сложными проверками Добавим следУЮщий код в тег 181 <title> в файле index . html: <script src="app.js" type="text/javascript"></script> <!DOCTYPE html> <html lang="en"> <head> <meta charset ="UTF-8 " > <title>Po i nt and Rectangle</title> <script s"c="app.js" t "e="text/javascript"></script> </head> <body> </body> </html> Так осуществляется связь между файлами (которые мы создадим позже). Тег <body> index. html и арр . js определяет тело html-до­ кумента. В нем мы пишем следУЮщий код: <body> <div style= ''float:left '' > <br / > <label>Rectangle Xl:</ label> <input id="rect-xl" type="number" /> <br / > <label>Rectangle Yl:</ label> <input id=''rect-yl '' type='' number'' /> <br / > <label>Rectangle X2:< / label> <input id="rect-x2 " type="number" /> <br / > <label>Rectangle Y2:</ label> <input id="rect - y2 " type="number" /> <br / > <label>Point X:</ label> <input id="point-x" type="number" /> <br / > <label>Point Y:</ label>
Глава 182 4.1. Более сложные проверки <input id="point-y" type="number" /> <br /> <input type="button" onclick="draw()" value="Draw!" /> <br /> <div id=''result''> <label>Status:</label> <span id="status"></span> </div> </div> <div style=''float:right''> <canvas style="border: 2рх solid orange;" id="a" width="400" height= "200"> Sorry, your browser does not support HTMLS Canvas. </canvas> </div> </ body> Для ввода координат прямоугольника и точки мы используем поля input типа Number, с тегами <label>. Для рисования геометри­ ческих фигур в приложении используется html-тer <canvas>: <div style="float:right"> <canvas st ::.e="border: 2рх solid O orange;" iri="a" • idth ="400" eig'1t ="200"> This text is displayed if your browser does not s upport HTfvlLS Canvas . </canvas> </ div> Принимаются следУЮщие параметры: • • • Ширина Длинна (width) в пикселях ( рх) (height) в пикселях (рх) Граница (border) Чтобы отразить изменения в приложении, файлы необходимо сохранить с помощью [Ctrl + S]. Чтобы запустить приложение, выполните следУЮщую команду в консоли (в текущей папке проекта): electron .
Упражнение: графическое приложение с более сложными проверками 183 Приложение должно выглядеть следующим образом: 8 A:>int ,n Rectanglc F,le Ed1t v,,,... Recta11gle Х 1: Rectangle У 1: Rectangle Х2: Rectang!e У2: Poi11t Х: Х - W1ndO\V Help --------1 --------1 - -------,-1 Point У: ' 6. J Осталось реализовать самую сложную часть: визуализацию прямоугольника функции draw() и точки в в файле поле app.js, элемента с помощью который мы создаем в каталоге приложения, как описано в пункте Мы создаем объект <canvas> 2. CanvasRenderingContext2D, написав следую- щий код: / / Создание элемента canvas let canvas = document.getElementByid('a'); let context = canvas.getContext('2d'); J Элемент ся объект, <canvas> представляет собой поле, в которое помещает­ сгенерированный функцией . getcontext ( '2d · ), рисует графику, текст, изображения и дРуrие элементы. В данном случае переменная context представляет этот объект. Координаты двух углов прямоугольника мы сохраняем в отдельных переменных: / / Получение входных данных координат прямоугольника let rectXl = Number(document . getElementByid('' rect -xl'').value) let rectYl = Number(document . getElementByid(''rect-yl'').value) let rectX2 = Number(document.getElementByid(''rect-x2'').value) let rectY2 = Number(document.getElementByid(''rect-y2'').value) * 10; * 10; * 10; * 10; Значения координат доступны через id полей <input>. Для луч­ шей визуализации на экране мы масштабируем значения в 10 раз. Следующим шагом будет вычисление сторон прямоугольника, по-
Глава 184 скольку context 4.1. Более сложные проверки рисует прямоугольник по четырем параметрам: координата х, координата у, ширина в пикселях и длина в пик­ селях: // вычисление параметров прямоугольника let rect Wi dth = Math.abs(rectXl - rectX2); let rectHeight = Math.abs(rectYl - rectY2); Мы можем использовать приведенный ниже код, который рису­ ет красный прямоугольник в соответствии с координатами с помо­ щью метода . strokeRect( ...): // установка стиля прямоугольника context.strokeStyle = "#ff0000"; context.lineWidth = З; // отрисовка прямоугольника с заданными параметрами context.st rokeRect(rectXl, rect Yl, rectWidth, rectHeight); Как и в случае с прямоугольником, мы берем координаты точ­ ки и масштабируем их. Затем задаем стиль точки - оранжевый цвет. Для лучшей визуализации на экране мы преобразуем точку в окружность с помощью метода . arc( ... ) . Этот метод принимает пять параметров: х-координата, у-координата, радиус, начало дуги в радианах, конец дуги в радианах: // получение входных данных для координат точек let pointX = Number(document.getElementByid("point-x").value) * 10; let pointY = Number(document.getElementByid("point-y").value) * 10; // установка с тил я точк и и отрисовка точки context.beginPath(); context.fillStyle = ''#ff cc00''; context.arc(pointX, pointY, 4, 0, 2 * Math . PI); context . close Path(); context.fill(); Что бы отразить результаты в конструкции i f, мы сохраняем сле­ дующие элементы html-кoдa в отдельных переменных: // // присвоен и е переменных и (<span id="status">) (<div id="result">) html - элемен тов
Упражнение: графическое приложение с более сложными проверками let result let output = = 185 document.getElementByid (''status''); document.getElementByid(''result''); Последний шаг - проверка положения точки относительно пря­ моугольника: // проверка положения точки if о { result.innerHTML = "Inside"; output.style.backgroundColor = ''palegreen''; } else if О { result.innerHTML = "Border"; output.style.backgroundColor = ''gold''; } else { result.innerHTML = "Outside"; output.style.backgroundColor = ''lightsalmon''; } Давайте подумаем, как завершить незаконченные (намерен­ но) условия в конструкциях if. Приведенный выше код намерен­ но не компилируется, поскольку его цель - заставить читателя задуматься о том как и почему он не работает, и заполнить недо­ стающие части. Приведенный выше код берет координаты прямо­ угольника и точки и проверяет, находится ли точка внутри, сна­ ружи или на одной из сторон прямоугольника. При отображении результата цвет фона содержащего его текстового блока также из­ меняется. Это полная версия функции draw ( ): function draw() { // создание элемента canvas let canvas = document.getElementByid('a'); let context = canvas.getContext('2d'); // очистка окна canvas context . clearRect(0, 0, canvas . width, canvas.height); // получение входных данных для координат прямоугольника let rectXl = Number(document.getElementByid("rect-xl"). value) * 10; let rect Yl = Number(document.getElementByid("rect-yl"). value) * 10; let rectX2 = Number(document.getElementByid("rect-x2"). value) * 10;
186 Глава 4.1. Более сложные проверки let rectY2 = Number(document . getElementByid( "rect-y2'') . value) * 10; // вычисление параметров прямоугольника let rectWidth = Math.abs(rectXl - rectX2); let rectHeight = Math.abs(rect Yl - rectY2); // установка стиля прямоугольника context.strokeStyl e = "#ff0000"; context.lineWidth = З; // отрисовка прямоугольника с заданными параметрами context.strokeRect(rectX1, rectY1,rectWidth,rectHeight); // получен ие входных данных для координат точки let pointX = Number(document . getElementByid("point-x'') . value) * 10; let point Y = Number(document . getElementByid( "point-y'') . value) * 10; // установка стиля и отри совка точки cont ext.beginPat h(); cont ext.fillStyle = "#ffcc00"; cont ext.arc(pointX, pointY, 4, 0, 2 * Math.PI); context.closePath(); context.fill(); // присвоение переменных (div id=''result'') // и (span id="status") html-элементов let result = document.getElementByid(''status''); let output = document.getElementByid(''result''); // проверка положения точки if (pointX > rectXl && pointX < rectX2 && pointY > rectYl && pointY < rectY2) { result . innerHTML = "Inside"; output . style . backgroundColor = ''palegreen'' ; } else if ( (pointX === rectXl 11 pointX === rectX2) && pointY >= rectYl && pointY <= rectY2 11 (pointY === rectYl 11 pointY === rect Y2) && poi nt X >= rectXl && pointX <= rectX2) { result.innerHTML = "Border"; out put.style.backgroundCol or = ''gold'';
Упражнение: графическое приложение с более сложными проверками 187 } else { result . innerHTML = "Outside"; output . style.backgroundColor = ''lightsalmon''; } } Мы запускаем приложение с помощью файла index. html и тести­ руем его (вводя различные данные). Мы пробуем вводить разные прямоугольники и позиционировать точку в разных местах, изме­ няем размер приложения и смотрим, правильно ли оно себя ведет. Если приложение работает некорректно, проверяем его на нали­ чие ошибок. Наиболее вероятная причина ошибки - если мы на­ писали код не в том месте. Наконец, мы запускаем приложение в его собственном GUI-oкнe: electron . 1. Точка расположена в прямоугольнике: Случай 8 Po,nt ,n Rectangle F,le Ed1t View WindO\V - Х Help RectaugJe XI: 1 ---------1 Rec1a11gle У 1: 1 ---------< Rectangle Х2: 39 '----------1 Rectangle У2: 19 PointX: ~ P oin t Y: 10 --------- Drawl Status: Inside 2. Точка лежит на одной из сторон прямоугольника: Случай 8 Potnt ,n Re<".angle File Edit - Х Vie,v \'Jindo,v Help Rec1a1tgle Х 1: 1 R ec1angle У 1: 1 -----Recta1tgle Х2: 39 Rec1a11gle У2: 15 Point Х: 25 Point У: 15 ------ ------ ------ Drawl Status: Border -----------·:· - -----.
Глава 188 Случай 8 4.1. Более сложные проверки 3. Точка лежит вне прямоугольника: Po1n1 ,n Rectangle File Edit View - Х WindO\V Help Recran2le Х l : 24 Rec1an;le Y l : 1,... ~ _ _ _ _ ___, Recran2le Х2 : 39 Recran;le У2: Роiш Х : 11-18-----~J ______ 15 ..., Poi111 У: 8 Draw! '=-....,._ _ _ _ _ __, 1 ~tan1s: Outside - - - - - ~ Если у вас возникли трудности с последней задачей, попросите совета на форуме SoftUni: https://softuni.bg/forum.
Глава 4.2. Более сложные проверки - экзаменационные задачи В предыдущей главе мы узнали о вложенных условных операто­ рах в JavaScript. С их помощью логику программирования в програм­ ме можно представить в виде операторов i f, которые содержатся друг в друге. Мы также рассмотрели условный оператор switch-case, который позволяет выбирать из списка возможных вариантов. Да­ лее мы отработаем и закрепим полученные знания, рассмотрев не­ сколько более сложных задач, которые даются на экзаменах. Прежде чем перейти к решеюпо задач, вспомним условные операторы. Вложенные проверки if (условиеl) if { (условие2) // набор } else { // набор { команд; команд; } } Вложенные i f-конструкции - это проверка с помощью три нее еще одна проверка с помощью i f и вну­ i f. Помните, что не стоит писать глубоко вложенные условные опера­ торы (с уровнем вложенности больше трех). Избегайте вложения более трех условных операторов друг в друга. Это усложняет код и делает его более трудным для чтения и понимания. Switch-case проверки Когда работа программы зависит от значения одной перемен­ ной, вместо последовательных проверок с помощью нескольких
Глава 190 блоков if-else 4.2. Более сложные проверки - экзаменационные задачи можно использовать условный оператор switch- case. switch (selector) { case значениеl: набор операторов; break; case значение2: набор операторов; break; default: набор операторов; break; } Конструкция состоит из: • Селектора - выражения, результатом которого является определенное значение. • Множественных меток case с блоками кода после них, за­ канчивающихся ключевым словом break. Экзаменационные задачи Теперь, когда мы вспомнили, как используются условные опера­ торы и как условные операторы вложены дµуг в дµуга для реализа­ ции более сложных проверок и логики программы, давайте решим несколько экзаменационных задач. Задача: успеть на экзамен Студент должен прийти на экзамен в определенное время (на­ пример в 9:30). Он заходит в экзаменационную ное время (например в 9:40). аудиторию в задан­ Студент считается пришедшим вовремя, если он пришел к момен­ ту начала экзамена или не более чем за полчаса до него. Если он при­ шел раньше более чем на 30 минут, то он пришел слишком рано. Если студент пришел после времени начала экзамена, то он опоздал. Напишите программу, которая принимает время экзамена и вре­ мя прихода студента и выводит, пришел ли студент вовремя, опоз-
Задача: успеть на экзамен 191 дал ли он или пришел слишком рано, на сколько часов или минут опоздал или пришел слишком рано. Входнъ1е данные Программа принимает четыре целых числа (аргумента): • Первая строка (аргумент) содержит час начала экзамена целое число от О до • - целое число от О до 59. Третья строка (аргумент) содержит час прибытия студента на экзамен - • 23. Вторая строка (аргумент) содержит минуту начала экзаме­ на • - целое число от О до 23. Четвертая строка (аргумент) содержит минуту прибытия студента на экзамен - целое число от О до 59. Вывод даннъ~х В первой строке выведите: • «Late» («Опоздание»), если студент прибыл позже времени начала экзамена. • • «Оп time» («Вовремя») - если студент прибыл точно к на­ чалу экзамена или менее чем на 30 минут раньше. «Early» ( «Сл ишком рано»), если за 30 минуr до начала экзамена. студент прибыл более чем Если студент прибыл с разницей более чем в одну минуrу по сравнению с временем начала экзамена, выведите в следую­ щей строке: • («З а мм минут до начала») «mm minutes before the start» в случае прибытия менее чем за час до начала. • «hh:mm hours before t he start» («чч:мм часов до начала ») для прибытия за 1 час или раньше. Всегда выводите мину­ ты, используя две цифры, например • «mm miпutes after the start» «1: 05». («мм минут после начала») в случае прибытия с опозданием менее чем на час. • «hh:mm hours after the start» («чч:мм часов после начала») для опоздавших на 1 час и более. Всегда выводите минуты, используя две цифры, например «1: 03».
Глава 192 4.2. Более сложные проверки - экзаменационные задачи Примеры ввода и вывода Ввод Вывод Ввод 16 00 15 00 9 30 Late 20 minutes after the start 9 1s0 1:•од Ввод time 30 minutes before the start Оп 00 8 130 1 Вывод Ввод 14 00 13 1 Вывод time 5 minutes before the start 155 Early 1:00 hours before the start вывод 9 00 10 30 Ввод Оп Вывод 10 00 10 00 Late 1:30 hours after the start Вывод Оп time Рекомендации и подсказки Прежде чем приступить к написанию кода, рекомендуется не­ сколько раз прочитать задание задачи, делая заметки и прораба­ тывая примеры по мере их обдумывания. Обработка входных данных Согласно заданию, нам должны быть заданы четыр е параметра с разными целыми числами. Посмотрев на заданные параметры, мы можем выбр ать тип Number, так как он удовлетворяет нашим ожидаемым значениям. Мы считываем входные параметры и фор­ матируем текстовые значения в выбранный нами целочисленный тип данных: let let let let examHours = Number (argl) ; examMi nutes = Number (arg2) , arrivalHours = Number (arg3) ; arrivalMinutes = Number (arg4) ,
Задача: успеть на экзамен 193 Посмотрев на ожидаемый вывод, мы можем создать перемен­ ные, содержащие различные типы вьmода, чтобы избежать ис­ пользов ания так называемых магических строк в коде: let late = "Late"; let oпTime = "Оп time"; let early = "Early"; Вычисления Приняв входные данные, мы можем начать записывать логику вычисления результата. Сначала рассчитаем время начала экзаме­ на в минутах, чтобы было проще сравнивать: let examTime = (examHours * 60) + examMiпutes; Затем рассчитаем время прибытия студента, используя ту же ло­ гику: let arrivalTime = (arriva l Hours * 60) + arrivalMiпutes; Осталось вычислить разницу между временем начала экзамена и временем прибытия студента, чтобы определить, когда и в какое время по отношению к экзамену пришел студент: let totalMinutesDifference = arrivalTime - examTime; Следующим шаrом мы провододим необходимые проверки и вы­ числения и, наконец, выводим результат. Давайте разделим резуль­ тат на две части. • Сначала покажем, когда пришел студент - опоздал ли он, пришел вовремя или рано. Для этого воспользуемся конструкцией • i f-else. Затем мы покажем разницу во времени, если студент пришел не в то время, в которое начался экзамен. Чтобы не делать лишнюю проверку (else), мы можем по умолча­ нию предположить, что студент опоздал. Затем, в соответствии с условием, мы проверяем, ет ли разница во времени более 30 составля­ минут. Если да, то считаем, что он явился рано. Если мы не вводим первое условие, то нам нуж­ но только проверить, меньше или равна ли разница нулю (<= О), что проверяет условие, что студент явился вовремя между О и 30 минутами до экзамена.
Глава 194 4.2. Более сложные проверки - экзаменационные задачи Во всех остальных случаях мы предполагаем, что студент опоз­ дал, что мы и сделали по умолчанию, и дальнейшая проверка не требуется: let studentArrival = late; if (totalMinutesDifference < -30) { studentArrival = early; } else if (totalMinutesDifference <= 0) { studentArrival = onTime; } В качестве последнего пункта нам нужно выяснить и показать, с какой разницей во времени студент прибыл на экзамен, и указы­ вает ли эта разница на время до или после начала экзамена. Мы проверяем, больше ли наша разница одного часа, чтобы по­ казать часы и минуты соответственно в формате, требуемом за­ данием, или меньше одного часа, чтобы показать только минуты в формате и описании. Осталось проверить еще один момент - время прибытия сту­ дента до или после начала экзамена: let result = ''''; if (totalMinutesDifference != 0) { let hoursDifference = Math.abs(~~(tot alMinutesDifference / 60)); let minutesDifference = Math.abs(tot alMinutesDifference % 60) , if (hoursDifference > 0) { result = hoursDifference + ":" + (minutesDifference > 9 ? minutesDifference : ''0'' + minutesDifference) + " hours"; } else { result = minutesDifference + "minutes"; } if (totalMinutesDifference < 0) { result +=" before the start"; } else {
Задача: путешествие 195 result +=" after the start"; } } Вывод результата Наконец, нам нужно вывести результат в консоль. По заданию, если студент пришел точно по расписанию (без единой минуты раз­ ницы), нам не нужно выводить второй результат. Поэтому мы дела­ ем следующую проверку: console.log (studentArrival) , if (result) { console . log (result) ; } На самом деле для целей данной задачи вывод результата на экран может быть осуществлен на более раннем этапе - во вре­ мя самих вычислений. Однако в общем случае это не очень хоро­ шая практика. Почему? Давайте ит не из 10 рассмотрим строк, а из вариант 100 или того, 1000! что наш код состо­ Когда-нибудь вывод нуж­ но будет делать не в консоль, а сохранять в файл или выводить в веб-приложении. В таком случае сколько мест в коде придет­ ся корректировать в связи с этим изменением? И не пропустим ли мы что-либо? Всегда думайте о коде с логическими вычислениями как об от­ дельной части, отличной от обработки ввода и вывода. Он должен работать независимо от того, как в него подаются данные и куда нужно вывести результат. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/932#0. Задача: путешествие Как ни странно, большинство людей планируют свой отпуск за­ ранее. У молодого болгарского программиста есть определенный бюджет и свободное время в определенный сезон.
4.2. Глава 196 Более сложные проверки - экзаменационные задачи Напишите программу, которая принимает такие данные как бюд­ жет и сезон и вьmодит, где программист будет отдыхать и сколько он потратит. Бюджет определяет место отдыха, а сезон - то, на что будет по­ трачен бюджет. Если сезон летний, программист отправится в кем­ пинг, если зимний - остановится в отеле. Если речь идет о Европе, независимо от сезона, программист остановится в отеле. Каждый кемпинг или отель, в зависимости от места отдыха, имеет свою цену, которая соответствует определенному проценту от бюджета: • • • Если 100 BGN или меньше - 30 % бюджета. о Лето о Зима - Если 1000 70 % бюджета. BGN или меньше - где-то на Балканах. - 40 % бюджета. о Лето о Зима - Если более о где-то в Болгарии. 80 % бюджета. 1000 BGN - где-то в Европе . На путешествие по Европе, независимо от сезона, про­ граммист потратит 90 % бюджета. Входнъ1е и выходнъ1е да1П1Ъ1е Входные данные считываются из консоли и состоят из двух строк. • В первой строке указывается бюджет ло в диапазоне • [ 10. 00 - вещественное чис­ ... s000. 00]. Во второй строке указано одно из двух возможных времен года: summer («лето») или winter («зима»). Выходнъ1е да1П1Ъ1е В консоль должны быть выведены две строки. • В первой строке- « Где-то {место отдыха}» из «в Болгарии », «на Балканах» и « в Европе». • Во второй строке средств}». - « {Тип отпуска} - {Сумма потраченных
Задача: путешествие 197 о Отпуск может принимать значение «Кемп и нг» или «Отель». о Сумма должна быть округлена до второй цифры после десятичной точки. Примеры ввода и вывода Ввод Вывод 50 Somewhere in Bulgaria summer Camp - 15.00 Ввод Вывод 75 Somewhere in Bulgari a winter Hotel - 52 . 50 Ввод Вывод 312 Somewhere in Balkans summer Camp - 124 . 80 Ввод Вывод 1500 Somewhere in Europe summer Hotel - 1350 .00 Рекомендации и советы Обычно, как и в случае с другими задачами, мы можем разделить решение на несколько частей: • Считывание входных данных • Расчеты • Вывод р езультата Обработка входных данных Внимательно читая условие, мы понимаем, что мых данных ожидаем два аргумента. Первый аргумент от вводи­ - это ве­ щественное число, для которого нужно выбр ать соответствую­ щий тип пер еменной. Для точности вычислений мы выберем тип Number для бюджета и String для сезона.
Глава 198 4.2. Более сложные проверки - экзаменационные задачи let budget = Number(argl); let season = arg2 . tolowerCase (); l Всегда учитывайте, какой тип значения передается во входных данных, а также то, в какой тип эти данные нужно преобразовать, чтобы созданный вами программный код работал корректно! Вычисления Давайте объявим переменные, необходимые для вычислений: let destinationResult = ''''; let holidayinformation = ""; let moneySpent = 0.00; По аналогии с примером в предыдущей задаче, мы можем ини­ циализировать переменные в зависимости от входных данных - для экономии дополнительной инициализации. Взглянув на условие задачи еще раз, мы замечаем, что базовое распределение того, где будет отдыхать студент, определяется вели­ чиной его бюджета, то есть наша базовая логика распадается на два случая: • • Если бюджет меньше заданного значения. Если он меньше другого значения или больше порогового значения. В зависимости от того, как мы выстроим нашу логическую схему (в каком порядке будем проводить сравнение с граничными значе­ ниями), у нас будет больше или меньше проверок в условиях. Поду­ майте, почему ! Далее нам нужно сделать проверку на значение представлен­ ного сезона. По нему мы определим, какой процент бюджета будет потрачен, и где будет отдыхать программист - в отеле или в кем­ пинге. Пример ОДНОГО из ВОЗМОЖНЬIХ подходов к решению: if (budget <= 100.00) { destinationResult = "Bulgaria"; if (season === "summer") { moneySpent = 0.30 * budget; holidayinformation = ''Camp - '' + moneySpent.toFixed(2);
Задача: путешествие 199 } else { moneySpent = 0.70 * budget; holidayinformation = Hotel + moneySpent.toFixed(2); 11 11 } else if (budget <= 1000.00) { destinationResult = Balkans if (season === summer") { moneySpent = 0. 40 * budget; holidayinformation = Camp + moneySpent.toFixed(2); } else { moneySpent = 0.80 * budget; holidayinformation = Hotel - "+ moneySpent.toFixed(2); 11 11 ; 11 11 11 11 } } else { destinationResult = Europe moneySpent = 0.90 * budget; holidayinformation = ''Hotel - '' + moneySpent.toFixed(2); 11 11 ; Мы также можем присвоить значение параметра, а затем вы­ полнить только одну проверку. Это экономит нам один логический шаг. Например, след-ующий блок: if (budget <= 100.00) { destinationResult = Bulgaria if (season === ''summer '') { moneySpent = 0.30 * budget; holidayinformation = Camp + moneySpent.toFixed(2); } else { moneySpent = 0.70 * budget; holidayinformation = Hotel + moneySpent .toFixed(2); 11 11 ; 11 11 11 11 } } можно сократить. И результат получится таким: destinationResult = Bulgaria moneySpent = 0.70 * budget; holidayinformation = "Hotel - "+ moneySpent . toFixed(2); 11 11 ;
200 Глава 4.2. Более сложные проверки - экзаменационные задачи if (season === "summer") { moneySpent = 0 . 30 * budget; holidayinformation = "Camp + moneySpent . toFixed ( 2) ; } Вывод результата Осталось вывести результат вычислений в консоль: console.log ("Somewhere in "+ destinationResult); console.log (holidayinformation); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/932#1. Задача: операции над числами Напишите программу, которая считывает два целых числа (Nl и N2) и оператор для выполнения над ними математической опе­ (+), вычитание (-), умноже­ (/) и деление по модулю (%). При сложении, вычи­ рации. Возможные операции: сложение ние (*), деление тании и умножении в консоль должны быть выведены результат и сведения о том, четное получилось число или нечетное. При про­ стом делении - только результат, а при делении по модулю - остаток. Обратите внимание, что делитель может быть равен нулю (= 0), а деление на ноль невозможно. В этом случае должно быть выведено специальное сообщение. Входнъ1е даннъ1е В функцию передается три аргумента: • Nl - целое число в диапазоне (0 ... 40 000]. • N2 - целое число в диапазоне (0 ... 40 000]. • Оператор - один символ из :«+ », « - »,« *»,«/ »,«% ». Вывод даIПiых Выведите в консоль одну строку: • Если операция является сложением, вычитанием или ум­ ножением:
Задача: операции над числами о • 201 «{Nl } {оператор} {N2} = {результат} - {even/odd}». Если опер ацией является деление : о «{Nl } / {N2} = {результат} » -результат округляется до вто ­ рого символа после десятичной точки. • Если опер ация является вычислением остатка от деления: о • «{Nl} % {N2} = {результат} ». В случае деления на О (ноль): о «Cannot divide {Nl} {Nl} на ноль»). zero» Ьу («Невозможно разделить Примеры ввода и вывода Ввод 10 1 - Вывод 10 - 1 = 9 - odd Ввод 7 3 Вывод 7 *3 = 21 - odd * Ввод 123 12 / Вывод 123 / 12 10.25 10 3 Вывод 10 % 3 = 1 % Ввод 10 12 = Ввод Вывод 10 + 12 = 22 - even + Ввод 112 0 / Вывод Cannot divide 112 Ьу zero Рекомендации и подсказки Задача несложная, но придется написать дов ольно много строк кода. Обработка входных данных Пр очитав условие, мы понимаем, что ожидаются три параметра, котор ая программа считает из консоли. Первые два параметра -
202 Глава 4.2. Более сложные проверки - экза менационные задачи целые числа (в диапазоне, который указан в условии), третий пара­ метр - знак операции: let Nl = Number (argl); let N2 = Number (arg2 ) ; let nOpe r ator = argЗ; Вычисления Давайте создадим и инициализируем переменные, необходи­ мые для логики и вычислений. В одной из них мы будем хранить результат вычислений, а другую будем использовать для финаль­ ного вывода программы: let result let output = 0.00; = '''' ; Внимательно прочитав условие, мы понимаем, что бывают слу­ чаи, когда нам не нужно производить никаких вычислений, а про­ сто вывести результат. Поэтому мы можем сначала проверить, равно ли второе число 0 (нулю) и является ли операция делением или делением по модулю (делением с остатком), а затем вывести специальное сообщение: if {N2 === output 0 = && (nOperator === "/" '' Cannot divide '' + Nl 11 + '' nOperator Ьу zero '' ; === "%" ) ) { } Давайте поместим результат в качестве значения при инициа­ лизации переменной output. Таким образом, нам потребуется вы­ полнить только одну проверку, и на основании ее мы поймем, нуж­ но ли изменить значение этой переменной. Из условия видно, что для сложения (+), вычитания (-) или ум­ ножения (*) ожидаемый вывод имеет одинаковую структуру, «{nl} {о ператор} {n2} = {результат} - {четное/нечетное} », а для деления(/) и вычисления остатка от деления (%) вывод имеет другую структуру: else if {nOperator === "/ ") { result = {Nl / N2) . toFixed{2 ) ; output = Nl +" "+ nOperator +" " + N2 +" = "+ result; } else if (nOperator === "%") { result = Nl % N2; output = Nl +" " + nOperator +" "+ N2 +" = "+ result; }
Задача: операции над числами 203 В конце нам остается написать проверки на сложение, вычита­ ние и умножение: else { if (nOperator === "+") { result = Nl + N2; } else if ( nOperator === "-") { result = Nl - N2; } else if (nOperator === "*") { result = Nl * N2; } output = Nl + " " + nOperator + " " - "+ (result % 2 == 0? "even" N2 + " = " "odd"); " + + result + } Для коротких и понятных проверок, как в приведенном выше примере для четных и нечетных чисел, можно использовать тер­ нарный оператор. Рассмотрим возможную проверку с тернарным оператором и без него. Без использования тернарного оператора код длиннее, но его легко читать: ... let numberis = " , if (result % 2 == 0) { numberis = "even"; } else { numberis = ''odd'' ; } При использовании тернарного оператора код получается на­ много короче, но может потребовать дополнительных усилий для чтения и понимания логики: let numberis = result % 2 == 0? ''even'' "odd"; вывод Наконец нам осталось вьmести результат вычислений в консоль: console.log(output); Проверка в системе Judge Проверьте свое решение: Index/932#2. https://judge.softuni.bg/Contests/Practice/
Глава 204 4.2. Более сложные проверки - экзаменационные задачи Задача: билеты на матчи Группа футбольных болельщиков решила купить билеты на Ев­ рокубок. Билеты продаются за болгарские левы (BGN) в двух цено­ вых категориях: • VIP - 499,99 BGN (болгарских левов) • Обычная (Norrnal) - 249,99 BGN (болгарских левов) У футбольных фанатов есть общий бюджет, и количество чело­ век в группе определяет, какой процент бюджета будет выделен на транспорт: • От 1 до 4 - 75 % бюджета • От 5 до 9 - 60 % бюджета • От 10 до 24 - 50 % бюджета • От 25 до 49 - 40 % бюджета • 50 и более - 25 % бюджета Наrшшите программу, которая вычисляет, смогут ли болельщи= ки купить билеты на выбранную категорию на оставшиеся деньги из своего бюджета и сколько денег у них останется на другие нужды. Входные данные Входные данные считываются из консоли и содержат три строки: • В первой стр оке указывается бюджет ло в диапазоне • Во второй вещественное чис­ [ 1 000 . 00 . . . 1 000 000 . 00 ]. строке указывается категория - «VIP» или « Обычная» . • В третьей строке указывается количество человек в груп­ пе - целое число в диапазоне [1 ... 200]. Выходные дан.ные Выведите в консоль в виде одной строки следующее сооб­ щение: • Если бюджет достаточен: о "Yes ! You have {N} leva left. " ("Да ! У вас осталось {N} лева"), - где N- количество оставшихся денег у группы.
Задача: билеты на матчи • 205 Если бюджет недостаточен: о "Not enough money ! You need денег ! В ам нужно {М} лева", - {М} leva . " где М - "Не хватает сумма, которой не хватает. Суммы должны быть отформатированы до второй цифры после десятичной точки . Примеры ввода и вывода Ввод Вывод Yes ! You 1000 have Normal 0.01 leva left. 1 Ввод Поя с нение 1 человек: 75 % бюджета трат и тся н а транс­ 1000 - 750 = 250 . Normal: цена би лета сос тавляет 249.99 * 1 = 249.99 249.99 < 250: у болельщика ос т анется 250 - 249.99 = 0, 01 лева 1 порт . Оставшаяся сумма: Категория Вывод Пояснение 149 человек: 40 % бюджета 30000 VIP 49 Not enough money! You need 6499.51 leva 1 на тратится транспорт . 30000 - 12000 = 18000 . Категор и я VIP : б илет стоит 499.99*49. 24499.51 < 18000 : сумма недостаточна, т ребуется больше денег: 24499.51 118000 = 6499 . 51 Ос т авшаяся сумма : Рекомендации и советы Считаем входные данные и вьmолним расчеты, описанные в по ­ становке задачи, чтобы пров ерить, хватит ли денег футбольным фанатам. Обработка входных данных Давайте внимательно прочитаем условие задачи и разберемся, что мы должны принимать в качестве входных данных, что ожида­ ется вернуть в качестве результата, а также каковы основные шаги в решении задачи. Для начала обработаем и сохраним входные данные в соответствующих переменных: let budget = Number(argl) ; let ticketType = arg2; let people = Number(arg3) ;
206 Глава 4.2. Более сложные проверки - экзаменационные задачи Вычисления Затем мы создадим и инициализируем переменные, необходимые для вычислений: let t ransportCharges = 0.00; let moneyForTickets = 0.00; let moneyDifference = 0.00; Давайте еще раз рассмотрим условие. Нам необходимо организо­ вать два различных блока с вычислениями. Работа первого блока будет организована так, чтобы понять, какую часть бюджета болельщикам придется выделить на транспорт. Ло­ гика этих расчетов напрямую зависит от количества человек в груп­ пе. Поэтому выберем коэффJЩИент, отвечающий за траты бюджета на транспортные расходы в зависимости от количества болельщиков. Мы будем использовать условную конструкцию тельность блоков - последова­ i f-else: if (people <= 4) { transportCharges } else if (people <= transportCharges } else if (people <= transportCharges } else if (people <= transportCharges } else if (people >= transportCharges = 0.75 * budget; 9) { 0.60 24) { = 0.50 49) { = 0.40 50) { = 0.25 = * budget; * budget; * budget; * budget; } Результатом работы с расчетами второго блока должна стать сум­ ма денег, которая потребуется на покупку билетов для всей группы. Согласно условию, это зависит только от типа билетов, которые не­ обходимо приобрести футбольным фанатам. Воспользуемся условной конструкцией switch (ticketType) { case "Normal" : moneyForTickets break; case "VIP": moneyForTickets swi tch-case. = people * 249 . 99; = people * 499 . 99;
Задача: ГОСТИНИЧНЫЙ номер break; default: moneyForTickets break; 207 = people * 249.99; } После того как мы подсчитали, каковы транспортные и билет­ ные расходы, необходимо вычислить конечный результат и выяс­ нить, сможет ли группа болельщиков поехать на Еврокубок или нет при заданных параметрах. При выводе результата, для сокращения кода, мы изначально предположим, что группа болельщиков может позволить себе по­ ехать на Еврокубок: let result = ''Yes! You have '' + moneyDifference .toFixed(2) + "leva left."; if (moneyDifference < 0) { result = "Not enough money! You need" + Math.abs(moneyDifference).toFixed(2) + '' leva."; } Вывод Наконец нам осталось вьmести полученный результат в консоль. Проверка в системе Ju.dge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/932#3. Задача: гостиничный номер Отель предлагает два типа номеров: студия и апартаменты. Напишите программу, которая вычисляет цену за все время про­ живания для студии и апартаментов . Цены зависят от месяца про­ живания: Май и октябрь Студия 50 - 65 Студия 75.20 лв./ночь Апартаменты лв./ночь Июнь и сентябрь - - 68.70 Июль и август Студия лв./ночь Апартаменты 1 - лв./ночь 76 - лв. / ночь Апартаменты 77 лв. / ночь -
Глава 208 4.2. Более сложные проверки - экзаменационные задачи Также предлагаются следующие скидки: • При проживании в студии более скидка скидка • 14 суток в мае и октябре: 30 %. При проживании в студии более скидка суток в мае и октябре: 5 %. При проживании в студии более • 7 14 суток в июне и сентябре : 20 %. При проживании в апартаментах более • ничения месяца : скидка 14 суток, без огра­ 10 %. Входнъ1е даинъ1е Входные данные считываются из консоли и содержат две строки: • В первой строке указывается месяц - май, июнь, июль, август, сентябрь или октябрь. • Вторая строка пазоне - это время пребьmания, целое число в диа­ [0 ... 200]. Выходные даинъ1е В консоль выводятся следующие две строки: • В первой: • Boвтopoй: "Studio : {цена за все время проживания} "Apartment: { цена за все время проживания } lv . " lv . " Цена за все время пребывания должна быть отформатирована до двух символов после десятичной точки. Примеры ввода и вывода Ввод Мау 15 1 Вывод Apartment: 877.50 lv. Studio: 525.00 lv. Пояснения 14 ноче й мы снижаем 30 % (50 - 15 = 35), а на апартаменты - на 10 % (65 - 6,5 = 58,5). Весь срок проживания в апартаментах - 877,50 lv. Весь срок проживания в студии - 525,00 lv. В мае при проживании более цену на студию на
209 Задача: ГОСТИНИЧНЫЙ номер Ввод June 14 вывод Apartment: 961.80 lv . Studio: 1052.80 lv. Ввод вывод August Apartment: 1386 . 00 lv. 20 Studio: 1520.00 lv. Рекомендации и подсказки Считаем входные данные и выполним расчеты в соответствии с предоставленным прайс-листом и правилами скидок, а затем вы­ ведем результат. Обработка входных данных В соответствии с требованиями задачи считываем две строки входных данных: месяц, в котором планируется пребывание (пер­ вая строка), и количество ночей пребывания (вторая строка). Обработаем и сохраним входные данные в соответствующих пе­ ременных: let month = argl; let night s = Number(arg2); Вычисления Создайте и инициализируйте переменные, необходимые для вычислений: let let let let studioPrice = 50.00; apartmentPrice = 65.00; studioRent = 0.00; apartmentRent = 0.00; Перечитав условие еще раз, мы замечаем, что основная логика программы зависит от того, какой месяц нам дан, а также от коли­ чества ночей. Вообще говоря, существуют различные подходы и способы вы­ полнения рассматриваемых условий, но мы остановимся на базо­ вом условном операторе switch-case, а в р азличных блоках case бу­ дем использовать условные операторы if и if-else. Начнем с первой группы месяцев: май и октябрь. Для этих двух месяцев цена одинакова для обоих типов р азмещения - в студии или апартаментах. По этому для пересчета соответствующей цены (при необходимости) нам необходимо произвести внутреннюю проверку на количе ство ночей:
Глава 210 4.2. Более сложные проверки - экзаменационные задачи switch (month) { case "Мау": case "October": studioPrice = 50.00; apartmentPrice = 65 . 00; studioRent = studioPrice * nights; apartmentRent = apartmentPrice * nights; if (nights > 14) { studioRent *= 0.70; apartmentRent *= 0.90; } else if (nights > 7) { studioRent *= 0.95; } break; Для последующих месяцев логика и расчеты бу'f!УТ относительно идентичными: case "June" : case "September": studioPrice = 75 . 20; apartmentPrice = 68.70; studioRent = studioPrice * nights; apartmentRent = apartmentPrice * nights; if (nights > 14) { studioRent *= 0.80; apartmentRent *= 0.90; } break; case "July": case "August": studioPrice = 76.00; apartmentPrice = 77.00; studioRent = studioPrice * nights; apartmentRent = apartmentPrice * nights; if (nights > 14) { apartmentRent *= 0.90; } break;
Задача: ГОСТИНИЧНЫЙ номер 211 Рассчитав соответствующие цены и итоговую сумму за про­ живание, въmодим результат уже в округленном виде, предва­ рительно сохранив его в переменных для въmода и - studioinfo apartmentinfo: let studioinfo = "Studio: "+ studioRent.toFixed(2) +" lv."; let apartmentinfo = "Apartment : "+ apartmentRent.toFixed(2) + '' lv."; Для округления результата используем метод . toFixed(Number). Этот метод округляет дРОбное число до заданного количества цифр после десятичной точки. В нашем случае мы округлим дРОбное чис­ ло до двух чисел после десятичной точки. Вывод результата Наконец осталось только вьmести вычисленные результаты в консоль. Проверка в системе Judge Проверьте свое решение: Index/932#4. https://judge.softuni.bg/Contests/Practice/
Глава 5.1. Циклы В этой главе мы познакомимся с конструкциями для повторе­ ния группы инструкций, которые в программировании называют­ ся циклами. Мы напишем несколько циклов, используя оператор for в его классической форме. Наконец, мы решим несколько прак­ тических задач, требующих повторения последовательности дей­ ствий с использованием циклов. Повторяющиеся блоки кода (цикл for) В программировании нам часто требуется выполнить блок ко­ манд несколько раз . Для этого используются так называемые ци­ кльr. Давайте рассмотрим пример цикла тельно перебирает числа от for, который последова­ 1 до 10 и выводит их в консоль: for (let i = 1; i <= 10; i++) { console.log("i =" + i); } Цикл начинается с оператора и перебирает все значения пе­ for ременной в заданном интервале, например, все числа от 1 до 10 включительно, и для каждого значения выполняет последователь­ ность инструкций. На рисунке ниже показана структура цикла Оператор цикла for начальное значение ) f or: ,o,es,oe ] значен ие тело цикла: блок команд for ( l et i = 1; i console.log("i } <= 10; i++) { = "+ i); ~ -------~
Повторяющиеся блоки кода (цикл for) 213 В объявлении цикла можно указать начальное и конечное зна­ чения. Тело цикла обычно заключено в фигурные скобки { } и пред­ ставляет собой блок с одной или несколькими командами. 1 до n (например, от 1 до 10). Цель цикла - последовательно перебрать числа 1, 2, 3, ..., n и выполнить для каждого из них какое-либо действие. В приве­ денном примере переменная i принимает значения от 1 до 10, а те­ кущее значение выводится в теле цикла. Цикл повторяется 10 раз, В большинстве случаев цикл for работает от и каждое из этих повторений называется итерацией. Пример: числа от 1 до 100 Напишите программу, которая выводит числа от 1 до 100. Эта программа не принимает никаких входных данных и выводит чис­ ла от 1 до 100 одно за другим, по одному в строке. Рекомендации и советы Решить задачу можно с помощью цикла редаем переменной i числа от for, в который мы пе­ 1 до 100 и выводим их в теле цикла: function numbers1To100() { for (let i = 1; i <= 100; i++) { console.log(i); } } Запускаем программу с помощью 0v.;,u-;- [ Ct r 1 + F5] и проверяем: DEBUG CONSO'_E 89 90 91 92 93 94 95 96 97 98 99 100 Проверка в системе Judge Проверьте свое решение: Index/933#0. https://judge.softuni.bg/Contests/Practice/
Глава 214 Code snippet для цикла for в 5.1. Циклы Visual Studio Code При программировании нам постоянно приходится писать ци­ клы, десятки раз каждый день. Именно поэтому в большинстве сред разработки (IDE) есть фрагменты кода (code snippets), так назы­ ваемые шаблоны, для написания циклов. Одним из таких шабло­ нов является цикл Visual Studio Code. Введите for в редакторе кода JavaScript в Visual Studio Code и нажмите [ТаЬ] один раз: - for в for ~:::for For '..оор (javascrip,:) О [J for О foreac h [J fori n О forof VS Code развернет для вас шаблон и напишет полнь1й цикл for: for (let index = 0 ; index < a r ray.length ; index++) { const e l ement = array[index]; 1 } Попробуйте сами, чтобы овладеть навыком использования ша­ блона кода цикла for в Пример: числа до Visual Studio Code. 1000, заканчивающиеся на 7 Напишите программу, которая находит все числа в диапазоне [1 ... 1000], оканчивающиеся на 7. Рекомендации и подсказки Мы можем решить задачу, объединив цикл сел от 1 до 1000 и проверяя каждое число, for для перебор а чи­ оканчивается ли оно на 7. Конечно, есть и другие решения, но давайте решим задачу с помо­ щью цикла с проверкой: function numbersEndingin7{ ) { for (let i = 1; i <= 1000; i++) { if (i % 10 == 7) { // TODO: вывести i } } }
Code snippet для цикла for в Visual Studio Code 215 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#1. Пример: все латинские буквы Напишите программу, которая выводит на экран буквы латин­ ского алфавита: а, Ь, ..., z. Рекомендации и подсказки Мы можем решить задачу, используя цикл for, который после­ довательно перебирает коды всех букв латинского алфавита, пом­ ня, что код (порядковый номер в стандарте кодирования символов Unicode, если хотите узнать больше, вспомните свой навык поиска в интернете) буквы 'а' равен 97, код буквы 'Ь' равен 98 и так далее, а код буквы 'z' равен 122. Переход от номера буквы к самой букве осуществляется с помощью функции String.fromCharCode(x). Вот пример ее реализации: function latinletters () { for (let i = 97; i <= 122; i++) { console.log(String. fromCharCode(i)); } } Если мы хотим сделать код более читабельным, мы можем напи­ сать его следующим образом: function latinletters() { for (let ch = 'а' .charCodeAt(0); ch <= ' z' . charCodeAt(0); ch++) { console.log(String.fromCharCode(ch)) ; } } Таким образом, становится гораздо понятнее, через какие зна­ чения проходит цикл, и нет никаких магических чисел вроде и 97 122. Проверка в системе Judge Проверьте свое решение: Index/933#2. https://judge.softuni.bg/Contests/Practice/
Глава 216 5.1 . Циклы Пример: суммирование чисел Напишите программу, которая принимает n целых чисел и скла­ дывает их. • • В первой строке вводится количество чисел Начиная со следующей в остальных n n. строках вводится по одному числу. • Числа складываются, и в конце выводится результат. Примеры ввода и вывода Ввод Вывод Ввод 30 3 -10 -20 -30 2 10 20 вывод Ввод 4 45 -20 -60 1 1 999 Вывод Ввод Вывод 999 0 0 1 43 7 1 Ввод Вывод 11 1 Рекомендации и советы Задачу сложения можно решить следующим образом: • Считываем входное число • Начнем с того, что первоначально сумма • Запускаем цикл от ваем число • n. sum = 0. 1 до n. На каждом шаге цикла мы считы­ num и прибавляем его к сумме sum. Наконец, мы выводим на экран результирующее значение sum. Приведем исходный код решения: function sumNumbers (args) { let sum = 0;
Code snippet для цикла for в Visual Studio Code 217 for (let i = 1 ; i < args.length; i++) { sum += Number(args[i]); } console . log(sum); } Проверка в системе Judge Пр ов ерьте св ое решение : https://judge.softuni.bg/Contests/Practice/ Index/933#3. Пример: наибольшее число Напишите программу, которая принимает n целых чисел (n > 0) и находит среди них наибольше е. В перв ой строке вв ода вводится количество целых чисел n. Затем вводятся сами числа, по одному за раз. Примеры ввода и вывода Ввод Вывод Ввод 3 2 100 100 99 1 999 20 999 Ввод 2 -1 -2 Вывод 1 - 20 99 7 99 1 Вывод Ввод 4 45 1 -10 20 -30 1 Ввод Вывод 1 Вывод -1 Рекомендации и подсказки Сначала мы вводим одно чи сло n (количество чисел, котор ые нужно ввести). Мы устанавливаем текущий максимум чальное нейтральное значение, например max в на­ -10000000000000 (или Numbe r . NEGATIVE_INFINITY). Исп ользуя цикл for, который ите­ рируется n раз ( n = args[0]), мы считываем одно целое число num. Если считанное число num больше текущего максимума max, мы присваиваем зн ачение num пер еменной max. В конце цикла са-
Глава 218 мое большое число должно быть сохранено в Циклы 5.1. max. Мы выводим его в консоль. func t ion maxNumber(args) { let n = Number( args[0 ]); let max = N umber .N EGATIVE_INFINIТY; for (var i = 1; i <= n; i++) { let num = Number(args[i]); if (num > max) { max = num; } } console.log( 'max 1 = 11 + max); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#4. Пример: наименьшее число Напишите программу, которая принимает на вход n целых чисел (n > 0) и находит среди них наименьше е. Сначала введите количе­ ство чисел n, затем сами числа, по одному в строке. Пример ввода и вывода Ввод Вывод Ввод 99 3 -10 20 -30 2 100 99 Вывод Ввод Вывод 4 45 - 30 - 20 -20 7 99 Рекомендации и подсказки Задача полностью аналогична предыдущей, за исключением того, что мы начина ем с другого нейтрального начального зна­ чения:
Code snippet для цикла for в Visual Studio Code 219 function minNumber(args) { let n = Number(args [0)); let min = Number.POSITIVE_INFINITY; for (var i = 1; i <= n; i++) { let num = Number(args[i]); if (num < min) { min = num; } } console . log(min ) ; } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#5. Пример: сумма левого и правого Напишите программу, которая вводит 2 * n целых чисел и про­ веряет, равна ли сумма первых n чисел (левая сумма) сумме вто­ рых n чисел (правая сумма). Если равна, выведите иначе выведите «Yes» + сумма, «No» + разность. Разница вычисляется как положи­ тельное число (по абсолютной величине). Формат вывода должен быть таким, как в примерах ниже. Примеры ввода и вывода Ввод Вывод Ввод 2 вывод 2 10 90 60 40 Yes, sum 90 9 50 50 = 100 No, diff = 1 Рекомендации и подсказки Сначала введите число n, затем первые n чисел (левая полови­ на) и сложите их. Продолжите ввод еще n чисел (правая полови­ на) и найдите их сумму. Вычислите разность между найденными
220 Глава 5.1 . Циклы суммами по абсолютной величине: Если разница равна О, выведите Math. abs ( leftSum - rightSum). «Yes» + сумма, иначе - выведите «No» + разность: function leftRightSum(args) { let n = Number(args[0]); let leftSum = 0; let rightSum = 0; for (var i = 1; i <= n; i++) { leftSum += Number(args[i]); } //TODO: реализуйте цикл for и вычислите rightSum if (leftSum == rightSum) { console.log("Yes, sum = "+ leftSum); } else { console . log( "No, diff =" + Math.abs(leftSum - rightSum)); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#6. Пример: четная/нечетная сумма Напишите проrрамму, которая принимает на вход n целых чисел и проверяет, равна ли сумма чисел в четных позициях сумме чисел в нечетных позициях. Если равна, то проrрамма выводит сумма, если нет - «No» + разность. «Yes» + Разность вычисляется как абсо­ лютное значение . Формат вывода должен быть таким, как показано в примерах ниже. Примеры ввода и вывода Ввод Вывод 4 10 50 60 20 1 Yes Sum = 70 1 Ввод 4 3 5 1 -2 вывод Ввод вывод 3 5 8 1 No Diff = 1 1 1 No Diff = 2 1
Code snippet для цикла for в Visual Studio Code 221 Рекомендации и подсказки Введите числа по одному и вычислите две суммы (чисел в чет­ НЪIХ позициях и чисел в нечетнь~х позициях). Как и в пр едыдущей задаче, вычислите аб солютное значение разности и выв едите ре­ зультат («Yes» + сумма, если р азность р авна О, или «No» + разность в противном случае): function oddEvenSum(args) { let n = Number(args[0 ] ); let oddSum = 0; let evenSum = 0; for (var i = 1 ; i <= n; i++) { if (i % 2 == 0) { evenSum += Number(args[ i ]); } el se { oddSum += Number(args[i]); } } // TODO: вывести значение суммы/ разности } Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#7. Пример: суммирование гласных букв Напишите программу, которая принимает на вход текст (стро­ ку), вычисляет и выводит сумму значений гласных букв в соответ­ ствии с приведенной ниже таблицей: а 1 е i о u 2 3 4 5 Примеры ввода и вывода Ввод hello вывод (е+о = 6 2+4 = 6)
Глава 222 Ввод 5.1. Циклы Вывод 3 hi (i = 3) bamboo (а+о+о 9 = 1+4+4 = 9) 1 ' beer (е+е 4 = 2+2 = 4) 1 Рекомендац ии и подсказки Считайте входной текст argl, обнулите сумму и выполните цикл от 0 до input. length (длина текста). Мы проверяем каждую букву input [ i] на предмет того, является ли она гласной, и добавляем со­ ответствующее ей значение к сумме: function vowelSum([argl]){ let input = argl; let sum = 0; for (var i = 0; i < input.length; i++) { if(input[i] == ''а''){ sum += 1; } else if (input[i ] -sum += 2; ''е''){ } else if (input[i ] -- ''i''){ sum += 3; } else if (input[i] -sum += 4; ''о''){ } else if (input[i] -- ''u''){ sum += 5; } } console.log(sum); }
Что мы узнали из этой главы? 223 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#8. Что мы узнали из этой главы? Мы можем повторять блок кода с помощью цикла for: for (let i = 1; i <= 10; i++) { console.log(i); } Мы можем выполнять различные математические операции: function maxNumber(args) { let n = Number(args [0]); let max = Number. NEGATIVE INFINIТY; for (var i = 1; i <= n; i++) { let num = Number(args[i]); if (num > max) { max = num; } } console.log( "max =" + max) , } Упражнения: циклы Теперь, когда мы познакомились с циклами, пришло время при­ менить наши знания на практике, а для этого, как вы знаете, нужно написать много кода. Давайте решим несколько задач. Задача: элемент, равный сумме остальных Напишите программу, которая принимает на вход n целых чисел и проверяет, существует ли среди них число, равное сум­ ме всех остальных. Если такой элемент существует, выведите «Yes» + его значение, иначе выведите «No» + разность между наибольшим элементом и суммой остальных (в абсолютном значении).
Глава 224 5.1. Циклы Пример ввода и вывода Ввод Вывод Комментарий Yes 3 + 4 + 1 + 2 + 1 + 1 = 12 7 3 4 1 1 2 12 1 = 12 Sum Ввод Комментарий Вывод 3 1 1 No Diff =8 110 - ( 1 + 1)1 =8 10 Ввод Вывод Вывод No Diff = 1 Ввод Вывод 4 3 3 1 1 1 Ввод 5 5 1 No Diff = 1 6 1 2 3 Yes Sum = 6 Рекомендации и подсказки Нужно вычислить сумму всех элементов, найти наибольший из них и проверить условие. Проверка в системе Judge Проверьте свое решение: Index/933#9. https://judge.softuni.bg/Contests/Practice/
Упражнения : циклы 225 Задача: четные/нечетные позиции Напишите программу, которая считывает п чисел и вычисляет сумму, минимальное и максимальное значения среди чисел, нахо­ дящихся в четных и нечетных позициях (считая от 1). При отсут­ ствии минимального/максимального элемента выведите «No». Пример ввода и вывода Ввод вывод Ввод Вывод 2 1.5 -2.5 OddSum=l.5, OddMin=l.5, OddMax=l.5, EvenSum=-2.5, EvenMin=-2.5, EvenMax= -2.5 Ввод 6 2 3 5 4 2 1 Odd5um=9, OddMin=2, OddMax=S, EvenSum=8, EvenMin=l, EvenMax=4 Вывод 1 1 1 OddSum=l, OddMin=l, OddMax=l, Even5um=0, EvenMin=No, EvenMax=No 1 Ввод Вывод 3 -1 -2 -3 OddSum=-4, OddMin=-3, OddMax= -1, EvenSum=-2, EvenMin=-2, EvenMax=-2 Ввод вывод Ввод Вывод 1 -5 OddSum=-5, OddMin=-5, OddMax=- 5, Even5um=0, EvenMin=No, EvenMax=No 5 3 -2 8 11 -3 Odd5um=8, OddMin=-3, OddMax=8, Even5um=9, EvenMin=-2, EvenMax=ll 1 1 1 Рекомендации и подсказки Эта задача объединяет несколько предыдущих задач: нахожде­ ние минимума, максимума и суммы, а таюке обработку элементов на четных и нечетных позициях. Вспомните их. В этой задаче лучше работать с дробными числами (не с целы­ ми). Сумма, минимум и максимум таюке являются дробными чис­ лами. При нахождении минимума/максимума следует использо­ вать нейтральное начальное значение, -1000000000.0. Если то выведем «No». и например 1000000000.0 в конце мы получим нейтральное значение, Проверка в системе Judge Пр оверьте свое решение: Index/933#10. https://judge.softuni.bg/Contests/Practice/
226 Глава 5.1 . Циклы Задача: одинаковые пары Дано 2 тое - * n чисел. Первое и второе образуют пару, третье и четвер­ тоже, и так далее. Каждая пара имеет сумму составляющих ее чисел. Напишите программу, которая проверяет, все ли пары име­ ют одинаковую сумму. Если они одинаковы, то выведите «Yes, value= ... » + значение, в противном случае выведите максимальную разницу между дву­ мя последовательными парами в следующем формате - «No, maxdi ff= ... » + значение.На вход подается число n, за которым следу­ ют целые числа 2*n, по одному в строке. Примеры ввода и вывода Ввод Коментарий Вывод 1 2 -1 2 1 {1, -1} разница= {2} maxdiff=2 макс. -1 1 1 разница= Вывод 5 5 2 1 Yes, value=3 3 4 равные {3, 3, 3} значения -1 Ввод 2 1 2 2 2 Вывод No , maxdiff=l Коментарий {3, 4} разница= {1} суммы= макс. разница= 1 = {10} одно значение равная 1 Коментарий суммы= cyr-v"ы Yes, value=10 3 1 2 0 Коментарий Вывод 1 1 • Ввод 1 суммы= No, 0 Ввод сумма
Упражнения: графические и веб-приложения 227 Рекомендации и подсказки Мы считываем входные числа парами. Для каждой пары вычис­ ляем ее сумму. В процессе считывания входных пар для каждой пары, кроме первой, вычисляем разность по сравнению с предыду­ щей. Для этого необходимо хранить сумму предыдущей пары в от­ дельной переменной. Наконец, мы находим наибольшую разницу между двумя парами. Если она равна О, то выводим ние, если нет «Yes» + значе­ - «No» + разность. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/933#11. Упражнения: графические и веб-приложения В этой главе мы познакомились с циклами как конструкцией программирования, позволяющей многократно повторять дей­ ствие или группу действий. Теперь давайте «поиграем» с ними. Для этого мы нарисуем несколько фигур, состоящих из большого количества повторяющихся графических элементов, но на этот раз не в консоли, а в графической среде с использованием «чере­ пашьей графики». Это будет интересно. И совсем не сложно. По­ пробуйте! Задача: рисование с помощью черепашки - графическое приложение Цель следующего задания - (GUI) «поиграть» с библиотекой рисова­ ния, известной как «черепашья графика» (turtle graphics). Мы созда­ дим графическое приложение, в котором будем рисовать различ­ ные фигуры, перемещая нашу «черепашку» по экрану с помощью 100 позиций», «повернуть «пройти вперед еще на 50 позиций» . таких операций, как «пройти вперед на направо на 30 градусов», Давайте сначала познакомимся с концепцией рисования «чер е­ пашьей графики». Мы можем рассмотреть следующие источники: • Определение «чер епашьей графики» (концепция движе­ ния и вращения)- http://c2.com/cgi/wiki?TurtleGraphics
228 Глава • 5.1. Циклы Статья в Википедии о «черепашьей графике» (с большим количеством примеров интересной графики) - https:// en.wikipedia.org/wiki{Гurtle_graphics • Интерактивный онлайн-инструмент для «черепашьей гра­ фики»: https://Ьlockly-games.appspot. com/turtle Приложение будет выглядеть примерно так: '~ TurtleGraphics - Demo Reset Hide T urtle Hexagon Splral Sun Triangle Star Мы будем реализовывать приложение, используя следующие технологии: • Язык HTML - для описания пользовательского интерфейса (поля для рис ования и кнопки). • • JavaScript-кoд-для реализации действий с кнопками. JS-библиотека jQuery (https://jquery.com/) - для облегчения доступа к элементам пользовательского интерфейса. • JS-библиотека jQuery-ТUrtle jquery-turtle) - для р еализации рисования на экране с по­ (https://github.com/PencilCode/ мощью механики «черепашьей графики». У нас есть два варианта загрузки всех библиотек и ресурсов для нашего веб-приложения • Turtle Graphics: Загрузить ресурсы через CDN (Content Delivery Network). Этот вариант подходит, когда у нас есть постоянное подключе­ ние к Интернету. Нам нужно создать стандартный НТМL-файл (на­ пример, index. html) и написать в нем следующий код:
Упражнения: графические и веб-приложения 229 <! ООСТУРЕ html> <html> <head> <meta charset="UTF-8"> <title>TurtleGraphics - Demo</title> <link rel="stylesheet" type="text/css" href=''ht tps://cdn . rawgit . com/SoftUni/Programming-BasicsBook-JS-BG/39673828/assets/chapter-5-1-assets/style.css''> </head> <body> <div id=" mai n-frame"> <div id="header"> <img id="small-icon" class="title-box" src=''https://cdn.rawgit.com/SoftUni/Programming-Basics - Book - JS - BG/39673828/assets/chapter-5-1-assets/ turtle-icon . png'' alt="icon" /> <span class=''title-box''>TurtleGraphics - Demo</span> </div> <div id=''elements''> <button id="justDraw">Draw</button> <button id="reset">Reset </button> <button id="hide">Hide Turtle</button> <button id="drawHexagon">Hexagon</button> <button id="drawStar">Star</button> <button id="drawSpiral">Spiral</button> <button id="drawSun">Sun</button> <button id="drawTri angle">Triangle</button> <div id="turtle"></div> </div> </div> <script src="https://cdn.rawgit.com/SoftUni/Programming-Basics-BookJS-BG/39673828/assets/chapter-5-1-assets/jquery. js''></ script> <script src="htt ps://cdn.rawgit.com/SoftUni/Programming-Basics- Book JS - BG/39673828/assets/chapter-5- 1-assets/jquery-turtle. js"></script> <script> </script> </body> </html>
Глава 230 Все необходимые ресурсы будут загружены 5.1. Циклы автоматически при запуске файла, и мы сможем приступить к созданию нашего JavaScript-кoдa. Если по каким-то причинам у вас нет постоянного доступа к Ин­ тернету, можно воспользоваться вторым вариантом: • Локальная загрузка ресурсов. Здесь вам придется самостоятельно загрузить все необходимые файлы и изменить несколько строк в html-фaйлe . Для начала соз­ дайте папку Turtle-Demo, а в ней-основной html-фaйл (index.html) и папку для необходимых ресурсов: lib index.htm l В папку «liЬ» нужно сохранить несколько файлов, которые мы можем скачать в хранилище ресурсов этой книги: https:// githuЬ.com/SoftUni/Programming-Basics-Book-JS-BG/tree/rnaster/assets/ chapter-5-1-assets. Для вашего удобства мы также поместили файлы в удобный для скачивания архив Тurtle-Graphics-Demo-Files.zip: ~ Тurtle-Graphics-Der,o- Files.zip §) jquery-turtle.js ~ jquery.js ~ style.css ~ turtle-icon.png Давайте рассмотрим каждый из них: jquery.js (версия 2. 0.3) Одна из самых известных библиотек JavaScript, которая обеспе­ чивает скорость и функциональность при работе с пользователь­ скими интерфейсами на основе те: https://jquery.corn. HTML. Изучите инструмент на сай­
Упражнения : графические и веб-приложения jquery-turtle.js (версия 231 2.0.8) Плагин (подключаемый модуль), написанный Дэвидом Баугом для jQuery - jQuery-turtle, который предоставляет набор функций для рисования графики с помощью «черепашки» . ПодРобную ин­ формацию и руководство пользователя можно найти здесь: https:// github.com/davidhau/jquery-turtle. style.css Все инструкции по оформлению, которые вынесены в отдель­ ный файл. turtle - icon.png Растровая графика, которую мы используем для лучшего пред­ ставления приложения. После того как мы поместили файль1 в папку, нам нужно изменить сетевой адРес ресурсов в нашем НТМL-файле <!ООСТУРЕ html> <html> <head> <meta charset="UTF - 8 " > <title>Tu rtleGr·aphics - Demo< / title> <link rel ="stylesheet" type="text/css" </head> index . html: href="liЬ/style . css " > <body> <di v id=''main - frame"> <div id=''header"> <img id="small-icon" cla ss="title-box" src=" lib/turtle-icon . png" alt ="icon" /> <span class="title- box">TurtleGr aphics - Demo</span> </div> <div id=''elements''> <button id="justDraw">Dra1-1</button> <button id="reset''>Reset </button> <button id="hide">Hide Turtle</button> <button id="dra1-1Hexagon">Hexagon</button> <button i d =" draиSt ar">St ar </button> <button i d=" dra1,1Spira l" >Spiral </button> <button id="dra1,JSun" >Sun</butto n> <button id=" dra1•IТriangle" >Triangle</button> <div id="turtle" ></div> </div> </div>
Глава 232 5.1 . Циклы <scri pt src=" lib/jquery . js"></s cri pt> <scri pt src="lib/jquery-turtle . js"></scri pt> <script> </script> </body> </html > После этого изменения при каждом запуске файла наш браузер будет загружать файлы локально из папки «lib». Теперь мы можем перейти к самому интересному - написанию JavaScript-кoдa для веб-приложения. Он будет расположен между последней парой тегов script в приведенном выше НТМL-файле (index. html): <script> </script> Код с функциями приложения будет относительно коротким (около 70- 80 строк), поэтому нам не нужно выделять его в отдель­ ный файл. Важно лишь правильно расположить его в нашем НТМL-файле. Рекомендуется размещать весь код JavaScript в конце НТМL-доку­ мента, перед закрывающим тегом «body». Это гарантирует более быструю загрузку страницы, поскольку мы не замедляем рендеринr (обработку) ее элементов. Мы всегда размещаем сначала файл библиотеки тем файл с кодом плаrина [jquery-turtle.js]. [jquery . js], за­ Только после этого мы пишем наш код, потому что он о снован на первых двух фай­ лах. Если мы попытаемся поменять их местами, то получим ошиб­ ки и наше приложение не будет функционировать как запланиро­ вано. Библиотека «jQuery» позволяет нам манипулировать НТМL­ элементами с помощью корректных селекторов оформления CSS. При этом нам необходимо применять определенный синтаксис: $('#id ' ) ил и $(' .class') Мы можем использовать имя НТМL-элемента, ID или его класс. Селекторы всегда являются строками текста, поэтому они заключа­ ются в одинарные или двойные кавычки. Если селектор - это ID (уникальное имя для каждого элемента), то в начале ставится знак решетки (#). Если же мы решили использовать селектор по классу (одно имя для нескольких элементов), то ставим точку.
Упражнения: графические и веб-приложения 233 Придерживаясь документации по jQuery-turtle, нам нужно ини­ циализировать наш объект и задать основные «черепашьи» харак­ теристики. С помощью следующего кода мы определим размер гра­ фики (turtleScale) и скорость движения (turtleSpeed): eval($.turtle{)); $('#turtle').css('turtleScale', '2') . css('turtleSpeed', '4'); После того как мы закончили с основой нашего приложения, нам нужно написать функции для каждой кнопки. Для этого мы ис­ пользуем предопределенные селекторы объектов (ID) в html-фaйлe. Мы поделимся кодом для первых трех кнопок, чтобы вы могли оз­ накомиться с основами: • КНопка «Draw» Мы подключаем функцию к элементу с идентификатором (се­ лектором) justDraw, которая будет активирована в момент нажа­ тия на кнопку: ${'#justDraw').click(function() { cg(); for {let index 0; index < 4; index++) { ${'#turtle').pen('Ыue', '5') . lt{30).fd(150) .lt{120).fd{l50) . lt{120) .fd{150); = } }); Сначала мы удалим графику с помощью функции graphics) cg() (clear и построим элементарный цикл, который будет повто­ ряться четыре раза. Мы намеренно используем ключевое слово для определения переменной let index. Таким образом мы гарантиру­ ем автономность переменной для конкретного цикла и можем лег­ ко использовать то же имя снова. На каждой итерации (повторении) мы применяем определен­ ные методы для перемещения с определенным значением (пово­ рот влево и движение вперед): lt{30) // поворот влево {left) с аргументом 30 .fd{150) // движение вперед {forward) с аргументом 150
Глава 234 5.1 . Циклы Техника цепочки позволяет сэкономить место на написании до­ полнительного кода: $('#turtle') . pen('Ыue' , // '5') . lt(30).fd(150).lt(120) ... что является сокращенной версией классического метода: $('#turtle') . pen('Ыue', '5'); $( ' #t urt le').lt(30); $('#turtle').fd(150); $('#turtle').lt(120); $('#t urt le') . fd(150); • кнопка «Reset» Прикрепите к ID элемента (селектора) функцию «Reset», которая будет активироваться в момент нажатия: $('#reset').click(function() { window.location.reload(); }) ; Используя window. location. reload(), мы активируем пер еза­ грузку окна, которая сбрасыва ет текущее состояние окна. Важно от­ метить, что location метод location. кнопка • К элементу это свойство объекта window, а reload () - «Hide turtle» с идентификатором (селект ором) «hide» мы прикр епля ем функцию, которая актив ируется при нажатии на кнопку: $( ' #hide').click(funct ion() { $( ' #turtle').toggle(); $(this).text(function(i, text) { ret urn text === "Hide Turtle" ") "Show Turtle" : "Hide Turtle"; }); }); Мы используем готовую функцию из библиотеки toggle( ). jQuery - С ее помощью мы скрываем и показываем элементы. От-
Упражнения: графические и веб-приложения 235 дельно мы подключим еще одну функцию для изменения текста кнопки при нажатии. Нам необходимо использовать ключевое слово ет важную роль в синтаксисе ero менить то есть цию на self/itself. JavaScript, текста, Оно игра­ и мы можем мысленно за­ В данном случае оно равно элементу this = #hide. Мы ссылаемся на замены this. которая также hide, сам элемент и задаем функ­ активируется при нажатии на кнопку. Давайте подведем итоr написанному нами коду: <script> eval($. turtle()); $('#turtle').css('turtle5cale', '2').css('turtleSpeed', '4'); $('#reset') . click(function() { window.location.reload(); }); $('#justDraw').click(function() { cg(); for (let index ~ 0; index < 4; index++) { $('#turtle').pen('Ьlue', '5') .lt(30).fd(150) .lt(120).fd(150) . lt(120) .fd(150); } }); $('#hide') . click(function() { $('#turtle').toggle(); $(this).text(function(i, text) { return text === ''Hide Turtle'' ) ''Show Turtle'' Turtle"; ''Hide }); }); </script> Нам еще предстоит решить проблему с автоматическим удале­ нием поля рисования при нажатии новой кнопки. Мы не хотим ри­ совать фигуры дРуr над другом или каждый раз использовать кноп­ ку Reset.
Глава 236 • Функция 5.1 . Циклы resetCanvas () function resetCanvas () { cg(); home(); $('#turtle') . css (' turtleScale', '2') . css('turtleSpeed', '4' ); } Мы применим предопределенные функции из плагина Дэвида Бауrа для удаления всех элементов графа (cg()) и перемещения че­ (home () ). Затем мы снова устанав­ элемента turtle. Вся функция reset- репашки в исходное положение ливаем исходные настройки Canvas() добавляется в начало каждой новой функции, которую мы будем прикреплять к другим кнопкам. Пример: $( ' #drawSpiral') . cl ick(function() { resetCanvas (); $( ' #turtle').css('turtleSpeed', '4'); for (let index = 0; index < Х; index++) { // replace ''Х'' with ап appropriate number // some code you need to add } }) ; На свое усмотрение вы можете изменить скор о сть анима­ ции и цвет контура, добавив новые настройки непосредствен­ но в функцию click( ... ) и прикладную функцию для каждой кнопки: $( ' #turtle').css('turtleSpeed', '6').pen('red', '5 ' ); Задача*: нарисовать шестиугольник с помощью черепахи Добавьте функцию для кнопки [Hexagon], которая рисует обыч­ ный шестиугольник. Подсказка: В цикле повторите следующие действия шесть раз: • Поворот на 60 градусов.
Упражнения : графич еские и веб-п риложения • Перемещение вперед на 237 90 пикселей. '~- TurtleGraphics - Demo Reset Hide Turtle He)090R Spiral Sun Triangle Star Задача*: нарисовать звезду с помощью черепахи Добавьте функцию для кнопки [Star], которая рисует пятиконеч­ ную звезду, как на рисунке ниже: '~- TurtleGraphics - Demo Drav, Reset Hide Turtle Hexagon Splral Sun Triangle Подсказка: Измените цвет: $ ( «#turtle»). реп( « g ree п », «5») Star
Глава 238 5.1. Циклы В цикле повторите следующие действия пять раз: • • Двигайтесь вперед на Поворот на 180. 144 градуса. Задача*: нарисовать спираль с помощью черепашки Добавьте к кнопке с [Spiral] функцию, которая рисует спираль 30 вершинами, как на рисунке ниже: ~~ TurtleGraphics - Demo Dniv, Reset Нюе Turtle Heia,gon Sporal Sun Tnengle Ster Подсказка: Н арисуйте петлю, двигаясь вперед и поворачиваясь. С каждым шагом постепенно увеличивайте длину движения на вперед и поворачивайте на 5 пикселей 60 градусов. Задача*: нарисовать солнце с помощью черепахи Добавьте функцию для кнопки с [Sun], которая рисует солнце 36 вершинами, как на рисунке ниже. Подсказка: В цикле повторите следующие действия • Перемещение вперед на • Поворот на 170 градусов. 200. 36 раз:
Упражнения : графич еские и веб-приложения '~ ОГс!Уi 239 TurtleGraphics - Demo Reset Shov, Turtle Hexagon Splral Sun Triangle Star Задача * : нарисовать спиралънь1й треугольник с помощью черепахи Добавьте к кнопке треугольника с 22 [Triangle] функцию , которая рисует три в ер шинами каждый, как пока зано на рисун­ ке ниже: '~ Drav, TurtleGraphics - Demo Reset Hlde Turtle Hexagon Spiral Sun Triangle Star
240 Глава 5.1 . Циклы Подсказка: Нарисуйте петлю, двигаясь вперед и поворачивая. С каждым шагом увеличивайте длину движения вперед на вайте на 120 градусов. 10 и поворачи­ Повторите еще три раза для всех трех тре­ угольников. Если у вас возникли проблемы с приведенным выше примером проекта, задавайте вопросы на форуме forum. SoftUni: https://softuni.bg/
Глава 5.2. Циклы - экзаменационные задачи В предыдущей главе мы узнали, как выполнить блок команд бо­ for и рассмотрели не­ способы его использования. Цель этой главы - лее одного раза. Мы познакомились с циклом которые основные закрепить наши знания, решив несколько более сложных задач с циклами, которые даются на экзаменах. Для некоторых из них мы покажем подробные решения на примерах, а для других оста­ вим только подсказки. Прежде чем приступить к работе, неплохо было бы вспомнить конструкцию цикла for: Начальное Конечное значение значение for ( let i = 1; i <= 10; i++) console.log(''i = 11 Тело цикла: - блок команд Ша г на исполнение { + i); } Циклы for состоят из: • Блок инициализации, в котором объявляется переменная­ • (let i) и устанавливается ее начальное значение. Условие итерации (i <= 10), проверяемое один раз перед ка­ счетчик ждой итерацией цикла. • Обновление счетчика (i ++) - этот код вьmолняется после каждой итерации. • Тело цикла - содержит произвольный блок исходного кода. Экзаменационные задачи Давайте решим несколько экзаменационных задач с циклами.
242 Глава 5.2. Циклы - экзаменационные задачи Задача: гистограмма У нас есть n целых чисел в диапазоне [1 ... 1000]. Некоторый про­ цент из них pl меньше 200, другая часть р2 находится в диапазоне от 200 до 399, р3 - от 400 до 599, р4 - от 600 до 799 и остальные р5 от 800 и выше. Напишите программу, которая вычисляет и выво­ дит, сколько процентов составляют pl, р2, р3, р4 и р5. n = 20 чисел: 53, 7, 56, 180, 450, 920, 12, 7, 150, 250, 680, 2, 600, 200, 800, 799, 199, 46, 128, 65. Мы получаем следУЮщее Пример: у нас есть распределение и визуализацию: r Группа Кол ичество Числа 53, 180, 150, 46, < 200 7, 56, 12, 7, 2, 199, 128, 65 12 pl р2 200... 399 250, 200 2 400... 599 450 1 600... 799 680, 600, 799 3 920, 800 2 ~ 800 Процент чисел = 12 / 20 * 100 = 60 . 00% = 2 / 20 * 100 = 10.00% р3 = 1 / 20 * 100 = 5 . 00% р4 = 3 / 20 * 100 = 15.00% р5 = 2 / 20 * 100 = 10.00% Входнъ1е даннъ1е Первая строка (аргумент) входных данных содержит целое чис­ ло n (1 5. n 5. 1000), обозначающее количество чисел, которые будут переданы программе. В следУЮЩИХ целые числа в диапазоне n строках (аргумент) находятся [1 ... 1000] - числа, по которым будет вы­ числяться гистограмма. Вывод да1П1ых Вывести в консоль гистограмму из пяти строк, каждая из кото­ рых содержит число от 0% до 100%, округленное до двух цифр после десятичной точки (например, 25.00%, 66.67%, 57.14%). Ввод 3 1 2 999 вывод Ввод Вывод 66.67% 0.00% 0 . 00% 0 . 00% 33.33% 4 53 7 56 999 75.00% 0.00% 0 . 00% 0.00% 25.00%
Задача: гистограмма Ввод 243 Вывод Ввод Вывод Ввод Вывод 9 367 99 200 799 999 33 . 33% 33.33% 11.11% 11. 11% 11.11% 14 53 7 56 180 450 57 .14% 14 . 29% 7 . 14% 14 . 29% 7 . 14% 7 800 801 250 199 14.29% 28.57% 14 . 29% 14. 29% 28.57% Ввод Вывод Ввод Вывод Ввод Вывод 1 920 12 7 150 250 680 2 600 200 333 555 111 9 399 599 799 Рекомендации и подсказки Мысленно можно разделить программу, решающую эту задачу, на три части: • Чтение входных данных чтение числа в данной задаче это означает - n, за которым следуют n целых чисел, каждое в отдельной стр оке. • Обраб отка входных данных в данном случае это означа­ - ет распределение чисел по группам и вычисление процент­ ного распределения по группам. • Вывод конечного р езультата - печать гистограммы в кон­ соли в заданном формате. Считывание входных данных Прежде чем перейти к считыванию самих входных данных, необ­ ходимо объявить переменные, в которых мы будем их хранить : / /Переменная , let n = представляющая общее количество чисел Number (args(0]);
Глава 244 //Переменная, let pl let р2 let рЗ let р4 let pS = = = = = 5.2. Циклы - экзаменационные задачи содержащая количество чисел по группам 0; 0; 0; 0; 0; //Переменные, в которых мы будем хранить процентное //соотношен и е отдельных групп let let let let let plPercentage p2Percentage = = pЗPercentage = p4Percentage = pSPercentage = В переменной n 0; 0; 0; 0; 0; мы будем хранить количество чисел, которые нам нужно получить. Кроме того, мы объявляем переменные pl, р2 и т. д., в которых мы будем хранить количество чисел соответству­ ющей группы. После того как мы объявили необходимые переменные, можно приступать к обработке входных данных. Обработка входных данных Чтобы получить и распределить каждое число в соответствую­ щую группу, мы будем использовать цикл for от 0 до n (количество чисел). Каждая итерация цикла будет считывать и распределять одно число (currentNum) в соответствующую группу. Чтобы опреде­ лить, принадлежит ли число к группе, мы проверяем его диапазон. Если да, то мы увеличиваем количество чисел в этой группе ит.д.)на 1: for (let i = 1; i <= n; i++) { let currentNum = Number (args[i]); if (currentNum < 200) { pl++; } else if (currentNum < 400) { р2++; } else if (currentNum < 600) { рЗ++; } else if (currentNum < 800) { р4++; } else { (pl, р2
Задача: гистограмма 245 pS++; } } Определив количество чисел в каждой группе, мы можем пе­ рейти к вычислению процентного соотношения, что и является основной целью задачи. Для этого мы воспользуемся следующей формулой: (процент группы)= (количество чисел в группе)/ (количество всех чисел) * 100 В программном коде эта формула выглядит примерно так, как по­ казано ниже: plPercentage = (pl / n ~ 100). toFixed (2); В условии сказано, что результат должен содержать две циф­ ры после запятой. Исходя из этого, добавляем в формулу метод . toFixed( ... ), и для первой переменной она будет выглядеть следу­ ющим образом: plPercentage (pl / n * 100).toFixed(2); = / /Добавьте формулы для оставшихся переменных Чтобы было еще понятнее, что происходит, давайте рассмотрим следующий пример: Ввод Вывод ' 66.67% 0 . 00% 0.00% 0.00% 33 . 33% 3 1 2 999 1 В случае • • n = 0- з при выполнении цикла имеем: 1, которое меньше 200 и попадает в первую группу (pl), увеличиваем счетчик группы на 1. i = 1 - считаем число 2, которое снова попадает в первую группу (pl), и увеличиваем его счетчик снова на 1. i = считываем число
Глава 24 6 • i = 2- 5.2. Циклы - экзаменационные задачи считываем число нюю группу (pS), так счетчик группы на как 999, которое попадает в послед­ оно больше 800, и увеличиваем 1. После считывания чисел в группе pl у нас есть два числа, а в ps - одно число. В остальных группах у нас нет чисел. Применяя при­ веденную выше формулу, вычисляем процентное соотношение ка­ ждой группы. Вывод окончательного результата Осталось вьmести результаты в консоль: consol e.log(plPercentage + "%" ) ; Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/934#0. Задача: умная Лили Nлет. На каждый день рождения она получала подарок. На каждый нечетный день рождения (1, 3, 5, ..., n) она получа­ ла игрушки, а на каждый четный (2, 4, 6, ..., n) - деньги. На свой вто­ ЛИли испоJП-IИЛось рой день рождения она получила 10.00 USD, и эта сумма увеличивает­ ся на 10.00 USD на каждый следующий четньrй день рождения (2 -> 10, 4-> 20, 6-> 30 и т. д.). Все эти годы ЛИли тайно копила деньги. Брат ЛИли в те годы, когда она получала деньги, брал по 1.00 USD из каждой сум­ мы. ЛИли продала игрушки, полученные за эти годы, КаждУЮ за Р USD, и добавила эту сумму к сумме накопленных денег. На вырученнь1е деньги она хотела купить стиральную машину за х USD. Напишите программу, которая вычислит, сколько денег она со­ брала и достаточно ли их для покупки стиральной машины. Входнъ1е даннъ1е Считываем из консоли три числа, каждое в отдельной строке: • Возраст Лили - целое число в диапазоне [1 ... 77].
Задача: умная Лили • 247 Цена стир альной машины - число в диапазоне [1.00 ... 10 000.00]. • Цена за ощrу игрушку - целое число в диапазоне [О ... 40]. Выходнъ1е даннъ1е Выведите на экран одну стр оку: • Если денег ЛИли будет достаточно: о • где N- оставшиеся после покупки деньги. Если денег не хватает: о • "Yes ! {N}" "No ! {М}" - где м- недостающая сумма. Числа N и м должны быть отформатированы до второй цифры после десятичной точки. Примеры ввода и вывода Ввод вывод Пояснения 550 USD. Она продала 11 игрушек по 3 USD каждая = 33 USD. Ее брат взял за 10 лет по 1 USD в год= 10 USD . Оставшаяся сумма : 550 + 33 - 10 = 573 USD. 573 < 1570,98 : ей не удалось купить Лили накопила 21 1570 . 98 No! 997.98 3 ст и ральную машину . составляет Ввод Недостающая сумма 1570, 98 - 573 = 997.98 USD . Вывод Пояснения На первый день рождения Лили получает -> 10 USD; 3-й -> игрушку; 4-й - > 10 + 10 = 20 USD; 5-й -> игруш­ ку ; 6-й -> 20 + 10 = 30 USD ; 7-й -> игрушку; 8-й -> 30 + 10 = 40 USD ; 9-й -> игрушка; 10-й -> 40 + 10 = 50 USD . Она сэкономила-> 10 + 20 + 30 + 40 + 50 = 150 долларов . Л и ли продала 5 и гру­ ше к по 6 USD каждая= 30 USD . Ее брат взял 1 USD 5 раз= 5 USD . Ос т авшаяся сумма-> 150 + 30 - 5 = 175 USD . 175 > 170 (цена стиральной маши­ и г рушку; 10 170.00 6 Yes! 5. 00 2-й ны): она смогла ее купить и осталась с 175 - 170 = 5 USD. 1
Глава 248 5.2. Циклы - экзаменационные задачи Рекомендации и советы Решение этой задачи, как и предыдущей, также можно разде­ лить на три части - считывание входных данных, их обработка и вывод на экран: let age = Number(argl); let 1-1ashingl~achineP r ice = let toyPrice = И снова мы начинаем с выбора подходящих имен перемен­ ных: для количества лет Лили (age), для цены стиральной машины (washingMachinePrice) и для цены единицы игрушки (toyPrice). В при­ веденном вьппе коде мы также объявляем и инициализируем (при­ сваиваем значение) переменные для количества игрушек (toysCount) и подаренных денег на дни рождения (moneyFromBirthdays): let toysCount = 0; let moneyFromBirthdays С помощью цикла for = 0; мы перебираем все дни рождения Лили. Если ведущая переменная - нечетное число, мы увеличива­ ем количество игрушек. Мы проверяем четность путем вычис­ ления остатка от деления (%) на число число четное, а если остаток равен щая переменная - 2- если остаток равен О, 1, то число нечетное. Если веду­ четное число, это означает, что Лили получи­ ла деньги, и мы соответственно добавляем эти деньги к ее общим сбережениям. Мы увеличиваем значение переменной Birthdays, то есть увеличиваем на 10 сумму, moneyFrom- которую она получит на свой следующий день рождения. В то же время мы вычитаем 1 USD - деньги, которые забирает ее брат. Мы используем более краткий вариант, доб авляя два знака минус после переменной (moneyFromBirthdays- -): for (let i = if (i % 2 1; i <= age; i ++) { == 1 ){ toysCount++; } else { moneyFromBi rthdays += 10 * i/2; moneyFromBirthdays , } }
Задача: вернуться в прошлое 24 9 Если вы будете вычислять количество полученных Лили денег таким образом, у вас наверняка возникнут проблемы с подсчетом денег, полученных на день рождения: moneyFromBirthdays += 10; В итоге получается 10 х 5 = 50, в то время как нам нужно 10 + 20 + 30 + 40 + 50 = 150. Мы можем решить эту проблему с помощью допол­ нительной переменной (bonusMoney): bonusMoney += 10; moneyFromBirthdays += bonusMoney; Или мы можем использовать значение переменной выступает как счетчик, и разделить на i, которая 2: moneyFromBirthdays += 10 * i / 2; Добавьте деньги от продажи игрушек к сбережениям Лили: let money = moneyFromBirthdays + toyPrice * toysCount; Наконец, нам нужно вывести результат, соблюдая форматиро­ вание, указанное в условии, то есть сумма должна быть округлена до двух цифр после десятичной точки: if (money >= was hingMachinePrice) { console . log( ' Yes! ${ ( money washingMachinePrice). toFixed (2) }'); } else { console . log('No! ${(washingMachinePrice money). toFixed (2) }' ); } Чтобы не создавать дополнительные переменные, мы использу­ ем placeholder - ${выражение}. С его помощью мы можем вьmол­ нить вычисление и непосредственно включить результат в тексто­ вую строку. Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/934#1. Задача: вернуться в прошлое Ивану 18 лет, и он получает наследство, состоящее из суммы денег х и машины времени. Он решает переместиться в 1800 год,
250 Глава 5.2. Циклы - экзаменационные задачи но не знает, хватит ли ему денег, чтобы жить не работая. Напиши­ те программу, которая вычисляет, хватит ли Ивану денег, чтобы не работать до определенного года (включительно). Предположим, (1800, 1802 и т. д.) год он потратит 12 ООО дол­ нечетный (1801, 1803 и т. д.) год он потратит что за каждый четный ларов. В каждый 12 ООО + 50 * (возраст, которого он достигнет в данном году). Входные данные Входные данные считываются из консоли и содержат две строки: • Унаследованные деньги - вещественное число в диапазоне [1.00 ... 1 ООО 000.00]. • Год, до которого он должен прожить в прошлом (включи­ тельно) - целое число в диапазоне [1801 ... 1900]. Выходные данные В консоль выводится одна строка. Сумма должна быть отформа­ тирована до двух символов после десятичной точки: • Если денег достаточно: о "Yes ! Не will li ve а carefree li fe and will have {N} dollars left." ("Да! Он будет жить беззаботно, и у него останется {N} долларов"), где N- количество денег, которые останутся. • Если денег недостаточно: о "Не will need {М} dollars to survive." ("Чтобы выжить, ему потребуется {М} долларов"), где М-сумма, которой не хватает. Примеры ввода и вывода Ввод Вывод 100000.15 Не will need 1808 12399.85 dollars to survive. Пояснен и я 1800 ➔ чет н ый ➔ Остается 1801 = 88000.15 ➔ нечетный ➔ Остается . .. 100000.15 - 12000 88000.15 - 12950 = 75050.15 1808 ➔ ч ет н ый ➔ -399,85 - 12000 12399.85 недостаточно =- 12399.85
Задача: вернуться в прошлое Ввод 50000 1802 251 Вывод Yes! Не will live а carefree life and will have 13050.00 dollars left . Пояснения 1800 ➔ четный ➔ Тратит 12000 долларов 50000 - 12000 = 38000 ➔ Осталось 1801 ➔ нечетный ➔ Потрачено 12000 + 19*50 = 12950 долларов ➔ Осталось 1802 38000 - 12950 = 25050 ➔ четный 12000 долларов Остаток 25050 - 12000 = 13050 ➔ Тратит ➔ Рекомендации и советы Метод решения этой задачи ничем не отличается от предыду­ щих, поэтому приступаем к объявлению и инициализации необхо­ димъrх переменньrх. В условии сказано, что возраст Ивана равен явлении переменной ние равным 18. years 18, поэтому при объ­ мы устанавливаем ее начальное значе­ Значения остальных переменньrх мы считываем из считанных параметров функции: let heritage = let yearTolive = let years = 18 ; С помощью цикла for переберем все годы. Начнем с 1800 года, года перемещения Ивана, и будем перебирать до года, до которого он должен жить в прошлом. В цикле мы проверяем, является ли те­ кущий год четным или нечетным. Четность проверяется вычис­ лением остатка от деления (%) на 2. Если год четный, то вычитаем (heri tage) 12000, а если нечетный, то вычитаем из на­ следства (heri tage) 12000 + 50 * (возраст Ивана): из наследства for (let currentYear = 1800; currentYear <= yearToLive; currentYear++) { if (currentYear % 2 == 0) { heritage -= 12000; } else { heritage -= (12000 + 50 * years); } years++; }
Глава 252 5.2. Циклы - экзаменационные задачи Наконец, нам осталось вывести результаты, для чего мы прове­ ряем, достаточно ли его наследства (heri tage) для того, чтобы жить, не работая, или нет. Если наследство - положительное число, то выводим «Yes ! Не will live а carefree li fe and will have {N} dollars left.» («Да! Он будет жить беззаботно и у него останется {N} долларов»), а если отрицательное - «Не will need {М} dollars to survive . » («Чтобы выжить, ему потребуется {М} долларов . »). Не забудьте отформатировать сумму с точностью до двух знаков по­ сле десятичной точки. Подсказка: подумайте об использовании метода Math. abs( . .. ) при выводе результата, если наследства недостаточно. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/934#2. Задача:больница В течение определенного периода времени каждый день в боль­ ницу поступают пациенты для обследования. Изначально в ней ра­ ботает семь врачей. Каждый врач может лечить только одного па­ циента в день, но иногда врачей не хватает, поэтому оставшихся пациентов отправляют в другие больницы. Каждый третий день в больнице проводятся подсчеты, и если количество непролечен­ ных пациентов превышает количество пролеченных, то назнача­ ется еще один врач. Назначение производится в этот же день до на­ чала приема пациентов. Напишите программу, которая вычисляет количество пролечен­ ных и непролеченньIХ пациентов за определенньIЙ период времени. Входные данные Входнь1е данные считываются из консоли и содержат: • • В первой строке - период, для которого необходимо произ­ вести вычисления. Это целое число в диапазоне (1 ... 1000]. В следующих строках (равньIХ количеству дней) - количе­ ство пациентов, поступивших на лечение за текущий день. Целое число в диапазоне [О ... 10 ООО].
Задача: больница 253 Выходные данные Выведите в консоль две строки: • В первой строке: "Treated patients: {количество пролеченных пациентов}". • Во второй: "Untreated patients: {количество непролеченных пациентов}". Примеры ввода и вывода Ввод вывод 3 7 7 7 Treated patients: 21 . Untreated patients: 0. Ввод Вывод Пояснения ! день 1: 7 пациентов День 4 7 27 9 1 2: 7 пациентов Treated patients: 23. Untreated patients: 21. День 3: ентов уже за и 1 День 0 и 20 непролеченных день пролеченных непролеченных день 14, а непролеченных Назначен новый врач . -> 8 непролеченный пациент 4: 1 Итого: 23 пациент. Вывод 6 25 25 25 25 25 2 за и к этому моменту пролеченных паци- пациентов Ввод пролеченных Treated patients : 40. Untreated patients: 87. пролеченный и за 0 - 20 -> пролеченных за день непролеченных день пролеченных и 21 непролеченный
Глава 254 5.2. Циклы - экзаменационные задачи Рекомендации и советы Начнем с того, что объявим и инициализируем необходимые переменные. Период (количество дней), для которого необходимо произвести вычисления, мы считьmаем из параметров функции и сохраняем в переменной period. Также нам понадобятся несколь­ ко вспомогательных переменных: количество пролеченных паци­ ентов (treatedPatients), количество непролеченных пациентов (untreatedPatients) и количество врачей (countOfDoctors), которое изначально равно let period 7: = let treatedPatients = 0 ; let untreatedPatients = 0 ; let countOfDoctors = 7; С помощью цикла for мы перебираем все дни в заданном периоде (period). Для каждого дня мы считываем из консоли количество па­ циентов (currentPatients). Увеличение количества докторов по ус­ ловию можно производить каждый третий день, НО только если количество непролеченных пациентов больше количества проле­ ченных. Для этого проверяем, является ли день третьим - с помо­ щью арифметического оператора вычисление остатка от деления(%): == 0. day % 3 Например : • Если день третий, то остаток от деления на З будет равен О (3 % • 0), и проверка day % з == 0 вернет true. Если день второй, то остаток от деления на (2 % • з = з = 3 будет равен 2 2), и проверка вернет false. Если день четвертый, то остаток от деления будет равен 1), и проверка снов а вернет false. проверка day % з == 0 возвращает true, то (4 % Если 1 з = также прове­ ряется, превышает ли количество непролеченных пациентов ко­ личество untreatedPatients > treatedPatients. true, то количество врачей будет увеличено пролеченных: Если результат снова (countOfDoctors). Затем проверяем, больше ли количество пациентов за день (currentPatients), больше: чем количество врачей (countOfDoctors). Если
Задача: деление без остатка • 255 Мы увеличиваем значение переменной на количество врачей • Увеличиваем treatedPatients (count0fDoctors). значение переменной untreatdPatients на количество оставшихся пациентов, которое вычисляет­ ся путем вычитания количества врачей из всех пациентов (currentPatients - count0fDoctors). Если количество пациентов не больше, мы только увеличива­ treatedPatients (currentPatients): ем переменную на количество пациентов за день for (let day = 1 ; day <= period; day++} { let currentPatients = if ((day % З == 0 ) && (untreatedPatients > treatedPatients)) { countOfDoctors++; } i f ( currentPatients > count OfDoctot·s) { treatedPatients += countOfDoctors; untreatedPatients += currentPatients - countOfDoctors; } else { treatedPatients += currentPatients; } } Наконец, нам нужно вывести только количество пролеченных и количество непролеченных пациентов. Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/934#3. Задача: деление без остатка У нас е сть n целых чисел в диапазоне [1 ... 1000]. Среди них определенный процент чисел pl, которые делятся без остатка н.а 2, процент чисел р2, которые делятся без остатка н.а 3, про­ цент чисел рЗ, которые делятся без остатка н.а 4. Напишите про­ грамму, которая вычисляет и выводит процентное соотношение pl, р2 И рЗ.
Глава 256 Пример: у нас есть 5.2. Циклы - экзаменационные задачи n = 10 чисел: 680, 2, 600, 200, 800, 799, 199, 46, 128, 65. Получаем распределение и визуализацию, приведенные в та­ блице: Деление без о с татка Кол - Числа на В процентном соотноwении во 1 2 680, 2, 600, 200, 800, 46, 128 7 pl = (7 / 10) * 100 = 70.00 % 3 600 1 р2 = (1 / 10) * 100 = 10.00 % 4 680, 600 , 200, 800 , 128 5 р3 = (5 / 10) * 100 = 50.00 % Входные данные В первой строке ввода находится целое число количество чисел. В каждой из следующих ному целому числу из диапазона n (1 ~ n ~ 1000) - n строк находится по од­ [1 ... 1000] - числа, которые необ­ ходимо проверить на делимость. Выходные данные Выведите в консоль три строки, каждая из которых содержит процент от О % до 100 % с двумя цифр ами после десятичной точки, например 25.00 %, 66.67 %, 57.14 %. • В первой строке - проце нт чисел, которые деля тся на • 2. Во второй строке - процент чисел, которые делятся - пр оцент чисел, которые делятся наз. • В третьей строке на 4. Примеры ввода и вывода Ввод 3 3 6 9 1 Вывод 33.33 % 100 . 00 % 0.00 %
Задача: деление без остатка Ввод 1 12 Ввод 10 680 2 600 200 800 799 199 257 Вывод 100.00 % 100.00 % 100.00 % Вывод 70.00 % 10.00 % 50.00 % 46 128 65 Рекомендации и советы Для этого и следующего задания необходимо самостоятельно на­ писать программный код, сле'!JУЯ приведенным инструкциям. Пр ограмма, решающая данную задачу, аналогична программе из задачи «Гистограмма », рассмотренной выше. Поэтому мы мо­ жем начать с объявления необходимых нам переменных. Пример ­ ные имена переменных: n- количество чисел (которые нам нужно считать) и divisiЫeBy2, divisiЫeByЗ, divisiЫeBy4 - вспомога­ тельные переменные, хранящие количество чисел в соответству­ ющей группе. Чтобы считать и распределить каждое число в соответствую­ щую группу, нам нужен цикл for от 0 до n (количество чисел). Ка­ ждая итерация цикла должна считывать и обрабатьmать одно чис­ ло. Отличие в том, что одно число может попасть в несколько групп одновременно, поэтому нам нужно сделать три отдельные провер­ ки if для каждого числа - делится ли оно на 2, 3 и 4 соответствен­ но, и увеличить значение переменной, хранящей количество чи­ сел соответствующей группы.
Глава 258 Внимание: оператор if-else 5.2. Циклы - экзаменационные задачи в данном случае не поможет, по­ скольку, обнаружив совпадение, он прервет дальнейшую провер­ ку условий. Наконец, необходимо вывести результаты, соблюдая формат, указанный в условии. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/934#4. Задача: логистика Вы отвечаете за логистику различных типов грузов. В зависи­ мости от веса каждого груза вам потребуются разные автомобили, и перевозка будет иметь разную цену за тонну: • • • До З тонн - (200 USD за тонну). От 3 до 11 тонн - грузовик (175 USD за тонну). Свыше 11 тонн - поезд (120 USD за тонну). Ваша задача - рассчитать среднюю цену за тонну груза, а также микроавтобус то , какой процент груза перевозится на каждом виде транспорта. Входные данные Из консоли мы должны считать последовательность чисел, ка­ ждое в отдельной строке: • Первая строка: количество грузов для перевозки число в диапазоне • - целое [1 ... 1000]. В следующих строках мы передаем тоннаж текущего гру­ за - целое число в диапазоне [1 ... 1000]. Выходные данные В консоль выводятся четыре строки следующего содержа­ ния: • Строка № 1- средняя цена за тонну груза (округляется до второй цифры после десятичной точки). • Строка № сом 2 - процент грузов, перевозимых микроавтобу­ (от 0,00 % до 100,00 %, округление до второй цифры по­ сле десятичной точки).
259 Задача: логистика • • Строка - процент грузов, перевозимых грузовиком (от 0,00 % до 100,00 %). Строка No 4 - процент грузов, перевозимых по железной дороге (от 0,00 % до 100,00 %). No З Примеры ввода и вывода Ввод Вывод 4 143.80 1 16.00 % 5 20.00 % 16 64.00 % 3 Пояс нения На микроавтобусе вы всего 4 перевозите два 1 + 3, груза тонны. На грузовике вы перевозите один груз: 5 тонн. 16 тонн. Сумма всех грузов: 1 + 5 + 16 + 3 = 25 тонн. Процент груза на микроавтобусе : 4/25*100 = 16.00 % Процент груза на грузовике: 5/25*100 = 20 .00 % Процент груза на поезде: 16/25*100 = 64.00 % Поездом вы перевозите один груз: Средняя цена за тонну перевозимого груза: (4 * 200 + 5 * 175 + 16 * 120) / 25 Ввод = 143 . 80 Вывод 5 149.38 2 7.50 % 10 42. 50 % 20 50 .00 % 1 7 Ввод 4 53 7 56 999 Вывод 143.80 16.00 % 20 . 00 % 64. 00 % Рекомендации и советы Сначала мы считываем вес каждого груза и суммируем, сколько тонн перевозится микроавтобусом, грузовиком и поездом, а также
Глава 260 5.2. Циклы - экзаменационные задачи подсчитьmаем общее количество тонн перевезенного груза. Далее рассчитьmаем цены на каждый вид транспорта в зависимости от ко­ личества перевезенных тонн и общей стоимости. Наконец, мы рас­ считаем и выведем общую среднюю цену за тонну и то, сколько гру­ зов перевозится различными видами транспорта, в процентах. Объявляем необходимые переменные, например следующие: countOfLoads количество перевозимых грузов (считываем из консоли), sumOfTons truckTons, trainTons - сумма тоннажа всех грузов, microbusTons, переменные, содержащие сумму тоннажа грузов, перевозимых соответственно микроавтобусом, грузовиком и поездом. Нам понадобится цикл for от 0 до countOfLoads - 1, чтобы обой­ ти все грузы. Для каждого груза мы считьmаем его вес (в тоннах) и сохраняем его в переменной, например текущего груза (tons) tons. к сумме весов всех грузов Мы добавляем вес (sumOfTons). После того как мы считали вес текущего груза, нам нужно определить, какое транспортное средство будет для него использовано (фургон, грузовик или поезд). Для этого нам понадобятся проверки • i f-else: tons меньше 3, то мы увеличи­ ваем значение переменной microbusTons на величину tons: Если значение переменной microbusTons += tons; • Если значение 11- увеличи­ ваем значение переменной truckTons на tons. • Если tons больше tons больше трех, но меньше 11, увеличиваем trainTons на tons. Пер ед тем как вьmести результат, нам нужно рассчитать процент тонн, перевезенных. каждым транспортным средством, и ср еднюю стоимость одной тонны. Для средней цены за тонну мы объявим еще одну вспомогательную пер еменную totalPrice, в которой про­ суммируем общую цену всех перевезенных грузов (микроавтобу­ сом, грузовиком и поездом). Среднюю цену мы получим, разделив totalPrice на sumOfTons. Вам остается вычислить процент тонн, пе­ ревезенных каждым тр анспортным средством, и вьmести резуль­ тат, следуя формату, указанному в условии. Проверка в системе Judge Проверьте свое решение: Index/934#5. https://judge.softuni.bg/Contests/Practice/
Глава 6.1. Вложенные циклы В этой главе мы рассмотрим вложенные циклы и использова­ ние циклов for для рисования различных консольных фигур, со ­ стоящих из символов и знаков, ра сположенных в консоли в стро ­ ках и столбцах. Мы будем использовать одиночные и вложенные циклы (один цикл внутри другого), вычисления и проверки для по­ строения различных фигур в консоли в соответствии с заданными размерами. Пример: прямоугольник размером 10 х 10 звездочек Нарисуйте в консоли прямо угольник размером дочек. Ввод (нет) вывод ********** ********** ********** ********** ********** ********** ********** ********** ********** ********** Рекомендации и советы function printSquare() { for (let i = 1; i <= 10; i++) { console.log(''*''.repeat(10)); } } 10 х 10 звез­
Глава 262 6.1. Вложенные циклы Как работает пример? Инициализируйте тело цикла перемен­ 1, которая увеличивается на каждой итерации цикла, пока не станет меньше или равна 10 (i <= 10). Таким образом, код в теле ной i = цикла вьmолняется строку«*». 10 раз. Тело цикла печата ет в консоли новую repeat(10), котор ая создает строку из 10 звездочек. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#0. Пример: прямоугольник из N х N звездочек Напишите программу, которая считывает целое п оложитель­ ное число n и выводит в консоль прямоугольник из N х N звез­ дочек. Ввод Вывод ** ** 2 Ввод вывод *** *** *** 3 1 Ввод 4 Вывод **** **** **** **** Рекомендации и подсказки func t ion drawSquare(n) { for (let i = 1; i <= п; i++) { console.log(''*''.repeat(n)); } } Примечание В некоторых веб-браузерах идентичные строки в консоли объ­ единяются NodeJS. в одну. Для примеров Если вы все же попали в такую ситуацию, можно добавить новую стр оку + рекомендуется использовать \n в конце метода print: console.log(«*».repeat (10) «\п») ; Проверка в системе Judge Проверьте свое решение: Index/935#1. https://judge.softuni.bg/Contests/Practice/
263 Вложенные циклы Вложенные циклы Вложенные циклы - это конструкции, в которых в теле одно­ го цикла (внешнего) выполняется дРуrой цикл (внутренний). При каждой итерации внешнего цикла внутренний цикл выполняется еще раз. Это происходит следующим образом: • Когда вложенные циклы начинают вьmолняться, первым запускается внешний цикл: инициализируется управляю­ щая переменная и после проверки на завершение цикла выполняется код в его теле. • После этого вьmолняется внутренний цикл. Инициализи­ руется начальная позиция управляющих переменных, про ­ изводится проверка на завершение цикла и выполняется код в его теле. • При достижении заданного значения для завершения цикла программа возвращается на один шаг вверх и продолжает вьmолнение предыдущего (внешнего) цикла. Управляющая переменная внешнего цикла изменяется на один шаг, проис­ ходит проверка вьmолнения условия завершения цикла и на­ чинается новое вьmолнение вложенного (внугреннеrо) цикла. • Это повторяется до тех пор, пока переменная внешнего цикла не выполнит условие завершения цикла. Приведем пример, иллюстрирующий использование вложенных циклов. Задача состоит в том, чтобы вывести на экран прямоуголь­ n * n звездочек, выполняя цикл от 1 до n для каждой строки и вложенный цикл от 1 до n для каждого столбца: ник из function drawSquare(n) { for (let i = 1; i <= let stars = ""; п; for (let j = 1; j <= stars += * , 11 11 • } console.log(stars); } } i++) { п; j++) {
Глава 264 6.1 . Вложенные циклы Рассмотрим приведенный выше пример. После инициализации первого (внешнего) цикла начинается выполнение его тела, ко­ торое содержит второй (вложенный) цикл. Он сам хранит строку из n количества звездочек в переменной, а затем вьmодит их в од­ ной строке. Как только внутренний цикл завершит выполнение на первой итерации внешнего цикла, внешний цикл продолжит выполнение. После этого переменная первого цикла будет обнов­ лена, и весь второй цикл будет выполнен снова. Внутренний цикл будет выполняться столько раз, сколько длится тело внешнего цик­ ла, в данном случае n раз. Пример: квадрат из звездочек Нарисуйте в консоли квадрат из Ввод N х N звездочек: Вывод * * * * 2 ввод Вывод 1 * * * * * * * * * 3 Ввод 4 вывод * * * * * * * * * * * * * * * * Рекомендации и подсказки Задача аналогична предыдущей. Отличие состоит в том, что не­ обходимо продумать, как вьmести пробел после звездочек таким образом, чтобы не было лишних пробелов ни в начале, ни в конце: function drawSquare(n) { for (let i = 1; i <= n; i++) { let stars = ''*'';
265 Вложенные циклы for (let j = 1; j < n; j++) { stars +=" * , 11 • } console.log(stars); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#2. Пример: треугольник из с.имволов доллара Напишите программу, которая принимает целое число n и выво­ дит треугольник, составленный из символов доллара, размером n. Примеры ввода и вывода Ввод Вывод ' Ввод $ $ 3 Вывод $ $ $ $ $ 4 $ $ $ $ $ $ $ $ $ Рекомендации и подсказки Задача похожа на рисование прямоугольника и квадµата. Мы снова будем использовать вложенные цикль1, но здесь есть одна загвоздка. Разница в том, что количество столбцов, которые нам нужно вывести, зависит от строки, в которой мы находимся, а не от входного числа n. Из примера ввода и вывода видно, что ко­ личество символов доллара зависит от того, в какой строке мы на­ ходимся в момент вывода, то есть строку, 3 знака доллара - 1 знак доллара означает первую третью и т. д. Рассмотрим приведенный ниже пример более подµобно. Мы видим, что переменная вложен­ ного цикла связана с переменной внешнего цикла. Таким образом, наша программа выводит нужный треугольник. function drawTriangle(n) { for (let i = 1; i <= n; i++) {
Глава 266 6.1 . Вложенные циклы let dollars = "$"; for (let j = 1; j < i; j++) { dollars +=" $"; } console . log(dollars); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#3. Пример: квадратная рамка Напишите программу, которая считывает целое положительное число n и рисует в консоли квадратную рамку размером n * n. Ввод Вывод Ввод + - - + - - 4 - - 1 - + + 1 Вывод + 5 - - - - - - Ввод + - - - - + - - - - - - - + -- -- -- Вывод 6 - - - - - - - + - - - - + + - - - + Рекомендации и подсказки Решить задачу можно следующим образом: • • Считываем из консоли число n. Выводим верхнюю часть: сначала знак+, затем n-2 раза - и в конце знак+. • Средняя часть: выводим n - 2 строки, так как сначала выво­ дим знак 1,затем n-2 раза - и в конце снова знак 1- Мы мо­ жем сделать это с помощью вложенных циклов. • Выводим нижнюю часть: сначала знак +, затем n- 2 раза - и в конце знак+. Вот пример реализации описанной выше идеи с использовани­ ем вложенных циклов: function drawSquareFrame(n) { // вывод верхнего ряда->+ - - +
Вложенные циклы 267 let topRow = "+"; for (let top = 0; top < n - 2; top++) { topRow +=" -"; } topRow += "+"; console.log(topRow); // вывод среднего ряда-> 1 - - 1 for (let mid = 0; mid < n - 2; mid++) { let middleRow = '' 1'' ; for (let j = 0; j < n - 2; j++) { middleRow += '' -''; } middleRow += '' 1'' console.log(middleRow); } // вывод нижнего ряда->+ - - + let bottomRow = "+"; for (let bot = 0; bot < n - 2; bot++) { bottomRow +=" - "; } bottomRow += "+"; console.log(bottomRow); } Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/935#4. Пример: ромб из звездочек Напишите программу, которая считывает целое положительное число Ввод 1 n и вьmодит ромб из звездочек размера n. вывод * Ввод 2 Вывод * * * * Ввод вывод 3 * * * ** * ** * Ввод 4 Вывод * * * * * * ** ** * * * * * *
Глава 268 6.1 . Вложенные циклы Рекомендации и подсказки Чтобы реnшть эту задачу, нужно мысленно разделить ромб на две части - верхнюю, которая также включает в себя средний ряд, и нижнюю. Для вывода каждой части мы будем использовать два отдельных цикла, а зависимость между n и пер еменными ци­ клов оставим на усмотрение читателя . Для первого цикла мы мо­ жем использовать следУЮщие рекомендации: Выводим п • • • - интервалы между рядами (row). Выводим*. Выводим row - 1 раз *. Вторую (нижнюю) часть выводим аналогичным образом, остав­ ляя реализацию для самостоятельной работы читателя: function drawRhombus (n) { for (l et row = 1; row <= n; row++) { let liпe = ""; for (let col = 1; col <= n - row; col++) { line +=" "; } line += "*" ; for (let col = 1; col < row; col++) { line +=" *"; } console.log(line); } // TODO : вывести нижнюю часть ромба } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#5. Пример: рождественская елка Напиnште пр ограмму, которая считывает число и выводит рождественскую елку высотой Ввод вывод 1 * 1 вывод 1 1 1 Ввод * 2 * ** 1 1 * ** n + 1. n (1 s; n s; 100)
Рисование более сложных фигур Ввод Вывод 3 1 1 1 1 * ** *** 269 Ввод * ** *** Вывод 4 1 * ** *** **** 1 1 1 1 1 * ** *** **** 1 Рекомендации и подсказки Из примеров видно, что рождественскую елку можно разделить на три логические части. Первая часть до и после них, средняя - - это звездочки и пробелы (пробел) 1 (пробел), и последняя - снова звездочки, но на этот раз перед ними только пробелы. Для вывода достаточно одного цикла и метода . repeat ( п), который мы будем использовать один раз для звездочек и один раз для пробелов: function drawTree(n) { for (let i = 0; i <= n; i++) { let stars = "*".repeat(i); let spaces =" ".repeat (n - i); let body =" 1 "; let row = spaces + stars + body + stars + spaces; console.log(row); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#6. Рисование более сложных фигур Давайте посмотрим, как мы можем рисовать фигуры в консоли с более сложной логикой построения, которую нужно продумать до начала написания кода. Пример: солнечные очки Напишите (З ~ n ~ S*n х 100) программу, которая принимает целое число n и выводит на экран солнечные очки размером n, как показано в примерах.
270 Глава Ввод вывод 3 ****** ****** *////* 111*////* ****** ****** Ввод 6.1. Вложенные циклы Вывод ******** ******** ******** ******** *!!lll!*I 11 l*!!III!* *!!!/!!* *!/!/!!* 4 1 Ввод Вывод ********** ********** ********** ********** *!!I/I/!/* *!!I///I/* *!!lllll!*I 111 l*!!llll!I* *////////* *!!I//I/!* 5 Рекомендации и подсказки Из примеров видно, что солнечные очки можно разделить на три части - верхнюю, среднюю и нижнюю. Часть кода, с помощью ко­ торого можно решить задачу, приведена ниже. При рисовании верхней и нижней строк нам нужно вьmести на экран 2 * n звездочек, n пробелов и 2 * n звездочек: function sunGlasses(n) { // Print the top part let topline = ''*''.repeat(2 * n); topline += '' ''.repeat(n); topline += ''*''.repeat(2 * n); console.log(topline); for (let i = 0; i < n - 2; i++) { // TODO: вывести среднюю часть } // Print the bottom part let bottomline = "*".repeat(2 * n); bottomline += '' ''.repeat(n);
Рисован и е более сложных фигур 271 bot tomline += "*" . repeat(2 * n); console . log(bottoml ine); } При выводе центральной части необходимо найти номер стро ­ ки по формуле поскольку из примеров видно, ( n - 1) / 2 - 1, что на этой строке нужно выводить вертикальные линии вместо пробелов. Проблема с выражением ( n - 1) / 2 - 1 заключается в том, что оно может давать дробное число. Например, при n = 6 : (6 - 1) / 2 - 1 => s / 2 - 1 => 2.5 - 1 => 1 . 5. Поэтойпричине необходимо применить математический метод для отбрасывания дробной части- Math . floor( ...): / / Print the middle part for (let i = 0; i < n - 2; i++) { let middleline = '' ''; // TODO: вывести*//// / /* if (i === Math.fl oor((n -1) / 2 -1)) { middleline += ''l''.repeat(n); } else { middleline += '' '' . repeat(n); } // TODO: вывести*//// / /* console . log(middleline) ; } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#7. Пример : ДОМИК НаIШШИТе программу, которая считьmает число и вьmодит на экран домик размером Ввод 2 вывод ** 11 Ввод вывод 3 -**** 1*1 1 1 n х n (2 i n .$. 100) n, в точности как в примерах: Ввод вывод 4 -****** 1**1 1**1 Ввод 5 вывод --*--******** 1***1 1***1
Глава 272 6.1. Вложенные циклы Рекомендации и подсказки Из условия задачи мы понимаем, что дом имеет размер n х n. Из примера ввода и вывода мы видим, что: • Дом разделен на дае части: крышу и основание. ,,...... ...... , , крыша • • Когда nКогда n - основание четное число , крыша дома не острая. нечетное число, крыша острая и на порядок боль­ ше основания. Крыша • • Состоит из звездочек(*) и дефисов (черточек)(-). В верхней части находятся одна или две звездочки, в зави­ симости от того, является ли число n четным или нечетным (таюке связано с дефисами). • В нижней части много звездочек, а дефисов либо очень мало, либо их совсем нет. • С каждым очередным рядом количество звездочек увели­ чивается на две, а количество дефисов уменьшается на два. Основание • • • Состоит из n рядов. Сформировано из звездочек и вертикальных линий. Строки состоят из двух вертикальных линий, по одной в на­ чале и в конце строки, и звездочек между линиями с дли­ ной строки Мы считываем n - 2. n как параметр нашей функции: function drawHouse(n){ / / ... } Очень важно проверить, являются ли введенные даннь1е кор­ ректными! В этих задачах нет проблем с прямым преобразованием переданного параметра в Number, поскольку явно сказано, что мы получим действительные целые числа. Однако если вы занимае­ тесь более серьезными приложениями, проверить данные будет не лишним. Что произойдет, если вместо буквы «А» пользователь введет число?
Рисование более сложных фигур 273 Чтобы нарисовать крышу, мы поместим количество звездочек в переменной stars: Если n - четное число, оно • • будет равно Если нечетное, то будет равно 2. 1. let stars = 1; if (n % 2 === 0){ stars++; } Вычисляем длину крыши. Она равна половине результат в переменную n. Записываем roofLength: let rooflength = Math.ceil(parseint(n) / 2); Важно отметить, что когда n нечетное число, длина крыши больше длины основания. В JavaScript при делении двух целых чи­ сел с остатком результат будет дробным числом. Пример: let result = 3 / 2; // результат 1.5 Если мы хотим округлить результат в большую сторону, нам нуж­ но использовать метод маth . сеil ( ...): let result = Math . ceil(З / 2);. Результат з / 2 равен 1. 5. Math . ceil ( ... ) округлит результат деле­ ния в большую сторону. В нашем случае 1. 5 будет округлено до 2. parseint() используется для преобразования входного параметра в тип Number. По сле того как мы вычислили длину крыши, вьmолняем цикл от О до • rooflength. На каждой итерации мы будем: Вычислять количество черточек, которые нам нужно нари­ совать. Это число будет равно шем его в переменную (n padding: звездочки) / 2. Запи­ let padding = (n - stars) / 2; • Выводим в консоль: «черточки» (padding / 2 раза)+ «звездочки» (количество stars) + «черточки» (padding / 2 раза) : let line = ''-''.repeat(padding); line += ''* ''.repeat(stars); line += ''-''.repeat(padding); console . log(line); • Перед завершением итерации цикла добавьте ной stars += 2; stars (количество звездочек): 2 к перемен­
274 Глава Теперь пришло время для основания. 6.1 . Вложенные Его проще циклы вывести на экран: • Начнем с цикла от 0 до n (не включая). • Выведем в консоль: 1 + * (n - 2 раза) + 1- for (let i = 0; i < n / 2; i++) { let line = "1" + "*".repeat(n - 2) + console . log(line); " 1"; } Если мы все написали правильно, то наша задача решена. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/935#8. Пример: бриллиант Напишите программу, которая считывает целое число 100) и рисует бриллиант размера n (1 ~ n ~ n, как показано в следующих при­ мерах: Ввод 1 вывод Ввод 2 * вывод ** Ввод вывод 3 -**-* Ввод вывод 4 -***--* -**- -*- 1 Ввод Вывод 5 --*--*-**---* -*-*--*-- Рекомендации и советы Из условия задачи мы знаем, что бриллиант имеет размер n х n. Из примера ввода и вывода можно сделать заключение, что все строки содержат ровно n символов, и все строки, за исклю­ чением верхней и нижней, имеют по две звездочки. Мы можем мысленно разделить бриллиант на две части: • • Верхняя часть. Начинается от верхней точки до середины. Нижняя часть . Начинается с ряда ниже среднего и спуска­ ется до нижней точки (включительно). Верхняя часть • Если n- нечетное число, построение бриллианта начина­ ется с одной звездочки.
Рисование более сложных фигур • Если 275 четное число, построение начинается с двух звез­ n- дочек. • С каждым очередным рядом звездочки становятся все даль­ ше друг от друга. • Пространство между звездочками, до и после них заполня­ ется дефисами. Нижняя часть • С каждым рядом звездочки становятся ближе друг к другу. Это означает, что пространство (дефисы) между ними ста­ новится меньше, а пространство (дефисы) слева и справа - больше. • Самая нижняя часть имеет одну или две звездочки, в за­ висимости от того, является ли n четным либо нечетным числом. Верхняя и нижняя части бршzлианта • В каждом ряду, кроме среднего, звездочки окружены вну­ тренними и внешними дефисами. • В каждом ряду между двумя звездочками есть простран­ ство, кроме первого и последнего ряда (иногда здесь распо­ лагается только одна звездочка). Мы передаем значение n как входной параметр (аргумент) в функцию: function drawDiamond(n) { // ... } Начните рисовать верхнюю часть ромба. Первое, что нужно сде­ лать, - вычислить начальное значение внешнего числа дефисов leftRight (дефисы на внешней стороне звездочек). Оно равно ( n 1) / 2, округлим в меньшую сторону. Для округления мы будем ис­ пользовать метод Mat h . floo r ( ...) , чтобы удалить остаток от деления. Такой код может быть написан при введенном нечетном n: let leftRight = Math.floor((n - 1) / 2); Подсчитав количество внешних черточек leftRight, мы начи­ наем рисовать вершину ромба. Мы можем начать с цикла от 0 до
6.1. Глава 276 Вложенные циклы n / 2 + 1 (округление вниз). На каждой итерации цикла необходи­ мо выполнить следующие действия: • Нарисуйте в консоли левый дефис (длины leftRight) и сразу за ним первую звездочку: console.log("-".repeat(leftRight)); console.log("*"); • Вычислив расстояние между двумя звездочками. Вы­ числить его можно, вычтя из и число 2 (количе ство n длину внешних дефисов звездочек, то есть контур брилли­ анта). Результат этой разницы запишите в переменную mid: let mid • = n - 2 * leftRight - 2; Если значение mid меньше О, то мы знаем, что на линии должна быть одна звездочка. Если значение mid больше или равно О, то мы должны нарисовать дефисы длиной mid и одну звездочку после них. • Нарисуйте правую внешнюю черточку длиной leftRight: console.log("-".repeat(leftRight)); • В конце цикла уменьшите leftRight на 1 (звезд очки удаляются друг от друга) . Мы закончили работу с вер­ шиной. Отрисовка нижней части полностью аналогична отрисовке верх­ ней. Отличие состоит в том, что вместо того чтобы вместо уменьше­ leftRight на 1 в конце цикла мы будем увеличивать leftRight на 1 в начале цикла. Кроме того , цикл будет ния значения параметра ОТ0ДО(n - 1 ) / 2. Повторяющийся код считается плохой практикой, потому что его становится довольно сложно поддерживать. Представим, что у нас есть часть кода (например, логика построения линии из ромба) еще в нескольких местах и мы решили внести изменения. Для этого нужно будет пройтись по всем местам и внести изменения. Представим, что вам нужно использовать код не 1, 2 или 3 раза, а десятки раз. Справиться с этой проблемой можно с помощью функций. Более подробную информацию о них можно найти в Ин­ тернете или просмотреть главу 10. Если мы все написали правильно, то наша задача решена.
Что мы узнали из этой главы? 277 Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/935#9. Что мы узнали из этой главы? Мы узнали о методе repeat( ... ) для объектов String: let foo = ''* '' . repeat(10); Мы научились рисовать фигуры с помощью вложенных циклов for: for (let i = 1; i <= let stars = ""; п; i++) { for (let j = 1; j <= n; j++) { stars += * , 11 lt • } console.log(stars); } Упражнение: рисование фигур в веб-среде Теперь, когда мы познакомились с вложенными циклами и научились рисовать с их помощью фигуры в консоли, мы мо­ жем заняться еще более интересным делом: посмотреть, как ци­ клы можно использовать для рисования в веб-среде. Мы создадим веб-приложение, которое будет отображать числовой рейтинг (чис­ ло от О до 100) со звездочками. Такая визуализация часто встреча­ ется на сайтах электронной коммерции, в обзорах товаров, рейтин­ гах событий, рейтингах приложений и т. д. Не волнуйтесь, если вы не понимаете всего кода, как именно он сделан и как именно работает проект. Это нормально, мы сей­ час учимся писать код, мы еще не дошли до технологий веб-раз­ работки. Если у вас возникнут трудности с написанием проекта по описанным шагам, задайте вопросы на форуме softuni.bg/forurn. SoftUni: https://
Глава 278 Задание: рейтинги - 6.1. Вложенные циклы веб-визуализация Разработайте JаvаSсriрt-приложение для визуализации рейтин­ га (число от О до 100). Необходимо нарисовать от 1 до 10 звездочек (с половинками). Звездочки должны генерироваться с помощью цикла for. Ratings l.зs. . _ ___.l l Draw 1 Создайте в файловой системе пустую папку с именем «ratings». В ней мы создадим два файла и одну папку: • • index.html script.js • images (папка) Теперь добавим изображения звездочек (они входят в состав файлов заданий для этого проекта и могут быть загружены с сайта https://github.com/SoftUni/ Programming-Basics-Book-JS-BG/tree/master/ assets/chapter-6-1-assets). Вставьте картинки в папку images с помо­ щью copy/paste. Откройте файл index . html и введите следующий код: <! -- HTML Структура документа -- > <! DOCTYPE ht ml> <!- - HTMLS это тип документа -- > <html lang=''en''> <! -- Раздел Title, содержит описательные теги для контента -- > <head> <meta charset="UTF-8"> <meta name="viewport" content=''width=device-width, initial-scale=l.0''> <meta http-equiv="X-UA-CompatiЫe" content="ie=edge"> <! -- Имя документа-- > <tit le>Ratings</title> нашего
Упражнение: рисование фигур в веб-среде </head> <! -- Тело видит наш нашего приложения, пользователь 279 описывает содержимое, которое -- > <body> <! -- Заголовок на <hl>Ratings</hl> <!-- странице -- > Элементы для взаимодействия с -- > <input id="input-rating" type="number" name="input-rating" min="0" max= ''100 '' value= ''ЗS'' /> <input id="input-draw" type="button" name=''input-draw'' value=''Draw'' /> <! -- Новая строка -- > <br> пользователем <!-- Элемент, который содержит сгенерированный HTML со -- > <div id="ratingHolder"></div> звездочками <!-- Подключение файла с JavaScript <script src=''script.js''></script> </body> </html> кодом -- > Этот код создает поле жет ввести число в input-rating, в которое пользователь мо­ диапазоне [О ... 100], и кнопку [Draw], которая приводит к действию со звездочками. Действие, которое будет об­ рабатывать данные, называется водится содержимое <div drawRating. После поля ввода вы­ id="ratingHolder"></div>. Код, кото­ рый в ней будет содержаться, это динамически сгенерированный НТМL-элемент с серией звездочек. Мы добавляем функцию drawRating() в файл script.js, которая имеет следующий код: /** * drawRating, рисует HTML, * звезд * @param {Number} rating необходимый для визуализации
Глава 280 6.1. Вложенные циклы * @return {String} html */ func tion drawRating(rating) { // строка из html let html = ""; // конечное число звезд let allStars = 10; // все полные звезды let fullStars = Math.floor(rating / allStars); // все пустые звезды let emptyStars = Math.floor((100 - rating) / allStars); // все наполовину заполненные звезды let halfStars = allStars - fullStars - emptyStars; // построение HTML for (let i = 0; i < fullStars; i++) { html += '<img src=''images/full-star . png''>'; } for (let i = 0; i < halfStars; i++) { html += '<img src="images/half-star.png">'; } for (let i = 0; i < emptyStars; i++) { html += '<img src=''images/empty-star.png''>'; } / / возвращаем return html; готовый HTML } Приведенный выше код принимает введенное число rating, про­ изводит некоторые вычисления и рассчитывает количество пол­ ных звездочек, количество половинок звездочек и количество пу­ стых звездочек, затем генерирует НТМL-код, который расставляет несколько звездочек друг за другом, чтобы собрать конечную кар­ тинку рейтинга. Подготовленный НТМL-код возвращается как ре­ зультат работы функции и готов к дальнейшему использованию. В настоящее время результат этой функции не может быть исполь-
Упражнение: рисование фигур в веб-среде 281 зован, поскольку нет способа связать его с кнопкой. Мы вводим функцию drawHandler( ), которая содержит следующий код: /** * drawHandler, * нажимает на функция, которая выполняется, когда пользователь кнопку «Рисовать» . * @return {Void} */ function drawHandler() { / / найдите элемент ввода, который содержит // данные о количестве рейтинга let ratinginput = document.getElementByid("input-rating"); / / по умолчанию все значения из форм приходят в виде / / ''string'' --> преобразуем их в число с помощью "parseint()" let rating = parseint(ratinginput.value); // находим элемент, содержащий рейтинг let ratingHolder = document .getElementByid( "ratingHolder"); // генерируем HTML на основе введенного let html = drawRating(rating); / / отрисовка страницы ratingHolder . innerHTML = рейтинга html; } Функция • drawHandler() Находит выполняет несколько действий: НТМL-элемент, содержащий рейтинг (input- rating), и принимает его значение. • Преобразует значение из строки в число. • Находит НТМL-элемент, который будет содержать звездоч­ ки • (ratingHolder). Генерирует НТМL-изображение звездочек с помощью функ­ ции • drawRating( ...). Помещает сгенерированный с помощью метода HTML в элемент ratingHolder innerHTML. Нам нужна еще одна функция, чтобы объединить две вышепе­ речисленные и связать их с НТМL-элементами. Эта функция пазы-
Глава 282 вается appinit(), 6.1. Вложенные циклы и, как следУет из названия, ее роль заключает­ ся в запуске нашего приложения. Мы записываем сле,цующий код в функцию appini t ( ): !** * appinit, отвечающий за начальное выполнение нашей программы * @return {Void} */ func tion appinit() { // находим элемент button (кнопки) в HTML let button = document.getElementByid("input-draw"); // начинаем "слушать" событие "click" для // выполнения отрисовки button.addEventlistener(''click'', drawHandler); // начальная отрисовка рейтинга drawHandler(); } После того как мы установили все функции, пришло время за­ пустить наше приложение. Обратите внимание, что script . js включен в конец нашего файла, прямо перед закрывающим тегом </body> на странице. Это хорошая практика, которая позволяет ускорить загрузку дерева оом. Это также позволяет нам вьmолнять код JavaScript, использующий элементы HTML. При таких условиях мы можем быть уверены, что все они уже загружены в память бра­ узера. Однако вместо того чтобы вызывать appini t () непосредственно в конце файла, мы добавим еще одну хорошую практику: !** * Запуск приложения асинхронно, через ''event listener'' . * Прослушивание события "DOMContentloaded". */ document.addEventlistener("DOMContentloaded", appinit); Событие ooмcontent loaded гарантирует, что браузер завер­ шил создание всего дерева оом. Подключение к нему с помощью addEventlistener( ... ) гарантирует, что код JavaScript будет выпол­ нен правильно. Когда бр аузер будет готов, он выполнит нашу функцию запуска appinit().
Упражнение: рисование фигур в веб-среде 283 Результатом работы этой функции является: • Подключение функции на нашей кнопке • drawHandler() к событию click Draw. Первоначальный вызов функции drawHandler(), полнить звездочки рейтинга на основе текущего чтобы за­ HTML. Если у вас возникли проблемы с приведенным выше примером проекта, не стесняйтесь задавать вопросы на форуме softuni.bg/forurn. SoftUni: https://
Глава 6.2. Вложенные циклы - экзаменационные задачи В предыдущей главе мы рассмотрели вложенные циклы и их использование для рисования различных фигур на экране. Мы научились строить фигуры разных размеров, придумывая со­ ответствующую логику построения с использованием одиночных и вложенных циклов for в сочетании с различными вычисления­ ми и логикой программы: let result = ''''; for (let i = 0; i < 10; i++) { for (let j = 0; j < 10; j++) { result += * , 11 lf • console . log(result); result = ""; } Мы также познакомились с методом str . repeat ( count), кото­ рый позволяет выводить строку определенное количество раз: 'аЬс' .repeat(2); // 'аЬсаЬс' Экзаменационные задачи Теперь давайте вместе решим несколько экз аменационных за­ дач, чтобы закрепить пройденный материал и развить алгоритми­ ческое мышление. Задача: нарисовать крепость Напишите программу, которая считывает целое число крепость шириной n и рисует 2 * n столбцов и n строк в высоту, как показано
285 Задача: нарисовать крепость в примерах ниже. Левый и пр авый столбцы внутри имеют шири­ ну n/2. Входнь1е данные Входные данные пр ограммы состоят из одного элемента (аргу­ мента) - целого числа n в диапазоне [З ... 1000]. Въmод данных Выведите в консоль n текстовых строк, представляющих кр е­ пость, как в примерах. Примеры ввода и вывода Ввод Вывод Ввод 1 1 vv Ввод Вывод ;ллvлл\ /ЛЛ\/ЛЛ\ ;лvл\ 3 Вывод 4 1 1 1 1 1 5 1 1 1 1 \ _ / \_ / V - 1 V Рекомендации и подсказки Из постановки задачи видно, что вводимые данные будут состо ­ ять только из одного целого числа в диапазоне [З ... 1000], поэтому мы создаем функцию, принимающую в качестве аргумента массив string, а нам нужно используем конструкцию Number() в каче­ из одного элемента. Поскольку он имеет тип работать с числами, мы стве функции для его пр е обр азования: function drawFort([argl]){ let n = Number(argl); По сле того как мы объявили и инициализировали входные данные, нам нужно разделить крепость на три части: • • • крыша корпус основание Из примеров видно, что крыша состоит из двух башен и проме­ жуточной части. Каждая башня состоит из начала и конца\. /, середины л
Глава 286 6.2. Вложенные циклы - экзаменационные задачи При условии, что левый и правый столбцы внутри имеют шири­ ну n/2, мы можем выделить это значение в отдельную переменную, при этом следует учитывать, что если в качестве входных данных у нас будет нечетное число, то при делении на два результат будет представлять собой десятичное число с целой и дробной частью. Поскольку в данном случае нам нужна только целая часть (в ус­ ловии задачи мы видим, что количество л внутри столбца равно 1 для входа тода 3 и 3 для входа 5), мы можем отбросить ее с помощью ме­ Math. trunc () и сохранить только ее значение в нашей новой переменной: let colSize = Math.trunc(n/2); Хорошая практика - всякий раз, когда мы видим, что у нас есть вы­ ражение, значение которого мы будем использовать более одного раза, хранить его значение в переменной. Таким образом, с одной стороны, наш код будет легче читать, а с другой - легче исправлять в нем ошибки, поскольку нам не придется искать каждое использо­ вание выражения по отдельности. Мы таюке объявляем вторую переменную, в которой будем хра­ нить значение части междУ двумя башнями. По условию мы зна­ ем, что общая ширина крепости равна башни с одной косой чертой в начале и шириной n * 2. У нас таюке есть две и в конце (всего 4 символа) colSize. Поэтому, чтобы получить количество символов междУ ними, нам нужно вычесть размер башен из ширины всей * n - 2 * colSize - 4 . let midSize = 2 * n - 4 - colSize * 2; крепости:2 Чтобы вывести крышу в консоль, мы воспользуемся методом repeat ( n), который конкатенирует заданную строку n раз: let towerTop = "/" + "л".repeat(colSize) + "\\"; console.log(towerTop + "_".repeat(midSize) + towerTop); \- JavaScript, и если использо­ console. log( ...), то консоль не выведет \ \ мы показьmаем консоли, что хотим это специальный символ в языке вать только его в методе его, поэтому с помощью вывести этот символ, не интерпретируя его как специальный (мы экранируем его, в английском языке это назьmается «character escaping»).
Задача: бабочка 287 Корпус крепости состоит из начала странства) и конца *n- 2 2. 1, середины (пустого про­ 1- Середина пустого пространства имеет размер Количество рядов для стен мы можем определить из при­ веденных примеров: n - з: for (let row = 0; row < n-3; row++) { console . log( " I" +" ". r epeat(2 * n - 2) +"1 "); } Чтобы нарисовать предпоследнюю линию , которая является ча- стью основания, нам нужно вьmести сначала 1, середину (пробел)_ (пробел) и конец 1- Для этого мы можем использовать уже объяв­ ленные переменные colSize и midSize, поскольку из примеров видно, что они равны количеству_ в крыше: console . log( ''I '' + " " .repeat(colSize+l) + "_" .repeat(midSize) + '' ".repeat(colSize+l) + "1 " ); Мы прибавляем + 1 к значению пробелов, потому что в приме­ рах есть еще один пробел. Структура основания крепости такая же, как и крыши. Оно со­ стоит из двух башен и промежуточной части. У каждой башни есть начало \, середина _ и конец /. let towerBottom = "\ \ " + "_" . repeat (colSize) + "/ "; console.log(towerBottom +" " .repeat(midSize) + towerBot tom); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/936#0. Задача: бабочка n и рису­ ет бабочку шириной 2 * n - 1 столбцов и высотой 2 * (n - 2) + 1 Напишите программу, которая принимает целое число строк, как показано в примерах далее. Ее левая и правая стороны имеют ширину n - 1.
Глава 288 6.2. - Вложенные циклы экзаменационные задачи Примеры ввода и вывода Ввод вывод Ввод Вывод ***\ /*** - - -\ /- - *\ /* 3 ***\ /*** 5 @ @ ***/ \ ** * */ \* - - -1 \ -- - ***/ \*** Ввод Вывод 1*****\ /***** ----- \ / ----- *****\ /***** -- - - -\ / ----- *****\ /***** 7 @ *****/ \***** ----- / \ ----- *****/ \***** -- -- - / \ - - --- *****/ \***** 1 Входнъ1е даннъ1е Входные данные состоят из одного элемента (аргумента) го числа цело­ n в диапазоне [З ... 1000). Вывод даннъIХ Выведите в консоль 2 * ( n - 2 ) + 1 текстовых строк, изобража­ ющих бабочку, как в примерах. Рекомендации и подсказки Как и в предыдущей задаче, из условия мы видим, что входные данные будут состоять только из одного целого числа в диапаз оне [З ... 1000]. Создадим функцию, принимающую в качестве аргумен­ та массив из одного элемента. Поскольку он имеет текстовый тип (String), а нам нужно работать с числами, используем конструк­ цию Number ( ) в качестве функции для его преобразования: function butterfly ( [ar gl] ){ let n = Number (a r gl);
Задача: бабочка 289 Мы можем разделить фигуру на три части - верхнее крыло, тело и нижнее крыло. Чтобы нарисовать верхнее крыло бабочки, нам нужно разделить его на части нец *. - начало *,середину \/ и ко ­ Рассмотрев примеры, мы можем сказать, что верхнее крыло бабочки имеет размер n - 2: l et ha l fR01,ISize = Чтобы нарисовать верхнее крыло, мы создаем цикл, который по­ вторяется halfRowSize раз: for (let i = 1; i <= halfRowSize; i++) { } *, сере­ \ / и конец -. Из примеров также видно, что в четной строке есть начало дина \ / и конец *, а в нечетной - начало -, середина Поэтому на каждой итерации цикла нам необходимо вьmолнить про­ верку i f-else, является ли выводимая строка четной или нечетной. Из примеров, приведенных в условии, видно, что количество звездо­ чек и тире в каждой строке также равно пользовать переменную n - 2, то есть мы можем ис­ hal fRowSize для их повторного вывода: for (let i = 0 ; i < halfR01·JSize; i ++ ) { if(i % 2 == 1 ){ console.log(" - " .repeat(halfR01-JSize ) + "\\ " + + 11 11 ··1·· + " - ". r epeat ( hal fRoi-JSiz e )); } else { } } Чтобы нарисов ать тело бабочки, мы можем снова использовать переменную half RowSize и вывести в консоль ровно одну строку. Структура тела имеет начало ( nробел) , середину@ и конец (пробел). Из примеров видно, что количество пробелов равно n-1. console . log( " " . repeat(n - 1 ) + "@" +" ".repeat(n - 1) ) ;
Глава 290 6.2. Вложенные циклы - экзаменационные задачи Осталось только вывести в консоль нижнее крыло, которое ана­ логично верхнему: нужно только поменять местами косые черты. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/936#1. Задача: знак «STOP!» Напишите программу, которая принимает целое число n и рисует знак STOP! с размерами, как в примерах ниже. Входные даннъ1е Входные данные состоят из одного элемента (аргумента), целого числа n в диапазоне [3 ... 1000]. Вывод даннъIХ Выведите в консоль текстовые строки, изображающие знак STOP!, как в примерах. Ввод Вывод .... . . . . . . ./ / \ \ ... . ./ / \ \ .. . // \\ . / /- -STOP! - - \ \ \\ // //. .\\ . .\ \ / / .. 3 Ввод вывод ....... ....... . . . . . ./ / . . . . ./ / . . . ./ / . . ./ / . ./ / 6 . // // \\ . \\ .. \\ .. .\ \ . ...\ \ . ... .\ \ STOP! \ \ ...... \ \ ..... \\ .... \ \ ... \ \ .. \\ . \\ // // . / / .. / / ... / / .... / / .....
Задача: знак «STOP!» 291 Рекомендации и подсказки Как и в предыдущих заданиях, мы создаем функцию, кото­ рая принимает массив из одного элемента и использует для преобразования его из текстового типа Number() (String) в числовой: function stopSign([argl]){ let n = Number(argl); Мы можем разделить фигуру на три части - верхнюю, среднюю и нижнюю. Верхняя часть состоит из двух подчастей - начальной строки и строк, в которых символ расширяется. Начальная строка состоит из начальных точек в середине и точек .в ., символов _ конце. Посмотрев примеры, можно сказать, что начало имеет значение n + 1, и лучше выделить это значение в отдельную переменную: let dot s = Также необходимо создать вторую переменную, в которой мы будем хранить значение середины начальной стр оки размером 2 * n + 1: let underscores = 2 * n + 1; После того как мы объявили и инициализировали две перемен­ ные, мы можем вывести в консоль начальную строку: console. log ( '' . " . repeat(dots) + ''_".repeat(underscores) + "." . repeat(dots) ); Для того чтобы рисовать строки, в которых знак становится n раз. Структу­ \ \ \ и конца (. ). «шире», нужно создать цикл, который выполняется ра строки состоит из начала (. ), / / +середины_+ Для того чтобы можно было повторно использовать созданные пе­ ременные, необходимо уменьшить точки ния dots на 1и подчеркива­ underscores на 2, так как первую строку мы уже вывели, а коли­ чество точек и подчеркиваний в верхней части рисунка на каждой очередной строке уменьшается: underscores dots ; -= 2;
292 Глава 6.2. Вложенные циклы - экзаменационные задачи На каждой последующей итерации начало и конец уменьшают­ ся на 1, а середина увеличивается на 2: Средняя часть рисунка имеет начало // + _J нец_ +\ \ \. Количество подчеркиваний_равно середину STOP ! и ко­ (underscores - 5) / 2: Нижняя часть рисунка, где знак сужается, может быть вьшол­ нена путем повторного создания цикла, который осуществляется n раз. Структура строки - начало . + \ , середина _ и конец / / + •• Количество точек на первой итерации цикла должно быть равно О и увеличиваться на единицу на каждой последующей итерации. Поэтому можно сказать, что количество точек в нижней части ри­ сунка равно i. Чтобы наша программа работала корректно, необходимо на ка­ ждой итерации цикла уменьшать число _ на 2: for (let i = 0; i < n; i++){ console.log(''.". r epeat( i ) + " \\ \ \ " + "_".repeat(underscores) + " // " + " . " .repeat(i) ) ; underscores -= 2; }
Задача:стрелка 293 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/936#2. Задача:стрелка Напишите число n программу, которая принимает нечетное целое и рисует вертикальную стрелку с теми же размерами, что и в примерах ниже. Входнъ1е даннъ1е Вводится нечетное целое число n (аргумент) в диапазоне [З . .. 79]. Въmод даннъ~х Выведите в консоль вертикальную стрелку, в которой символ # используется для контура стрелки, а Примеры ввода и вывода Ввод вывод .###. . # . # . ##.## . # . # . . # . 3 . Ввод вывод . . . . .##### . . #. . # . . #. . # . . #. . # . ### . . ### . #. . # . . #. . # . . #.# . . # . . . 5 . . .. ... . . . . ... . . . . .. ... «. » - для всего остального.
Глава 294 Ввод 6.2. Вложенные циклы - экзаменационные задачи вывод . . . . ######### . . . . . . . . # ....... # . . . . • • • • # ••••••• # •••• . . . . # .. . . . . . # •..• • • • • # ••••••• # •••• . . . . # ....... # ... . . . . . # ....... # ... . . . . . # ....... # ... . ##### . . . . . . . # # # # # . # ..... . .....•. # . • • # ••••••••••• # •• . . . # ......... # . . . . . . . # ....... # . . . . . . • • • # ••••. # ••.•• . . . • . . # . .. # .••..• . . • • • • • # • # .•••.•• • • • • • • • • # •••••••• 9 Рекомендации и подсказки Как и в предыдущих заданиях, мы создаем функцию, которая принимает массив из одного элемента и с помощью образует Number() пре­ ero из текста в число: function drawArrow([argl]){ let n = Number(argl); Мы можем разделить фигуру на три части - верхнюю, среднюю и нижнюю. Верхняя часть состоит из двух подчастей - начальной линии и тела стрелки. Из примеров видно, что количество внеш­ (n - 1) / 2. Мы можем записать это значение в переменную outerDots: них точек в начальной строке и в теле стрелки равно let outerDots = (n - 1) / 2; Количество внутренних точек в теле стрелки равно нужно создать переменную innerDots, ( n - 2). Нам которая будет хранить это значение: let innerDots = n - 2; Из примеров видна структура начальной строки. Нам нужно использовать объявленные и инициализированные переменные outerDots и n, чтобы вывести начальную строку:
295 Задача:стрелка console . log('' . " . repeat(outerDots) + "#".repeat(n) + " . ".repeat(outerDots)); Чтобы нарисовать тело стрелки в консоли, нам нужно создать цикл, который повторяется n - 2 раза: for (let i = 0; i < n - 2; i++){ console . log(''." . repeat(outerDots) + ''#" + '' . ".repeat(innerDots) + "#11 + ''.".repeat(outerDots) ); } Середина фигуры состоит из начала личество# равно #, середины . и конца #. Ко­ outerDots + 1: console.log(''#''.repeat(outerDots + 1) + ''." . repeat(innerDots) + ''#''.repeat(outerDots + 1)); Чтобы нарисовать нижнюю часть стрелки, нам нужно задать но­ вые значения двум переменным outerDots innerDots = = outerDots и innerDots: 1; 2 * n - 5; На каждой итерации outerDots увеличивается на 1, а innerDots уменьшается на 2. Обратите внимание, что поскольку в предпослед­ ней строке значение innerDots будет равно 1, на последующих ите­ рациях цикла оно станет отрицательным. Если мы используем ме­ тод str . repeat ( count) с отрицательным числом, наша программа выдаст ошибку. Один из вариантов избежать этого - выводить по­ следнюю строку рисунка отдельно. Высота нижней части стрелки равна n - 1, поэтому цикл, кото­ рый будет вьmодить все строки, кроме последней, должен быть вы­ n - 2 раза: for (let i = 0; i < n - 2; i++){ console.log('' .".repeat(outerDots) + полнен "#11 + "." . repeat(innerDots) +
Глава 296 6.2. Вложенные циклы - экзаменационные задачи "#11 + '' . ".repeat(outerDots)); outerDots ++; innerDots -= 2; } Последняя строка нашего рисунка состоит из начала ны# и конца . , середи­ . . Количество . равно outerDots: console.log(''.".repeat(outerDots) + "#11 + '".".repeat(outerDots)); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/936#3. Задача:топор Напишите программу, которая принимает целое число n и рису­ ет топор с размерами, показанными далее. Ширина топора равна s * n столбцов. Входнъ1е даннъ1е Входные данные состоят из одного элемента (аргумента) го числа n в диапазоне цело- [2 . . 42]. Вывод данных Вывести топор в консоль, как в примерах. Примеры ввода и вывода Ввод Вывод Ввод Вывод ---------------* *-------- 2 ------**-------*-********-*------***- 5 * * ---------------*--*------- - --- - -- - --- - -*- - -*-- - ----------------*----*---- *** ******** *****----*---* * * * * * * * * * * * * * * * ----* ---- - -- - -- - -- - - -- - - * - - - - * - - - - --------------* * * * * * * *
Задача: топор 297 Ввод Вывод ------------------------**-------------------------------------*-*------------------------------------*--*-----------------------------------*---*----------------------------------*----*---------------------------------*-----*--------------------- -----------*- ----- *-------------------------------*-------*------- 8 *************************-------*------************************* ------- *------*************************-------*------*************************-------*------- ------------------------*-------*-----------------------------*---------*------ ----------------------*-----------*-------------------------****** ********* ---- Рекомендации и подсказки Для решения задачи нам сначала нужно р ассчитать количество черточек слева, черточек посередине, черточек справа и всей дли­ ны фигуры: let let let let width = 5 * n; leftDashes = 3 * n; middleDashes = 0; rightDashes = width - leftDashes - middleDashes - 2; После объявления и инициализации переменных можно при­ ступать к рисованию фигуры, начиная с вершины. Из примеров мы можем понять структуру первой строки и создать цикл, кото­ рый повторяется n раз. На каждой итерации цикла количество деф исов в середине увеличивается на справа уменьшается на 1, а колич ество дефисов 1: for (let i = 0 ; i < п; i++){ console . log( ''-'' .repeat(leftDashes) + "*" + "-".repeat (middleDashes) +
Глава 298 6.2. Вложенные циклы - экзаменационные задачи " "' " + " - " .repeat(rightDas hes ) ) ; } Теперь необходимо нарисовать рукоятку топора. Для того что­ бы можно было повторно использовать переменные, созданные при рисовании рукоятки топора, нужно уменьшить количество дефисо в в середине на на 1, а количество дефисов справа увеличить 1: middleDashes ,. rightDashes++; leftDashes++; Мы можем нарисовать рукоятку топора, выполнив цикл n/2 раз. Это значение можно выделить в отдельную переменную, пом­ ня о том, что если в качестве входных данных у нас будет нечет­ ное число, то при делении на 2 мы получим вещественное число с целой и дробной частью. Поскольку в данн ом случае нам нужна только целая часть (из условия задачи видно, что при вводе равна 2), 5 ширина мы можем использовать метод рукоятки топора Math. t runc (), чтобы со­ хранить только ее значение в нашей новой переменной. Из примеров мы можем видеть, каковы габариты рукоятки: axeHeight = Math.trunc(n / 2); for (let i = 0; i < axeHeight; i++) { console . log("*".repeat(leftDashes) + "- ". repeat(middleDashes) + "*" + '' - '' .repeat(rightDashes) ) ; } Нижнюю часть фигуры нам нужно разделить на две подча­ сти - «голову» топора и последнюю строку фигуры. Мы вы­ ведем в консоль «голову» то пора, создав цикл, повторяющий axeHeight - 1 р аз . На каждой итер ации количество де фисов слева и справа умень­ шается на 1, а количество средних дефисов увеличивается на 2:
299 Задача: топор leftDashes - - ,. middleDashes += 2; leftDashes--; rightDashes--; } Для последней строки рисунка мы снова можем использо­ вать три уже объявленные и инициализированные переменные leftDashes, middleDashes,rightDashes. Проверка в системе Judge Проверьте свое решение : Index/936#4. https://judge.softuni.bg/Contests/Practice/
Глава 7.1. Более сложные циклы Теперь, когда мы узнали, что такое цикл for и что он делает, мы познакомимся с другими типами циклов, а таюке с некоторы­ ми более сложными конструкциями циклов. Это расширит наши знания и поможет решать более сложные и трудные задачи. В част­ ности, мы рассмотрим, как использовать сле,цующие конструкции программирования: • • • цикль1 с определенным шагом • бесконечные цикль1 while циклы do-while циклы В этой главе мы таюке узнаем, что такое оператор break и как с его помощью прервать цикл. Циклы с шагом В главе «Цикль1» мы узнали, как работает цикл for, и теперь зна­ ем, когда и для чего его использовать . В этой главе мы сосредото­ чимся на одной конкретной и очень важной части его конструк­ ции, а именно на шаге. Что такое шаг? Шаг - это часть конструкции цикла for, которая определяет, на сколько нужно увеличить или уменьшить значение его пере­ менной-счетчика . Он объявляется последним в теле цикла Чаще всего шаг имеет размер i += 1 или i -= 1 1, и в этом случае вместо записи можно использовать операторы Если мы хотим, чтобы размер шага был не используем оператор i += for. (размер 1, i++ или i--. то при увеличении шага), а при уменьшении -
Циклы с шагом 301 i -= (размер шага). При шаге 3 цикл будет выглядеть следующим образом: let n = parselnt(argl); for (let i = 1 ; i < n; i += 3) { console . log(i); t } Установка шага Ниже приведена серия примеров задач, решение которых помо­ жет нам лучше понять использование шага в цикле Пример: числа for. 1 ...N с шагом 3 Напишите программу, которая выводит на экран числа от 3. Например, 10, ..., 94, 97, 100. с шагом если n = 100, то результат будет таким: 1 до n 1, 4, 7, Мы можем реllШть эту задачу, используя следующую последова- тельность действий (алгоритм): • Создаем функцию, которая будет принимать число • • Выполняем цикл n. for от 1 до n с размером шага 3. В теле цикла выводим значение текущего шага . / / при i+=З мы увеличиваем значение i function loopByStepЗ([argl]) { let n = parselnt(argl); for (let i = 1; i <= n; i+=З) { console.log(i); на величину шага (3) } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#0. Пример: числа от N до 1 в обратном порядке Напишите программу, которая выводит числа от ном порядке (шаг -1). Например, если ким: 100, 99, 98, ... , дующим обр азом: з, n = n до 1 в обрат­ 100, то результат будет та­ 2, 1. Мы можем решить эту задачу сле­
Глава 302 7.1. Более сложные • Создаем функцию, которая будет принимать число п. • В ней выполняем цикл • Меняем условие цикла на противоположное: • Определяем размер шага: • В теле цикла выводим значение текущего шага. for, присваивая let i циклы = п. i >= 1. -1. // Обратное условие: i >= 1 // Шаг уменьшения: i -= 1 function numbersNtol([argl)) { let п = parselnt(argl); for (let i = п ; i >= 1; i -= 1) { console . log(i); } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#1. Пример: числа от 1 до z лn с помощью цикла for В следующем примере мы рассмотрим, как использовать обыч­ ный размер шага 1. Н апишите программу, которая выводит числа от 1 до 2 лп (два в степени п). Например, если п = 10, то результатом 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024. будут числа 1, function powersOfTwo([argl]) { let п = parselnt (argl); let num = 1; for (let i = 0; i <= console . log(num); num = num * 2; п; i++) { } } Проверка в системе Judge Проверьте свое решение: Index/937#2. https://judge.softuni.bg/Contests/Practice/
Цикл While 303 Пример : четнъ1е степени Выведите четные степени 2 ... , 2лn. Например, если n = 10, то результатом будут 1, 4, 16, 64, 256, 1024. Вот как мы можем решить эту задачу: • • 2 до 2лn: 2л0, 2л2, 2л4, 2лs, Создаем функцию, которая будет принимать число n. Для текущего числа объявляем переменную которой num, • 1. Для шага цикла задаем значение 2. • В теле цикла: выводим значение текущего числа и увели­ присваиваем начальное значение чиваем текущее число num в 4 раза (по условию задачи). function evenPowersOfTwo([argl]) { let n = parseint(argl); let num = 1; for (let i = 0; i <= n; i+=2) { console.log(num); num = num * 2 * 2; } } Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#3. Цикл While Следующий тип циклов, который мы рассмотрим, называется циклом while. Их особенность в том, что они повторяют блок ко­ манд до тех пор, пока не будет вьmолнено условие. По структуре они отличаются от циклов for, но имеют более простой синтаксис. Что такое цикл while? В программировании цикл while используется, когда мы хотим повторять выполнение определенной логики до тех пор, пока вы­ полняется условие. Под условием мы понимаем любое выражение, которое возвра­ щает true или f alse. Когда условие становится ложным, цикл while
Глава 304 7. 1. Более сложные циклы прерывает свое вьmолнение, и программа продолжает выполне­ ние кода после цикла. Конструкция цикла while выглядит следующим образом: Конструкция цикла while ___ __1 Условие whi l e( ... ) { console.log("I am } а while loop."); r Тело цикла Ниже приведена серия примеров задач, решение которых помо­ жет нам лучше понять использование цикла Пример : последовательность чисел while. 2k+1 Напишите программу, которая выводит все числа ::;; n в последо­ вательности: 1, 3, 7, 15, 31, ..., предполагая, что каждое последующее число = предыдущему числу * 2 + 1. Вот как можно решить эту задачу: • Для текущего числа мы создаем переменную присваиваем начальное значение num, 1. • Для условия цикла задаем текущее число<= • В теле цикла выводим значение текущего числа и увеличи­ n. ваем текущее число по формуле из условия задачи. Приведем пример реализации описанной идеи: func t ion sequence([argl]) { let n = parseint(argl); let num = 1; while (num <= n) { console.log(num); num = 2 * num + 1; } } которой
Цикл While 305 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#4. Пример : число в диапазоне [1 ... 100] Введите целое число в диапазоне [1 .. . 100]. Если введенное чис­ ло недействительно, введите его еще раз. В этом случае недопусти­ мым будет считаться любое число, не входящее в указанный диа­ пазон. Для решения этой задачи можно использовать следующий алгоритм: • Объявляем переменную i, которой присваиваем начальное значение О. Мы будем использовать ее для хранения пози­ ции каждого числа, передаваемого в функцию. • Объявляем переменную num, которой присваиваем целочис­ ленное значение первого аргумента, передаваемого функции. • Для условия ЦИЮiа подставляем выражение, которое будет истинным (true), если число не находится в диапазоне, ука­ занном в условии. • В теле ЦИЮiа: инкрементируем цикле взять следующее i , чтобы при следующем число, переданное функции. Мы выводим в консоль сообщение «Invalid number!», тем присваиваем новое значение num а за­ (следующему аргу­ менту, переданному функции). После проверки числа мы выводим его значение за пределы тела цикла. Вот пример реализации алгоритма с использованием цикла while: function numberinRange(args) { let i = 0; let num = parseint(args[i]); while (num < 1 11 num > 100) { i++; console.log("Invalid number!"); num = parseint(args[i]); } console . log('The number is: ${num}' ); }
Глава 306 Более сложные циклы 7. 1. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#5. Наибольший общий делитель (НОД) Наибольший общий делитель (НОД, или GCD - Greatest Common Divisor) широко используется в математике и теории чисел. В этой главе мы научимся его вычислять. Определение НОД: наибольший общий делитель двух натураль­ ных чисел а и ь - это наибольшее число, на которое без остатка делятся и а , и Ь. ь а НОД а 1 ь НОД а ь нод 1 24 16 8 12 24 12 10 10 10 67 18 1 15 9 3 100 88 4 Евклидов алгоритм В следующей задаче мы воспользуемся одним из первых опу­ бликованных алгоритмов нахождения НОД - алгоритмом Ев­ клида . Пока не достигнем остатка О: • • Делим большее число на меньшее. Берем остаток от деления. Псевдокод алгоритма Евклида : while Ь * 0 oldB = Ь Ь = а %Ь а= oldB print а Пример : нахожде1mе наибольшего общего деJШтеля (ПОД, GCD) Введите целые числа а и ь и найдите НОД (а, Ь). Решим задачу с помощью алгоритма Евклида: • Создаем переменнь1е а и Ь, которым присваиваем целочис­ ленные значения, взятые из консольного ввода.
Цикл Do-while • 307 В качестве условия цикла задаем выражение, которое будет истинным, если число ь отлично от О. • В теле цикла следуем инструкциям из псевдокода: о Создаем временную переменную, которой присваиваем текущее значение ь. о Присваиваем новое значение ь, которое является остат­ ком от деления а и Ь. о Переменной а присваиваем предьIДуЩее значение пере­ менной ь. • Когда цикл завершен и мы нашли над (GCD), мы выводим его на экран. function greatesCommonDivisor([argl, arg2]) { let а= parseint (argl ) ; let Ь = parseint (arg2); while (Ь !== 0) { let oldB = Ь; Ь =а% Ь; а= oldB; } console . log("GCD ="+а); } Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/937#6. Цикл Do-while Следующий цикл, который мы рассмотрим - do-while, что пе­ реводится как «делать до тех пор, пока». По структуре он похож while, но между ними есть существенное различие . Оно заклю­ чается в том, что do-while выполнит тело цикла как минимум один раз. Почему так происходит? При построении цикла do-while усло­ на вие всегда проверяется после его тела, а это, в свою очередь, гаран­ тирует, что при первом запуске цикла код будет выполнен в любом случае, а проверка условия завершения цикла будет применяться к каждой последующей итерации do-while.
Глава 308 7. 1. Более сложные циклы Конструкция do .. while цикла ,,,,,,,. do { console. log( "I am а do...while loop . "); } while ( ... ) ~-------~ Условие Далее следует серия примеров задач, решение которых поможет нам лучше понять цикл do - while. Пример: вычисление факториала n необходимо вычислить n ! = 1 * 2 * если n = s, то результат будет таким: s ! = Для натурального числа * з * ... * n. Например, = 1 * 2 * 3 * 4 * 5 = 120. Вот как можно вычислить факториал: • Создаем переменную n, которой присваиваем целое значе­ ние; взятое из консольного ввода. • Создаем еще одну переменную - которой равно 1. fact, начальное значение Мы будем использовать ее для вычисле­ ния и хранения факториала. • n > 1, так как при ка­ ждом вьmолнении вычислений в теле цикла знач ение n бу­ дет уменьшаться на 1. • В теле цикла: В качестве условия цикла используем о Присваив аем f act новое значение, которое является ре­ зультатом умножения текущего значения щее значение о • f act на теку­ n. Уменьшаем значение n на 1. За пределами тела цикла выводим итоговое значение фак­ ториала. func t ion fac t orial([argl]) { let n = parse!nt(argl); let fact = 1;
Цикл Do-while 309 do { fact = fact * n; n--; } while ( n > 1); console . log(fact); } Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/937#7. Пример : сложение цифр числа Необходимо суммировать цифры целого положительного числа n. Например, eCJП:I n =5634, то результат будет таким: 5 + 6 + 3 + 4 =18. Для решения этой задачи мы можем использовать следующую идею: • Создаем переменную n, которой присваиваем значение, равное числу, введенному пользователем. • Создаем вторую переменную - sum, начальное значение которой равно О. Мы будем использовать ее для вычисле­ ния и хранения результата . • В качестве условия цикла будем использовать n > 0, так как после каждого вычисления результата в теле цикла мы будем удалять последнюю цифру • n. В теле цикла : о Присваиваем сумме sum новое значение, которое явля­ ется результатом сложения текущего значения следней цифрой числа о с по­ n. Присваиваем новое значение n, которое является ре­ зультатом удаления последней цифры из • sum n. За пределами тела цикла выводим итоговое значение суммы. function sumDigits([argl]) { let n = parseint(argl); let sum = 0;
Глава 310 7. 1. Более сложные циклы do { sum = sum + (n % 10); n = Math.floor(n / 10); } while (n > 0); console.log( 'Sum of digits: 1 11 + sum); } n % 10: возвращает последнюю цифру числа n. Math. floor ( n / 10): удаляет последнюю цифру числа n. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#8. Бесконечные циклы и оператор break До сих пор мы знакомились с различными типами циклов, изу­ чали их конструкции и области применения. Далее мы узнаем, что такое бесконечный цикл, когда он возникает и как можно пре­ рвать его вьmолнение с помощью оператора break. Бесконечньm цикл. Что это такое? Бесконечным циклом называется цикл, который бесконечно по­ вторяет выполнение своего тела. В циклах while и do-while провер­ ка завершения представляет собой условное выражение, которое всегда возвращает true. Бесконечный цикл отсутствии условия завершения. Вот как выглядит бесконечный цикл while(true) { console . log("Infinite loop"); } Так выглядит бесконечный цикл for ( ; ; ) { console . log( 'Infinite loop 1 } 11 ); for: while: for возникает при
Бесконечные циклы и оператор Оператор break 311 break Мы уже знаем, что бесконечный цикл выполняет определен­ ный код до бесконечности, но что будет, если мы захотим принуди­ тельно выйти из цикла в какой-то момент при заданном условии? На помощь приходит оператор break, то есть оператор остановки, или прерывания. Оператор break останавливает выполнение цикла в момент его вызова и продолжает его с первой строки после конца цикла. Это означает, что текущая итерация цикла не будет доведена до конца, а значит, и остальной код в теле цикла не будет выполнен. Пример: простые числа В следующей задаче нам необходимо проверить наличие про­ стого числа. Прежде чем приступить к ее решению, давайте вспом­ ним, что такое простые числа. ОпределеIШе: целое число является простым, если оно делится без остатка только на себя и на 1. По определению, простые числа положительны и больше 1. Наименьшее простое число - 2. Можно считать, что целое число n является простым, если n > 1 и n не делится на число от 2 до n-1. Первые несколько простых чисел: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, ... Напротив, непростые (составные) числа - это те числа, состав которых состоит из произведения простых чисел. Вот несколько примеров составных чисел: • 10 = 2 * 5 • 42 = 2 *3* 7 • 143=13*11 Алгоритм проверки того, является ли целое число простым: про­ веряем, корректно ли выражение n > 1 и делится ли n на 2, 3, ..., n-1 без остатка. • • Если оно делится на любое из этих чисел, то оно составное. Если оно не делится ни на одно из чисел, то оно простое. Мы можем оптимизировать алгоритм, проверяя делители до (корня от n) вместо майте, почему. того, чтобы проверять делители до vn n-1. Поду­
Глава 312 7.1. Более сложные циклы Пример: проверка на наличие простого числа. Оператор break Необходимо проверить, является ли число n простым. Для этого проверим, делится ли n на числа от 2 до ✓п. Вот алгоритм проверки простого числа, расписанный по шагам: • Объявляем переменную n, которой присваиваем целое чис­ ло, передаваемое в функцию. • Создаем булеву переменную true. prime с начальным значением Мы предполагаем, что число является простым, пока не доказано обратное. • Создаем цикл for, начальное значение переменной-счет­ чика цикла которого равно значение<= • 2, при условии, .Jn. Шar цикла равен 1. В теле цикла проверяем, есть ли у что ее текущее n, деленного на текущее значение, остаток. Если остатка от деления нет, меняем зна­ чение переменной prime на false и принудительно выхо­ дим из цикла с помощью оператора • В зависимости от значения ли число простым (true) break. prime выводим, или составным ственно. Вот пример реализации описанного алгоритма: function isPrime([argl]) { let n = parse!nt(argl); let prime = true; for (let i = 2; i <= Math.sqrt(n); i++) { if (n % i === 0) { prime = false; break; } } if (prime && n > 2) { console.log(''Prime'' ); } else { console.log(''Not prime''); } } (false) является соответ­
Бесконечные циклы и оператор break 313 Нам еще нужно добавить проверку на то, что вводимое число больше 1, потому что по определению числа О, 1, -1 и -2 не являют­ ся простыми. Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/937#9. Пример: оператор break в бесконечном цикле Напишите программу, которая проверяет, является ли число n четным, и если является, то выводит его на экран. Четным счита­ ется число, которое делится на 2 без остатка. Если число неверное, вернемся к повторному вводу и выведем сообщение о том, что вве­ денное число не является четным. Вот идея, как можно решить эту задачу: • Объявляем переменную i, которой присваиваем начальное значение О. Мы будем использовать ее для хранения пози­ ции каждого числа, передаваемого в функцию. • Объявляем переменную num, которой присваиваем началь­ ное значение О . • Создаем бесконечный цикл на • while, устанавливая условие true. В теле цикла : о Берем целое значение, переданное в функцию, и при­ сваиваем его num. break. о Если число четное, выходим из цикла с помощью о В противном случае выводим сообщение о том, что чис­ ло не четное. Мы увеличиваем i, чтобы при следующем цикле взять следующее число, переданное в функцию. Итерации продолжаются до тех пор, пока не будет вве­ дено четное число. • Четное число выводим на экран. Вот пример реализации этой идеи: function enterEvenNumber(args) { let i = 0; let num = 0;
Глава 314 7.1. Более сложные циклы while (true) { num = parseint(args[i]); if (num % 2 == 0) { break; // even number - > exit from the loop } console . log( ''The number is not even . "); i++; } console.log('Even number entered: ${num}'); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#10. Вложенные циклы и оператор break Теперь, когда мы узнали, что такое вложенные циклы и как ра­ ботает оператор break, пришло время понять, как они работают вместе. Для лучшего понимания давайте напишем пошаговую программу, которая должна составить все возможные комбина­ ции из пар чисел. Перв ое число комбинации увеличивается от до 3, а второе - уменьшается от З до няться до тех пор, пока И i 1. 1 Задача должна выпол­ + j не станут равны 2 (то есть i = 1 j = 1). Желаемый результат: 1 3 1 2 Вот неправильное решение, которое на первый взгляд кажется верным: function combinations( ) { for (let i = 1; i <= З; i++) { for (let j = З; j >= 1; j- - ){ if (i + j === 2){ break; }
Вложенные циклы и оператор break 315 console . log(i + '' '' + j); } } } Если мы оставим нашу программу в таком виде, то результат будет следующим: 1 1 2 2 2 3 3 2 3 2 1 3 3 2 3 1 Почему так получилось? Как мы видим, в результате не хвата­ ет «1 1». Когда программа доходит до точки, где i = 1 и j = 1, она входит в проверку if и вьmолняет операцию break. При этом проис­ ходит выход из внутреннего цикла, но продолжается вьmолнение внешнего цикла. По мере роста i программа входит во внутренний цикл и выводит результат. Когда мы используем оператор break во вложенном цикле, он пре­ рывает вьmолнение только внутреннего цикла. Каково правильное решение? Одним из способов решения этой задачи является объявление переменной bool, которая отслежива­ ет, должен ли цикл продолжать повторяться. Когда требуется выход (выход из всех вложенных циклов), переменная меняет свое зна­ чение на true и выходит из внутреннего цикла с помощью break, а при последующей проверке выходит из внешнего цикла. Вот при­ мер реализации этой идеи: function combinations () { let hasToEnd = false; for (let i = 1; i <= 3; i++) { if (hasToEnd === false) { for (let j = 3; j >= 1; j -- ) { if (i + j === 2) { hasToEnd = true;
Глава 316 7. 1. Более сложные циклы break; } console.log(i +" "+ j); } } } } Таким образом, когда i + j = 2, программа сделает hasToEnd = true и выйдет из внутреннего цикла. В следующий раз, когда внеш­ ний цикл вернется через условный опер атор i f, программа не смо­ жет добраться до внутреннего цикла и прервет выполнение. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#11. Задачи с циклами В этой главе мы познакомились с несколькими новыми типами циклов, которые можно использовать для создания итераций с бо­ лее сложной логикой программирования. Давайте решим несколь­ ко задач, используя эти новые знания. Задача: числа Фибоначчи Числа Фибоначчи в математике образуют ряд, который выгля­ дит следующим образом: 1, 1, 2, 3, 5, 8, 13, 21, 34, .... Формула для формирования ряда имеет вид: F0 Fl Fn = = = 1 1 Fn-1 + Fn-2 Пр имеры ввода и вывода Ввод ( n) Вывод Коммента рий Ввод ( n) вывод 10 89 F(11) = F(9) + F(8) 0 1 5 8 F(S) = F(4) + 1 1 20 10946 F(20) = F(19) + F(18) F(З ) Введите целое число n и вычислите n-e число Фибоначчи.
Задачи с циклами 317 Рекомендации и подсказки Идея решения задачи: • Объявляем переменную n, которой присваиваем целое зна­ чение, передаваемое в функцию. • Создаем переменные f0 и fl, которым присваиваем значе­ 1, так как именно с этого начинается ряд. Создаем цикл for с условием, что текущее значение i < n - 1 . ние • • Внутри цикла: о Создаем временную переменную fNext, которой при­ сваиваем следующее число в последовательности Фибо­ наччи. fl переменной f0. о Присваиваем текущее значение о Присваиваем значение временной переменной fNext числуfl. • За пределами цикла выводим n-e число Фибоначчи. При­ мер реализации: function fibonacci([argl]) { let n = Number(argl); let f0 = 1; let fl = 1; for (let i = 0; i < n - 1; i++) { let fNext = fo + fl; f0 = fl; fl = fNext; } console.log(fl); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#12. Задача: пирамида из чисел Выведите числа 1 ... n в виде пирамиды, как показано в приме­ рах ниже. В первой строке выводим одно число, во второй - два,
Глава 318 в третьей - 7. 1. Более сложные циклы три и так далее, пока числа не закончатся. В последней строке мы выводим столько чисел, сколько осталось, пока не до­ стигнем n. Пример ввода и вывода Ввод вывод 1 2 3 4 5 6 7 Ввод 5 7 вывод 1 2 3 4 5 Ввод Вывод 10 1 2 3 4 5 6 7 8 9 10 Рекомендации и подсказки Мы можем решить задачу с помощью двух вложенных циклов (по строкам и столбцам) с выводом в них и выходом при дости­ жении последнего числа. Теперь распишем эту идею более под­ робно: • Объявляем переменную n, которой присваиваем целое зна­ чение, передаваемое в функцию. • Объявляем переменную num с начальным значением 1. В ней будет храниться количество напечатанных чисел. На каждой итерации мы будем увеличивать ее на 1 и добав­ лять к текущей строке. • Объявляем переменную resul t , которая будет текущей строкой и к которой мы добавим значение текущей ячейки. • Создаем внешний цикл for, который будет отвечать за стро­ ки в таблице. Назовем переменную-счетчик цикла и установим ее начальное значение равным условия ставим • 1. row В качестве row < n. Размер шага равен 1. Внутри цикла создаем цикл for, который будет отвечать за столбцы таблицы. Назовем переменную-счетчик цикла col 1. В ка­ col < row (row = количество строке) . Размер шага равен 1. цифр и установим ее начальное значение равным честве условия ставим в
Задачи с циклами • 319 В теле вложенного цикла: о Проверяем, что в переменную col > 1, если да -добавляем расстояние resul t. Если не делать эту проверку, а до­ бавить расстояние напрямую, то в начале каждой стро­ ки будет лишняя единица. о Сохраняем ем его на о 1. Выполняем проверку на то, что ше • num в текущей ячейке таблицы и увеличива­ num > n. Если num боль­ n, мы прерываем внуrренний цикл. Выводим значение переменной resul t , а затем устанавли­ ваем ее в новое пустое значение. Таким образом мы перей­ дем к следующей строке. • Снова проверяем, больше ли num > n. Если больше , то пре­ рываем выполнение программы с помощью функции break. Вот пример реализации: function numberPyramid((argl]) { let n = parseint(argl); let num = 1; let result = " " ,. for (let row = 1; row <= n; row++) { for (let col = 1; col <= row; col++) { if ( col > 1) { resul t += " "; } result += num; num++; if (num > n) { break; } } console.log(result); result = ,. 11 •
Глава 320 if 7. 1. Более сложные циклы (num > n) { break; } } } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/937#13. Задача: табJШца чисел Выведите числа 1 ... n в виде таблицы, как показано в примерах ниже. Примеры ввода и вывода Ввод Вывод Ввод 1 2 3 2 3 2 3 2 1 3 Вывод 1 2 3 2 3 4 З 4 З 4 3 2 4 4 3 2 1 1 Рекомендации и подсказки Мы можем решить задачу с помощью двух вложенных циклов и некоторых вычислений в них: • Берем размер таблицы из целочисленной переменной n, ко­ торая передается в функцию . • Объявляем переменную result, которая будет текущей строкой и к которой мы добавим значение текущей ячейки. • Создаем цикл цы. Назовем for, который будет отвечать за строки табли­ переменную-счетчик цикла row и установим ее начальное значение равным О. В качестве условия ста­ вим • row < n. Размер шага равен 1. Внутри цикла создаем вложенный цикл for, который бу­ дет отвечать за столбцы таблицы. Н азовем переменную­ счетчик цикла col и установим ее начальное значение
Задачи с циклами 321 равным О. В качестве условия ставим равен • col < n. Размер шага 1. В теле вложенного цикла: о Создаем переменную num, которой присваиваем ре­ зультат текущей строки+ текущего столбца+ 1 (+1, так как мы начинаем считать с О). о Проверяем, верно ли выражение больше n, присваиваем удвоенному n- num num Если num новое значение, равное текущему значению для того, чтобы не превысить > n. n ни в num. Это делается одной из ячеек та­ блицы. □ Добавляем число из текущей ячейки в перемен­ result. Выводим значение resul t, а ную • затем устанавливаем его в но­ вое пустое значение. Таким образом мы перейдем к следу­ ющей строке. function numberTaЬle([argl]) { let n = parseint(argl); let result = ''''; for (let row = 0; row < n; row++) { for (let col = 0; col < n; col++) { let num = row + col + 1; if ( num > n) { num = 2 * n - num; } result = result + num + '' ''; } console.log(result); result = ""; } } Проверка в системе Judge Проверьте свое решение: Index/937#14. https://judge.softuni.bg/Contests/Practice/
Глава 322 7.1. Более сложные циклы Что мы узнали из этой главы? Мы можем использовать циклы for (let i = 1; i <= n; console.log(i); i+=З) for с шагом: { } Циклы while/do-while повторяются до тех пор, пока вьmолняет­ ся условие: let num = 1; while (num <= n) { console.log(num++); } Если нам нужно прервать выполнение цикла, мы делаем это с помощью оператора break: let n = 0; while (true) { n = parseint(argl); if (n % 2 === 0) { break; / / четное число-> выход из цикла } console.log( ''The number is not even." ) ; } console.log('Even number entered: ${num}');
Глава 7.2. Более сложные циклы - экзаменационные задачи Мы уже узнали, как можно выполнить блок инструкций более одного раза с помощью цикла for. В предыдущей rлаве мы рассмо­ трели еще несколько конструкций циклов, которые моrут помочь нам в решении более сложных задач, а именно: • • пошаговые циклы • ЦИКЛЬI • ЦИКЛЬido-while • бесконечные циклы и выход из цикла (оператор вложенные циклы while break) Экзаменационные задачи Закрепим полученные знания, решив несколько более слож­ ных задач с циклами, которые даются на вступительных экзаменах в университет SoftUni. Задача: генератор паролей Напишите программу, которая принимает на входе два целых числа п и k и генерирует в алфавитном порядке все возможные па­ роли, состоящие из следующих пять символов: • • • Символ 1: цифра от 1 до n. Символ 2: цифра от 1 до n. Символ 3: строчная буква из первых k фавита. букв латинского ал­
Глава 324 • Символ 4: 7.2. Более сложные циклы - строчная буква из первых экзаменационные задачи k букв латинского ал­ фавита. • Символ 5: цифра от 1 до n, больше первых двух цифр. Входнъ1е даннъ1е Н а вход подается два целых числа (аргумента): n и k в диапазоне [1 ... 9]. Вывод да1П1ых В консоль должны быть выведены все пароли в алфавитном по­ рядке, разделенные пробелом. Примеры ввода и вывода Ввод Вывод Ввод 2 11аа2 11аЫ 11ас2 4 11Ьс2 11bd2 11са2 11сЫ 11сс2 11da2 lldЫ 11dc2 11dd2 11ad2 11Ьа2 11ЬЫ 3 1 11cd2 Вывод 11аа2 11ааз 12аа3 21аа3 22ааз 1 ввод 4 2 Вывод 11аа2 11ааз 11аа4 11аЫ 11аЬ3 11аЬ4 11Ьа2 11ЬаЗ 11Ьа4 11ЬЫ 11ЬЬ3 11ЬЬ4 ввод вывод 3 2 11аа2 11ааз 11аЫ 11аьз 12ааз 12аа4 12аЬ3 12аЬ4 12Ьа3 12Ьа4 11Ьа2 11Ьа3 12ЬЬ3 12ЬЬ4 1Заа4 1ЗаЬ4 1ЗЬа4 1ЗЬЬ4 11ЬЫ 11ЬЬ3 21ааз 21аа4 21аЬ3 21аЬ4 21Ьа3 21Ьа4 12аа з 12а Ьз 21ЬЬ3 21ЬЬ4 22ааз 22аа4 22аЬ3 22аЬ4 12Ьа3 12ЬЬ3 22Ьа3 22Ьа4 22ЬЬ3 22ЬЬ4 2Заа4 2ЗаЬ4 21ааз 21аЬз 2ЗЬа4 2ЗЬЬ4 31аа4 31аЬ4 31Ьа4 31ЬЬ4 21Ьа3 21ЬЬ3 32аа4 З2 аЬ4 32Ьа4 32ЬЬ4 ззаа4 3ЗаЬ4 22аа з 22аЬз 3ЗЬа4 3ЗЬЬ4 22Ьа3 22ЬЬ3 Рекомендации и подсказки Мысленно можно разделить решение задачи на три части: • Считывание и преобразование вводимых данных - в дан­ ной задаче для этого нужно взять два элемента из заданно­ го массива n и • k и преобраз овать их в числа. Обработка введенных данных - с помощью вложенных циклов перебираем все возможные символы для каждо го из пяти символов пароля.
Задача: генератор паролей • Вывод результата 325 - печать любого пароля, удовлетворяю­ щего заданным условиям. Считывание и обработка вводимых данных Для считывания вводимых данных мы объявим две константы (const): n и k, кроме того, создадим переменную solution, в которой будем хранить строку с ответом: function passwordGenerator(input) { const n = Number(input(0]); const k = Number(input[l]); let solution = ' ' ; / / TODO: логика создания пароля return solution; } Вывод результата Один из способов найти решение этой задачи - клов for, вложенных друг в друга, создать пять ци­ по одному на каждый символ. Чтобы убедиться, что последний символ, который по условию явля­ ется числом, больше первых двух, которые также являются числа­ ми, мы воспользуемся встроенным методом Math. max( ... ): function passwordGenerator(input) { const n = Number(input[0]); const 1 = Number(input[l]); let solution = ' ' ; for (var s1 = 1; s1 <= n; s1++) { for (var s2 = 1; s2 <= n; s2++) { for (var sЗascii = 97; sЗascii < 97 + 1; sЗascii++) { let s3 = String.formatCharCode(sЗascii); for (var s4ascii = 97; s4ascii < 97 + 1; s4ascii++) { let s4 = String. formatCharCode(s4ascii); for (var s5 = Math.max(s1, s2) + 1; s5 <= n; s5++) {
326 Глава 7.2. Более сложные циклы solution = - экзаменационные задачи '${s1}${s2}${s3}${s4}${s5}'; } } } } } return solution; } Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/938#0. Задача: магические числа Напишите программу, которая принимает одно целое магиче­ ское число и выводит все возможные шестизначные числа, для ко­ торых произведение их цифр равно магическому числу. Пример : магическое число ➔ • 111112 111121 111211 112111 121111 211111 • • • • • ➔ ➔ ➔ ➔ ➔ ➔ 1 1 1 1 1 2 * * * * * * 1 1 1 1 2 1 * * * * * * 1 1 1 2 1 1 * * * * * * 1 1 2 1 1 1 2 * 1 * 2 *1 * 1 *1 * 1 * * * * * * 2 1 1 1 1 1 = = = = = = 2 2 2 2 2 2 Входные да нные Прогр амма считывает целое число (аргумент) в диапаз оне [1 ... 600 ООО]. Выходные данн ые Вьmедите в консоль все магические числа, разделенные пробелом. Примеры ввода и вывода Ввод 2 вывод 111112 111121 111211 112111 121111 211111
Задача: магические числа 327 8 Ввод вывод Ввод 111118 111124 111142 111181111214111222 111241 111421 111811112114112122 112141 112212 112221 114112 114121114211118111121114121122 121141 121221 121411122112122121122211124111141112 141211 142111 181111 211114 211122 211141 211212 211411 212112 212121 212211 214111 221112 221121 1 222111241111 411112 411121 411211 412111 421111 i 111412 112411 121212 141121 211221 221211 811111 1 531441 1 вывод 999999 Рекомендации и подсказки Решение задачи о магических числах следует той же концепции (снова нужно составить все комбинации для n элементов). Следуя этим шагам, попробуйте решить задачу самостоятельно: • Инициализируйте переменную, в которой будет храниться значение магического числа. • Вставьте дРуr в дРуrа шесть циклов for, по одному на ка­ ждую цифру искомого шестизначного числа. • В последнем цикле с помощью оператора if проверьте, рав­ но ли произведение шести цифр магическому числу. function magincNumber( i nput) { const magicNum = Number(input); let solution = ''; for (var dl = 1; dl < 10; dl++) { for (var d2 = 1; d2 < 10; d2++) { for (var dЗ = 1; dЗ < 10; dЗ++) { for (var d4 = 1; d4 < 10; d4++) { for (var dS = 1; dS < 10; dS++) { for (var dб = 1; dб < 10; dб++) { if (dl * d2 * dЗ * d4 * dS * dб magicNum) { solut ion = solution.concat(dl, d2, d3,d4, dS, dб,' '); }
Глава 328 7.2. Более сложные циклы - экзаменационные задачи } } } } } return solution; } В предыдУЩей главе мы рассмотрели дРуrие конструкции ци­ клов . Давайте рассмотрим пример решения той же задачи с помо­ щью цикла while. Сначала нам нужно записать в соответствующую переменную входное магическое число. Затем мы инициализиру­ ем шесть переменных, по одной для каждой из шести цифр числа, которое мы ищем в качестве результата: function magincNumber(input ) { const magicNum = Number (input ); let solution = '''; // T0D0: н аписать логику создания магического числа return solution; } После этого приступим к написанию циклов while. • Инициализируем первую цифру: • Зададим условие для каждого цикла: цифра должна быть меньше • dl = 1. 10. В начале каждого цикла мы устанавливаем значение сле­ дующей цифры, в данном случае: циклах них for d2 = 1. Во вложенных мы инициализируем переменные во внутрен­ циклах при каждом инкременте внешних циклов. Мы хотим добиться такого же поведения и здесь. • В конце каждого цикла мы будем увеличивать цифру на единицу: • d++. В самом внутреннем цикле мы вьmолним проверку и, если нужно, добавим результат в переменную, хранящую решение.
329 Задача: магические числа function magicNumber (input) { const magicNum = Number(input) let dl, d2, dЗ , d4, d5, dб; let sol uti on dl = 1; = , • 1. if (dl * d2 * dЗ * d4 * dS * sol ution = sol ution.concat(dl, d2, dб dЗ, === magi cNum) { d4, d5, dб, ' • ); } dб++; } d5++; } d4++; } dЗ++ ; } d2++; } dl++; } return solution; } Как мы видим, решать задачу можно с помощью разных типов ци­ клов. Разумеется, для каждой задачи есть наиболее подходящий ва­ риант. Чтобы отработать каждый из циклов, попробуйте решить ка­ ждую из следующих задач с помощью всех изученных вами циклов. Проверка в системе Judge Проверьте свое решение: Index/938#1. https://judge.softuni.bg/Contests/Practice/
Глава 330 7.2. Более сложные циклы - экзаменационные задачи Задача:стоп-число Н апишите программу, которая выводит в консоль все числа от до м, кратные N 2 и З б ез остатка, в обратном порядке. Мы будем считывать из консоли еще одно стоп-число какое-либ о из чисел, кратных - s. Если 2 и 3, равно стоп-числу, его не следует выводить, и программа должна завершиться. В противном случае выведите все числа до N, удовлетворяющие условию . Входные данные Из консоли считываются три числа, каждое в отдельной строке: • N- целое число: 0 < N < м. • м - целое число: N< м < 10000. • s- целое число: N < s < м. Вывод данных В консоли все числа, удовлетворяющие условиям, выводятся в одной строке, разделенные пробелом. Примеры ввода и вывода Ввод Вывод Комментарии 1 30 1, Числа ОТ ДО которые одновременно и без остатка делятся на и следу- 1 30 15 30 24 18 12 6 ющие: 30, 24, 18, 12 равно ни одному из и них , 6. 2 3, Число поэтому 15 ряд не про- должается . 1 Ввод Вывод 1 Комментарии Числа от 36 до 1, которые делятся на 2 и 3 1 36 36 30 24 18 одновременно без остатка, следующие: 36, 30, 24, 18, 12 и 6 . Ч и сло 12 равно остановочному 12 ч и слу, поэтому мы останавл и ваемся на 18. 1 Рекомендации и подсказки Задачу можно разделить на четыре логические части: • Считывание входных данных.
Задача: стоп-число • 331 Проверка всех чисел в заданном интервале (соответствен­ но, с помощью цикла). • Проверка условий задачи на соответствие каждому числу в рассматриваемом интервале. • Вывод чисел. Первая часть тривиальна - мы считываем три целых числа из консоли. Со второй частью мы тоже уже сталкивались - цикла for. Здесь есть небольшая загвоздка инициализация в условии указано, - что числа должны быть вьmедены в обратном порядке. Это озна­ чает, что начальным значением переменной i будет большее чис­ ло, которое, как мы видим из примера, равно М. Соответственно, конечное значение водить результаты i должно быть N. Тот факт, что мы будем вы­ в обратном порядке, и значения i говорят нам о том, что шаг будет уменьшаться на for (let i = m; i >= п; 1: i - -) После того как мы инициализировали цикл редь третьей части задачи ло делится на 2 и на стой проверки i f, - for, наступает оче­ проверка условия, что заданное чис­ З без остатка. Мы сделаем это с помощью про­ которую оставим читателю для самостоятельной работы. Другая загвоздка в этой задаче заключается в том, что, помимо вышеуказанной проверки, мы должны выполнить еще одну - рав­ но ли число стоп-числу, введенному из консоли в третьей строке. Чтобы дойти до этой проверки, проверяемое число должно пройти вышеуказанную проверку. Для этого мы построим еще один оператор if, который вло­ жим в предыдущий. Если условие истинно, то задача состоит в том, чтобы остановить программу, что в данном случае мы мо­ жем сделать с помощью оператора из цикла break, который выведет нас for. Соответственно, если условие проверки совпадения числа со стоп-числом возвращает f alse, то по умолчанию наша программа должна продолжить вывод. Это четвертая и последняя часть на­ шей программы.
Глава 332 7.2. Более сложные ци клы - экзаменационные задачи Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/938#2. Задача: особые числа Н апишите программу, которая считывает одно целое число N и генерирует все возможные особые числа от 1111 до 9999. Что бы считаться особым, число N должно соответствовать усло­ вию: • N должно делиться на каждую из своих цифр без остатка. Пример: если N = 16, то 2418-особое число: • 16 / 2 = 8 без остатка • 16 / 4 = 4 без остатка • 16 / 1 = 16 без остатка • 16 / 8 = 2 без остатка Входные данные Входные данные считываются из консоли и состоят из одного це­ лого числа в диапазоне [1 ... 600 ООО] . Выходные данные Выведите в консоль все особые числ а, разделенные про­ белом. Примеры ввода и вывода Ввод 11 Ввод 3 вывод l1111 Вывод 1111 1113 1131 1133 1311 1313 1331 1333 3111 3113 3131 3133 3311 3313 3331 3333 Комментарии 1 3 3 3 13 / / / / 1 = 3 3 = 1 3 = 1 3 = 1 без остатка без без без остатка ос татка остатка
Задача: разрядычисла 333 Ввод 16 вывод 1111 1142 1214 1248 1421 1482 1824 1888 2141 2212 2244 2418 2481 2822 2884 4128 4211 4242 4414 4448 4821 4882 8124 8188 8241 8412 8444 8818 8881 1112 1144 1218 1281 1422 1484 1828 2111 2142 2214 2248 2421 2482 2824 2888 4141 4212 4244 4418 4481 4822 4884 8128 8211 8242 8414 8448 8821 8882 1114 1148 1221 1282 1424 1488 1841 2112 2144 2218 2281 2422 2484 2828 4111 4142 4214 4248 4421 4482 4824 4888 8141 8212 8244 8418 8481 8822 8884 1118 1181 1222 1284 1428 1811 1842 2114 2148 2221 2282 2424 2488 2841 4112 4144 4218 4281 4422 4484 4828 8111 8142 8214 8248 8421 8482 8824 8888 1121 1182 1224 1288 1441 1812 1844 2118 2181 2222 2284 2428 2811 2842 4114 4148 4221 4282 4424 4488 4841 8112 8144 8218 8281 8422 8484 8828 1122 1184 1228 1411 1442 1814 1848 2121 2182 2224 2288 2441 2812 2844 4118 4181 4222 4284 4428 4811 4842 8114 8148 8221 8282 8424 8488 8841 1124 1188 1241 1412 1444 1818 1881 2122 2184 2228 2411 2442 2814 2848 4121 4182 4224 4288 4441 4812 4844 8118 8181 8222 8284 8428 8811 8842 1128 1211 1242 1414 1448 1821 1882 2124 2188 2241 2412 2444 2818 2881 4122 4184 4228 4411 4442 4814 4848 8121 8182 8224 8288 8441 8812 8844 1141 1212 1244 1418 1481 1822 1884 2128 2211 2242 2414 2448 2821 2882 4124 4188 4241 4412 4444 4818 4881 8122 8184 8228 8411 8442 8814 8848 Рекомендации и подсказки Решите задачу самостоятельно, используя то, что вы узнали из предыдущих двух задач. Вспомните разницу между оператора­ (/) ми целочисленного деления и вычисления остатка от делеюrя (%) в JavaScript. Проверка в системе Ju.dge Проверьте свое решеюrе: https://judge.softuni.bg/Contests/Practice/ Index/938#3. Задача: разрядычисла Напишите прогр амму, которая считывает из консоли целое число в диапазоне [100 ... 999], а затем выводит его заданное
Глава 334 7.2. Более сложные циклы - экзаменационные задачи количество раз , изменяя перед каждым выводом сл едующим образом: • Если число делится на 5 без остатка, вычтите из него его первую цифру. • Если число делится на З без остатка, вычтите из него вто­ рую цифру. • Если ни одно из вышеперечисленных условий не действу­ ет, добавьте к нему третью цифру. Выведите в кон соль N строк, каждая из которых содержит мчи­ сел, являющихся результатом вышеописанных действий. • N = сумма первой и второй цифры числа. • м = сумма первой и треть ей цифры числа. Входнъ1е даннъ1е Входные данные считываются из консоли и представляют собой целое число в диапазоне [100 ... 999]. Выходнъ1е да1mые Выведите в консоль все целые числа, являющиеся результа­ том вышеупомянутых вычислений, в соответствующих строках и столбцах, как показано в примерах. Примеры ввода и вывода Ввод 376 1 Вывод 382 418 454 490 517 553 589 625 652 688 388 424 460 487 523 559 595 622 658 694 394 430 457 493 529 565 592 628 664 700 400 427 463 499 535 562 598 634 670 697 397 433 469 505 532 568 604 640 667 703 403 439 475 502 538 574 610 637 673 709 409 445 472 508 544 580 607 643 679 715 415 442 478 514 550 577 613 649 685 712 412 448 484 520 547 583 619 655 682 718 Комментарии I 10 в рядов по 9 чисел каждом . Введите число 376: 376 ➔ ни 5, ни 3 ➔ 376 + 6 ➔ = = 382 ➔ ни 5, ни 3 ➔ 382 + 6 = = 388 + 6 = 394 + 6 = 400 * делен и е на 5 ➔ 400 - 3 = 397 1
Задача: разрядычисла Ввод 132 335 Вывод 129 126 120 119 123 120 121123 Комментарии (1 + 3) = 4 и (1 + 2) = 3 ➔ 4 ряда по 3 числа в каждом 123 Введенное число - 132: 121 132 ➔ деление на 3 ➔ 132 - 3 = = 129 119 деление на 3 ➔ 129 - 3 = = 126 ➔ деление на 3 ➔ 126 - 3 = 123 ➔ 120 деление на 3 ➔ 123 - 3 = = 120 ➔ = деление на 5 ➔ 120 - 1 = ... = 121 ➔ ни 5, ни 3 ➔ 121 + 2 = 123 ➔ Рекомендации и подсказки Решите эту задачу самостоятельно, используя то, что вы узнали из предыдущих задач. Помните, что для каждой цифры вводимых данных необходимо определить отдельную переменную. Проверка в системе Judge Проверьте свое решение: Index/938#4. https://judge.softuni.bg/Contests/Practice/
Глава 8.1. Подготовка к практическому экзамену - часть 1 В этой главе мы рассмотрим несколько задач, уровень сложно­ сти которых соответствует уровню задач на практическом экзаме­ не по основам программирования в университете SoftUni. Мы про­ верим и отработаем на практике все знания, полученные из этой книrи. Практический экзамен по «Основам программирования » Курс «Основы программирования» завершается практическим экзаменом. В экзамен включено шесть задач, на решение которых отводится 4 часа. Каждая из экзаменационных задач будет посвя­ щена одной из тем, изученных на курсе. Темы заданий следУЮщие: • • • • • задача с простыми вычислениями (без проверок); задача с одной проверкой; задача с б олее сложными проверками; задача с одним циклом; задача с вложенными циклами (рисование фигуры в кон­ соли); • задача с вложенными циклами и более сложной логикой. Система онлайн-оценки Все экзамены и домашние задания автоматизированы с помо­ щью системы проверки Judge: https://judge.softuni.bg. Для каждо­ го из заданий предусмотрены открытые (нулевые) тесты, кото-
Задачи с простыми вычислениями 337 рые помогут понять , что ожидается от задания, и исправить свои ошибки, а также конкурсные тесты, которые являются скрыты­ ми и проверяют правильность работы над заданием. Доступ к системе проверки осуществляется с помощью учетной записи softuni.bg. Как происходит тестирование в системе проверки Judge? Вы за­ гружаете исходный код и в меню под ним выбираете пункт «Вьmол­ нить с помощью JavaScript». Программа проверяется с помощью се­ рии тестов, и за каждый успешный тест вы получаете баллы. Задачи с простыми вычислениями В первой задаче практического экзамена по «Основам програм­ мирования» рассматриваются простые вычисления без проверок и циклов. Приведем несколько примеров. Задача: IШощадъ треугольника на IШоскости Треугольник на плоскости за- дается координатами трех его вер- шин. Сначала (xl, yl). задается вершина Затем задаются две дРуrие о _3 -2 вершины (х2, у2) и (хз, уЗ), которые -1 лежат на общей горизонтальной о прямой (то есть имеют одинаковые 1 координаты у). Напишите програм­ 2 1 з 4 s б х1, у1 площадь= s -з /z= 7.5 хЗ, уЗ о=5 х2,у2 2 му, которая вычисляет площадь тре­ угольника по координатам трех его вершин. Входные данные Из консоли считайте шесть целых чисел (по одному в строке): xl, yl, • • х2, у2, хз, уз. Все вводимые числа находятся в диапазоне Гарантируется, что у2 = уз . Вывод данных Выведите в консоль площадь треугольника. [-1000 ... 1000].
Глава 338 Подготовка к практическому экзамену 8.1. - часть 1 Примеры ввода и вывода Ввод вывод Визуализа ция о 5 -2 6 1 2 3 4 -3 7.5 1 1 1 -2 Коммента рии б 5 Сторона а xl, yl площадь= Высота треугольника : h -1 треугольника: =6 - 1 =5 = 1 - (-2) = 3 Площадь треугольника: s = о 1 о=5 хЗ, уЗ х2, у2 * а =5 * = = 7,5 h / 2 3 / 2 2 Ввод вывод 1 о -1 4 1 -1 -3 3 -3 Визуализация -4 2 3 Комментарии 4 Сторона а= з х3, у3 Высота треугольника: -3 8 -2 0 h = 1 - (-3) = 4 1 -1 площадь = треугольника: - (- 1) = 4 1h=4 Площадь треугольника : ' S =а * h / 2 =4 * 4 / 2 =8 4'4/1=8 1 xl, yl Рекомендации и подсказки В задачах такого типа, где на вход передаются некоторые ко­ ординаты, очень важно обращать внимание на порядок их пе­ редачи и правильно представлять , какие координаты и в каком порядке мы будем использовать. В данном случае на вход пере­ даются координаты xl, yl, х2, у2, хз , уз, именно в таком порядке. Е сли мы не будем соблюдать эту последовательность, то решение станет неверным. Сначала пишем код, который считывает вход­ ные данные: xl yl х2 у2 хз уз = Number(xl); = Number(yl); = Number(x2); = Number(y2); = Number(xЗ); = Number(yЗ);
Задачи с простыми вычислениями 339 Нам нужно вычислить сторону и высоту треугольника. Из при­ меров и из условия у2 = уз мы заметили, что одна сторона всегда параллельна горизонтальной оси. Это значит, что ее длина равна длине отрезка между координатами х2 и хз, который равен разно­ сти между большей и меньшей координатой. Аналогичным обра­ зом мы можем вычислить и высоту. Она всегда будет равна разно­ сти yl и у2 (или уз, так как они равны). Поскольку мы не знаем, всегда ли х2 будет больше хз, или yl будет ниже или выше противо­ положной стороны треугольника, мы будем использовать модуль значения разности, чтобы всегда получать положительные числа, так как отрезок не может иметь отрицательную длину: let а= Math.abs(x2 - х З); let h = Math.abs(y2 - yl); Используя известную нам со школы формулу для нахождения площади треугольника, мы вычислим ее: let s =(а* h) / 2; Осталось только вывести площадь в консоль: console.log(s); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#0. Задача: перемещение кирпичей Следующий пример экзаменационной задачи - рассчитать, сколько тележек необходимо для перемещения заданного количе­ ства кирпичей (при условии, что тележка имеет ограниченную гру­ зоподъемность). Описание задачи Строительные рабочие должны переместить в общей сложности х кирпичей. Число рабочих - w, работают они одновременно. Они перевозят кирпичи на тележках, каждая из которых вмещает mкир­ пичей. Напишите программу, которая считьmает целые числа х, w и m и вычисляет, какое минимальное количество рейсов нужно сде­ лать рабочим, чтобы перевезти кирпичи.
340 Глава 8.1. Подготовка к практическому экзамену - часть 1 Входные данные Вводятся три целых числа, по одному в строке: • • • Количество кирпичей х считывается из первой строки. Количество р абочих w считьmается из второй строки. Вместимость тележки m считывается из третьей строки. Все вводимые числа целые в диапазоне - [1 ... 1000]. Выходные данные Выведите в консоль минимальное количество рейсов, необходи­ мых для транспортировки кирпичей. Примеры ввода и вывода Ввод 120 2 130 Ввод вывод 2 Комментарии У нас есть 2 рабочих, каждый из которых перевозит по 30 кирпичей за рейс. Всего рабочие перевозя т 60 кирпичей за рейс. Чтобы перевезти 120 кирпичей, необходимо ровно вывод по 12 3 рабочих, к ирпичей за рейс . Всего рабочие п еревозят 30 кирпичей за рейс. Чтобы перевезти 355 кирпичей, необходимо ровно 12 рейсов: за 11 полных рейсов 330 кирпичей, перевозят последние Ввод вывод 5 12 30 1 25 а в последний 12-й рейс кирпичей . Комментарии У нас есть 5 каждый из которых пер евозит по 30 кирпичей за рейс. В общей сложности рабочие перевозят 150 кирпичей за рейс . Для того чтобы перевезти полного, 1 каждый из которых перевозит 10 перевозят 1 рейса. Комментарии У нас есть 355 3 10 2 5 рабочих, кирпичей, достаточно всего с 5 1 рейса (хотя и не- кирпичами). Рекомендации и подсказки Входные данные стандартные, единственное, на что следует об­ ратить внимание ваем данные: х = w = m= Number(x); Number(w); Number(m); - это последовательность, в которой мы считы­
Задачи с однократной проверкой 341 Мы вычисляем, сколько кирпичей перевозят рабочие за рейс: let bricksinOneCourse = w * m; Разделив общее количество кирпичей, перевозимых за 1 рейс, мы получим количество рейсов, необходимых для их перевозки. Мы воспользуемся методом Math. ceil( ... ), чтобы округлять резуль­ тат всегда в большую сторону. Когда кирпичи можно перевезти за точное количество рейсов, деление вернет точное число, и окру­ глять будет нечего. Соответственно, когда это не так, результатом деления будет число точных рейсов, но с десятичной дробью. Деся­ тичная часть будет округлена в большую сторону, чтобы получить требуемый 1 рейс для оставшихся кирпичей: let totalCourses = Math . ceil(x / bricksinOneCourse); Наконец, мы выводим результат в консоль: console.log(totalCourses); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#1. Задачи с однократной проверкой Вторая задача практического экзамена по ((Основам программи­ рования» охватывает условные конструкции и простые вычисле­ ния. Приведем несколько примеров. Задача: точка на отрезке На горизонтальной прямой находится горизонтальный отре­ зок, заданный координатами х двух его концов: первого и второго. На этой же горизонтальной прямой расположена точка, заданная координатой х. Напишите программу, которая проверяет, нахо­ дится ли точка внутри или вне отрезка, и вычисляет расстояние до ближайшего конца отрезка. Входные данные Консоль считывает три целых числа (по одному в строке): • В первой строке расположено число резка. first - один конец от­
Глава 342 • 8.1. Подготовка к практическому экзамену Во второй строке вводится - часть 1 другой конец от­ second - резка. • В третьей строке указываются координаты местопо­ point - ложение точки. Все вводимые числа являются целыми и находятся в диапазоне [-1000 ... 1000]. Выходные данные Выведите результат в консоль: • В первой строке выведите «in» или «out» - находится ли точка на отрезке или вне его. • Во второй строке выведите расстояние от точки до ближай­ шего конца отрезка. Примеры ввода и вывода Ввод 10 1~ Ввод 8 10 5 Ввод 1 Вывод iп 2 out 3 10 - - - Визуализация 8 5 -- • Вывод 2 7 5 Вывод out 1 ~2 Визуализация - ... 10 Визуализация -2 - . 1 з • Рекомендации и подсказки Считайте входные данные из консоли: first = Number(first); second = Number ( second); point = Number(point); Так как мы не знаем, какая точка находится слева, а какая спра­ ва, мы создадим две переменные, чтобы отметить это. Посколь-
Задачи с однократной проверкой 343 ку левая точка в сегда имеет меньшую координату х, мы будем использовать Math . min( ... ) для ее нахождения. Соответственно, правая точка всегда име ет большую ко ординату х, и мы использу­ ем Math .max( ... ). Таюке мы найдем расстояние от точки х до двух точек. Поскольку мы не зна ем их положения относительно дРуr дРуrа, для получения положительного р езультата используем Math . abs( ... ): let let let let left = Math . min( f irst, second); right = Math.max(first, second); distanceleft = Math.abs(left - point); distanceRight = Math.abs(right - point) ; Меньшее из двух расстояний найдем с помощью let minDistance = Math .min( ... ): Math . min(distanceleft, distanceRight); Осталось выяснить, находится ли точка на линии или вне ее. Точка будет находиться на отрезке, если она совпадает с двумя дРУ­ гими точками или ее координата х лежит между ними. В против­ ном случае точка лежит вне отрезка. После проверки мы выводим одно из двух сообщений, в зависимости от того, какая пр оверка ис­ тинна: if (point >= left && point <= right) { console . log('in'); } else { console . log('out'); } Наконец, мы выводим найденное ранее р асстояние: console.log(minDistance); Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#2. Задача : точка относительно фигуры Напишите программу, которая проверяет, находится ли точка (с координатами х и у) внутри или вне следующей фигуры:
344 Глава О 8.1. Подготовка к практическому экзамену 2 4 6 8 - часть 1 10 12 14 .----+--, • -5 • -3 -1 1 3 Входные данные В качестве параметров функции мы передаем два целых числа : хиу. В се вв одимые числа являются целыми и находятся в диапазоне [- 1000 .. . 1000]. Вывод ДЗIПIЪIХ Выведите в консоль «in» или «out» - находится ли точка внутри или вне фигуры (если точка попала на границу фигуры, будем счи­ тать, что точка находится внутри). Примеры ввода и вывода Ввод . Вывод I 8 Ввод 6 in -5 -3 Вывод Ввод in 11 -5 J Вывод Ввод 11 out 2 Вывод out Рекомендации и подсказки Что бы узнать, находится ли точка в фигуре, р азделим фигуру на два прямоугольника : О -5 2 4 6 .--- 8 О 10 12 14 -+--, . -3 -1 -1 1 1 3 4 6 3 8 - -5 -3 • 2 • 1 10 12 14 • -• 1 1 Достаточно, чтобы точка находилась в одном из них, чтобы она находилась внутри фигуры.
Задачи с более сложными проверками 345 Считываем данные из консоли: х = у = Number(x); Number(y); Создадим две переменные, которые будут указывать, находится ли точка в одном из прямоугольников: let pointinRectl = let pointinRect2 = х х >= 2 && >= 4 && х х <= 12 && <= 10 && у>= у>= - 3 && -5 && у<= у<= 1; 3; Когда мы будем вьmодить результат, мы проверим, приняла ли одна из переменных значение одна из них имела значение true. true, чтобы Достаточно, чтобы только определить местоположе­ ние точки на рисунке : if (pointinRectl 11 pointinRect2) { console.log('in'); } else { console.log('out'); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#3. Задачи с более сложными проверками Третья задача практического экзамена по основам программи­ рования включает в себя несколько вложенных проверок в сочета­ нии с простыми вычислениями. Вот несколько примеров. Задача: дата через пять дней Даны два числа дату. Напишите - d (день) и программу, m (месяц), которые образуют выводящую дату, которая будет через пять дней после определенной даты. Например, через пять дней после 28.03 будет дата 2.04. Мы предполагаем, что месяцы апрель, июнь, сентябрь и ноябрь имеют 30 дней, февраль - 28 дней, а остальные - 31 день. Меся-
Глава 346 8.1 . Подготовка к практическому экзамену - часть 1 цы должны выводиться с ведущим нулем, если они содержат одну цифру (например 01, 08). Примеры ввода и вывода Ввод 28 03 1 Вывод Ввод 2.04 27 12 1 вывод Ввод 1.01 25 1 1 вывод Ввод 30 . 01 26 02 вывод 1 3 . 03 1 1 Входные данные В качестве параметров функции мы передаем два целых числа: • Целое число d в диапазоне [1 . .. 31] - день. Номер дня не должен превышать количество дней в соответствующем месяце (например, • 28 для февраля). Целое число январь, mв интервале [1 ... 12] - месяц. Месяц 1 - это месяц 2 - это февраль, ..., месяц 12 - это декабрь. При вводе месяц может содержать ведущий ноль (напри­ мер, апрель может быть записан как 4 или 04). Вывод данных Выведите в консоль одну строку, содержащую дату через 5 дней в формате день.месяц. Месяц должен быть двузначным числом с ве­ дущим нулем, если необходимо . День должен быть без ведущего нуля. Рекомендации и подсказки Считаем входньrе данные из консоли: d = Number (d); m = Number (m); Чтобы облегчить проверку, создадим переменную, которая будет содержать количество дней в заданном месяце: let daysinMonth = 31; if (m === 2) { daysinMonth = 28; }
Задачи с более сложными проверками 347 if (m === 4 11 m === 6 11 m === 9 11 m daysinMonth = 30; 11){ } Мы увеJШчиваем количество дней на пять. d += 5; Проверяем, не стал JШ день больше, чем количество дней в этом месяце. ЕсJШ да, то из полученного дня нужно вычесть количество дней в месяце, чтобы получить день, которому соответствует день следующего месяца: if (d > daysinMonth) { d -= daysinMonth; } Как только мы перешли в следующий месяц, это следует учесть, увеличив исходное число месяцев на JШ оно больше 1. Нужно проверить, не стало 12, и есJШ да, то скорректировать. Так как при увеличении на пять дней мы не можем пропустить больше одного месяца, то достаточно будет сделать следующую проверку: if (d > daysinMonth) { d -= daysinMonth; m++; if(m > 12) { m = 1; } } Осталось только вывести результат в консоль. Важно правильно отформатировать вьmод, чтобы ведущий ноль появился в первых 9 месяцах. Для этого создается дополнительная переменная для ме­ сяца, к которой при необходимости можно добавить О. Наконец, мы выводим день и новое значение месяца: let monthToPrint if (m < 10) { monthToPrint = m; = '0' + monthToPrint; } console.log(d + ' ' + monthToPrint);
Глава 348 8.1 . Подготовка к практическому экзамену - часть 1 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#4. Задача: сумма трех чисел Даны три целых числа. Напишите программу, которая проверя­ ет, равна ли g,мма двух чисел третьему. Например, если числа и 3, 5 2, то сумма 'ДВух чисел равна третьему: 2 + 3 = 5. Входные данные Из консоли считываются три целых числа, по одному в строке. Числа находятся в диапазоне [1 ... 1000]. Выходные данные • Выведите в консоль текстовую строку с решением задачи в формате « а + Ь = с», где а, Ь и с при этом а • s. Если задача не имеет решения, выведите в консоль Пр имеры ввода и вывода Ввод Вывод Ввод Вывод 2 + 3 = 5 2 2 4 2 + 2 = 4 Вывод Ввод Вывод 1 1 Ввод 1 1 5 три входных числа, Ь. «No». 3 5 2 - 2 No 6 3 Считывание входнъzх даннъzх Получаем данные из консоли: No
Задача: сумма трех чисел 349 Number(a); Number(b); Number(c); а = Ь = с= Нам нужно проверить, равна ли сумма любой пары чисел третьему. У нас есть три возможных случая: • а + Ь = с • а + с = Ь • Ь+с=а Напишем основу, которую затем дополним необходимым кодом. Если ни одно из трех вышеперечисленных условий не выполняет­ ся, мы запрограммируем вьmод if (а+ Ь === с) «No»: { // некая последовательность } else if(a +с=== Ь ) { // некая последовательность } else if(b +с=== а ) { // некая последовательность } else { console.log('No'); команд команд команд } Теперь нам нужно определить порядок, в котором два слагаемых будут вьmодиться на экран. Для этого мы создадим вложенное усло­ вие, которое будет проверять, какое из двух чисел больше. В первом случае оно будет выглядеть следующим образом: if (а+ Ь if (а === > Ь) с) { { console.log(b + } else { coпsole.log(a + + + а + = + с); + + ь + = + с); } } Аналогично вьmолним два других случая. Полный код проверок и вывод программы будут выглядеть так: if (а+ Ь if (а === > Ь) с) { { coпsole.log(b + ' + ' +а+ ' = ' + с) ;
Глава 350 8.1 . Подготовка к практическому экзамену - часть 1 } else { console.log(a + ' + ' + ь + ' = ' + с); } else if (а + с=== Ь) { if (а> с) { console . log(c + } else { console.log(a + + + а + = ,+ + + с + = ' Ь), + + ь + = + а); + + с + = + а); Ь); } } else if if (Ь +с=== а) { console.log(c + } else { console.log(b + (Ь > { с) } } else { console.log ('No'); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#5. Задачи с одним циклом Четвертая задача практического экзамена по основам програм­ мирования включает в себя один цикл с простой логикой. Давайте решим несколько примеров задач с помощью простых циклов. Задача: суммъ1 с шагом 3 В следующем примере экзаменационной задачи нужно вычис­ лить три суммы, выбирая числа из заданной последовательности с шагом 3. Описание задачи Дано • n целых чисел: al, а2 , ..., an. Вычислите суммы: suml = al + а4 + а7 + ... (числа складываются, с первого, с шагом 3). начиная
Задачи с одним циклом • sum2 = а2 351 + as + со втор ого, с шагом • sumЗ =аз+ аб + с третьего, с шагом а8 + (числа складываются, начиная + (числа складываются, начиная 3). а9 3). Входные данные Входные данные считываются из консоли. В первой строке нахо­ дится целое число n (0 s n s 1000). В следующих n стр оках нам да­ ется n целых чисел в диапазоне [- 1000 . . . 1000]: al , а2, ..., an. Выходные данные В консоль мы должны вьmести три строки, содержащие три сум­ мы, в формате, как в примере. Примеры ввода и вывода Ввод вывод Ввод Вывод 4 2 3 5 7 suml = 3 sum2 = 5 sumЗ = 0 -2 6 12 suml = 19 sum2 = - 2 sumЗ = 6 1 Ввод 5 3 5 2 7 Вывод suml = 10 sum2 = 13 sumЗ = 2 8 Рекомендации и подсказки Возьмем количество чисел (размер вводимого массива) и объявим начальны е значения для трех сумм: let suml = 0; let sum2 = 0; let sumЗ = 0; Поскольку мы не знаем заранее, сколько чисел нам предстоит обработать, мы будем брать их по одному в цикле, который будет повторять ся n раз, и обрабатывать их внутри цикла: for {let i = 0; i < input.length; i++) { let num = input[ i ]; //TODO }
Глава 352 8.1 . Подготовка к практическому экзамену - часть 1 Чтобы понять, к какой из трех сумм нужно прибавить число, раз­ делим его порядковый номер на три и используем остаток. Чтобы определить, на каком порядковом номере мы находимся, мы будем использовать переменную i, которая отслеживает количество обо­ ротов цикла. Если остаток от i/3 равен нулю, значит, мы добавим это число к первой сумме, если 1- ко второй, а если 2- к третьей. f or (let i = 0; i < iпput. leпgth; i++) { let num = input[i]; if(i % 3 === 0) { suml += num; } if(i % 3 === 1) { sum2 += num; } if(i % 3 === 2) { sumЗ += num; } } Наконец, мы выведем результат в консоль в нужном формате: console.log('suml = console.log('sum2 = console.log('sumЗ = + suml); + sum2); + sumЗ); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#6. Задача: последовательность возрастающих элементов Сле,цующая примерная экзаменационная задача посвящена на­ хождению самой длинной возрастающей подпоследовательности заданной последовательности целых чисел. Описание задачи Дана серия из n чисел: al, а2, ..., an. Вычислите длину самой длин­ ной возрастающей последовательности последовательных элемен­ тов в этом ряду чисел.
353 Задачи с одним циклом Входные данные Входные данные считываются из консоли. В первой строке записано целое число В следующих n n (0 ~ n ~1000). строках нам дается n целых чисел в диапазоне (-1000 ... 1000]:al, a2, ... ,an. Выходные данные В консоль мы должны вьmести одно число - длину самой длин­ ной возрастающей последовательности. Примеры ввода и вывода Ввод Вывод Ввод 3 5 2 4 2 Вывод Ввод 4 4 2 8 7 6 1 2 4 4 2 Вывод 1 Ввод Вывод 4 5 3 1 6 7 8 4 Рекомендации и подсказки Чтобы решить эту задачу, нам нужно мыслить алгоритмично. Нам дана последовательность чисел, и мы должны проверить, бу­ дет ли каждое последующее число больше предыдущего, и если да, то подсчитать, насколько длинной будет последовательность, в которой это условие выполняется. Затем нам нужно найти, ка­ кая последовательность из всех таких последовательностей самая длинная. Для этого создадим несколько переменных, которые бу­ дем использовать в ходе решения задачи: let let let let countCurrentlongest count longest = 0; numPrev = 0; num = 0; Переменная из консоли. В n - = 0; это количество чисел, которые мы получим countCurrentLongest мы будем хранить количество элементов в растущей оч ереди, которые мы сейчас считаем. Напри­ 2, когда мы достигнем второго элемента последовательности (5, 6, 1, 2, 3), и станет равен 3, когда мы достигнем последнего элемента (5, 6, 1, мер, для ряда: 5, 6, 1, 2, 3 countCurrentLongest будет равен
Глава 354 8.1. Подготовка к практическому экзамену - часть 1 2, 3), потому что возрастающая последовательность 1, 2, З имеет 3 элемента. Мы будем использовать countlongest, чтобы сохранить самую длинную возрастающую последовательность. Другие пере­ менные - num, число, на котором мы сейчас находимся, и предыдущее число, которое мы будем сравнивать с num, numPrev, чтобы уз­ нать, растет ли последовательность . Мы начинаем перебирать числа и проверяем, больше ли теку­ щее число а, чем предыдущее число numPrev. Если это так, значит, последовательн ость растет и нам нужно увеличить число на 1. Мы сохраняем это в переменной, которая отслеживает длину последовательности, в котором мы сейчас находимся, а именно countcurrentlongest. Если num не больше предыдущего числа , это означает, что начинается новая очередь и нужно начать отсчет с 1. Наконец, по сле всех проверок numPrev становится тем числом, которое мы используем в данный момент, и мы начинаем цикл с самого начала со следующим введенным num. Вот пример реализации описанного алгоритма: for (let i = 0; i < iпput.length; i++) { пum = iпput[i]; if (num > numPrev) { countCurrentlongest++; } else { countCurrentlongest = 1; } numPrev = num; } Осталось выяснить, какая из всех последовательностей самая длинная. Для этого мы будем проверять в цикле, стала ли последо­ вательность, в котором мы находимся в данный момент, длиннее, чем длина самой длинной из наЙДенных на данный момент. Весь цикл будет выглядеть следующим образом: for (let i = 0; i < input.length; i++) { num = input[i]; if (num > numPrev) { countCurrentlongest++; } else {
Задачи по рисованию фигур в консоли countCurrentlongest = 355 1; } if (countCurrentLongest > countlongest) { countlongest = countCurrentlongest; } numPrev = num; } Наконец, мы выводим длину самой длинной строки, найденной на данный момент: console . log(countlongest); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#7. Задачи по рисованию фигур в консоли Пятая задача практического экзамена по основам программиро­ вания требует использования одного или нескольких вложенных циклов для рисования фигуры в консоли. Экзаменующиеся долж­ ны уметь логически мыслить и строить простые алгоритмы с ис­ пользованием вычислений, проверок и вложенных циклов для ре­ шения задач, то есть мыслить алгоритмически. Эта задача больше посвящена алгоритмическому мышлению, чем кодированию и ци­ клам. Давайте решим несколько примеров задач с вложенными ци­ клами (и рисованием фигур). Задача: идеалънъIЙ бриллиант Следующая примерная экзаменационная задача посвящена ис­ пользованию вложенных циклов и вычислений для вывода в кон­ соль ромба заданного размера, как показано в примерах ниже. Описание задачи Напишите программу, которая считывает целое число соли и рисует бриллиант размером n (см. примеры ниже). Входные данные На вход подается целое число n в диапазоне [1 ... 1000]. n из кон­
Глава 356 8.1. Подготовка к практическому экзамену - часть 1 Выходные данные В консоль должен быть выведен бриллиант, как показано в при­ мерах ниже. Примеры ввода и вывода Ввод Вывод 2 * *-* * Ввод Вывод 3 * *-* *-*-* *-* * Ввод Вывод 4 * *-* *-*-* *-*-*-* *-*-* *-* * Ввод Вывод 5 * *-* *-*-* *-*-*-* *-*-*-*-* *-* -*-* *-*-* *-* * Рекомендации и подсказки В задачах по рисованию фигур самое важное, что нужно учиты­ вать - это последовательность, в которой мы будем рисовать. Мы
Задачи по рисованию фигур в консоли 357 должны четко представлять, какие элементы повторяются и с ка­ ким шагом. Хорошо видно, что верхняя и нижняя части брилли­ анта одинаковы. Самый простой способ решить задачу - создать один цикл, который рисует верхнюю часть, а затем другой цикл, который рисует нижнюю часть . Число n = n мы будем считывать из параметров функции: Number(n); Начнем рисовать верхнюю половину бриллианта. Хорошо вид­ но, что каждая строка начинается с нескольких пробелов и *. Если присмотреться, то можно заметить, что пробелы всегда равны n- индексу строки - 1 (первая строка - n-1, вторая - n -2 и т. д. ) Начнем с того, что нарисуем необходимое количество пробелов, а также первую звездочку. Обратите внимание, что мы начинаем считать с О, а не с 1. Затем нам нужно будет просто добавить - * не­ сколько раз, чтобы завершить строку. Вот фрагмент кода для рисования вершины бриллианта: for (let i = 0; i < n; i++) { console.log( ' ' .repeat( n - i - 1) + '* ' // TODO: рисуем остаток строки ); } Осталось только завершить каждую строку необходимым коли­ чеством элементов элементов (в первой - *. -> В каждой строке нужно добавить О, во второй -> 1 и т. д.). Вот полный код для рисования верхней части ромба: for (let i = 0; i < n; i++) { console.log( .repeat(n - i - 1) + '* ' + '-*' .repeat(i) + ' ' .repeat( n - i - 1) ); } i таких
Глава 358 8.1 . Подготовка к практическому экзамену - часть 1 Что бы нарисовать нижнюю часть р омба, нам нужно перевер­ нуть вершину в обратную сторону. Мы будем считать с п как если мы начнем с n - забудьте изменить шаг с - 2, так 1, то нарисуем средний ряд дважды. Не ++ на - -. Вот код для рисования нижней части ромба: for (let i = n - 2; i >= 0; i--) { console.log( .repeat(п - i - 1) + '-*' . repeat(i) + ' ' . repeat ( п - i - 1) ); } Мы соберем всю программу воедино, сначала считав параметр функции, напечатав верхнюю, а затем нижнюю часть р омба. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#8. Задача: прямоуголъ1П1К со звездочками в центре Н апишите программу, котор ая считывает из консоли целое число n и рисует прямоугольник размер ом n с двумя звездочками в центре, как показано в пр имерах ниже. Входные данные Н а вход подается целое число n в диапазоне (2 ... 1000]. Выходные данные Прямоугольник должен быть выведен в консоль, как показано в примерах ниже. Примеры ввода и вывода Ввод 2 Вывод %%%% %**% %%%%
Задачи по рисованию фигур в консоли Ввод Вывод 3 %%%%%% % % % ** % % % %%%%%% 359 1 Ввод Вывод 4 %%%%%%%% % % % % ** %%%%%%%%%% 1 Ввод 5 1 Вывод %%%%%%%%%% % % % % % % ** % % % % %%%%%%%%%% Рекомендации и подсказки Считайте параметр функции: п = Number(n); Первое, что мы ср азу заметим, это то, что первая и последняя стр оки содержат 2 * п %символов. Начнем с этого, а затем нарису­ ем середину прямоугольника : console.log('%' .repeat(2 * n)); // TODO: отрисовать середину прямоугольника console.log('%' . repeat(2 * n)); Из приведенных примеров видно, что середина фигуры всегда имеет нечетно е количество линий. Обратите внимание, что при за­ дании четного числа количество строк равно предыдущему нечет­ ному числу (2 -> 1, 4 -> 3 и т. д.). Мы создадим переменную, которая будет представлять количество строк в нашем прямоугольнике, и изменим ее, если число n будет четным. Затем мы нарисуем пря­ моугольник без звездочек. Каждая стр ока имеет символ %для нача-
Глава 360 ла и конца и 2 * и мы отнимаем 8.1 . Подготовка к практическому экзамену - часть 1 n - 2 пробела между ними (ширина равна 2 * n, 2 для Щ!,ух % в конце). Не забудьте перенести код для последней строки после цикла: let numRows = n; if ( n % 2 === 0) numRows --; for (let i = 0; i < numRows; i++) { console.log( '%' + ' '. repeat(n - 2) + // TODO: разместить ' '. repeat(п - 2) + звездочки ); } Мы можем запустить и протестировать код до этого места. Все, кроме Щ!,ух звездочек в середине, должно работать правильно. Теперь нам осталось добавить звездочки в тело цикла. Мы прове­ рим, находимся ли мы в среднем ряду. Если мы находимся в середи­ не, то нарисуем ряд со звездочками, если нет, то обычный ряд. В ряду со звездочками есть n - 2 пробела (n - половина длины, и мы уби­ раем звездочку и символы процента), Щ3е звездочки и снова n - пробела . Два символа процента в начале и конце ряда мы оставим. for (let i = 0; i < пumRows; i++) { if (i === (numRows - 1) / 2) { console.log( '%' + ' ' . repeat(п - 2) + '**' + ' '.repeat(n - 2) + '%' ); } else { console.log( '%' + ' ' . repeat ( n * 2 - 2) + ' %' ); } } 2
Задачи с вложенными циклами с более сложной логикой 361 Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#9. Задачи с вложенными циклами с более сложной логикой Последняя (шестая) задача практического экзамена по основам программирования требует использования нескольких вложен­ ных циклов и более сложной логики в них. Задача проверяет спо ­ собность студентов мыслить ашоритмически и решать нетриви­ альные задачи, требующие композиции циклов. Ниже приведены примеры экзаменационных задач. Задача: сочетания из четъ1рех возрастающих чисел Для заданной пары чисел а и Ь найдите все четыре числа nз, n4, для которых а 5- nl 5- n2 < nз < n4 5- nl, n2, Ь. Входные данные В качестве параметров функции мы вводим два целых числа а и ь в интервале [0 .. . 1000]. Вывод данных Надо вывести все искомые четверки чисел в порядке возраста­ ния, по одной в строке. Примеры ввода и вывода Ввод 3 7 Ввод 5 7 Вывод 3 3 3 3 4 4 4 4 5 5 5 5 6 6 6 Вывод No 6 7 7 7 7
Глава 362 Ввод 10 13 8.1 . Подготовка к практическому экзамену - часть 1 вывод 10 11 12 13 Рекомендац ии и подсказки Считайте параметры функции. Мы таюке создадим дополни­ тельную переменную count, которая будет следить за тем, суще­ ствует ли диапазон чисел: Number (a); Ь = Number (b) ; let count = 0; а= Легче всего будет решить задачу, если логически разделить ее на части. Если нам нужно вьmести все числа между а и ь, то мы сде­ лаем это с помощью цикла, который вьmедет все числа от а до Ь. Давайте подумаем, как это будет работать с парами возрастающих чисел. Ответ прост - мы будем использовать вложенные циклы: for (let i = а; i <= Ь; i++) { for (let j = i + 1; j <= Ь; j++) { console . log(i + ' ' + j); } } Мы можем протестировать недописанную программу, чтобы проверить, насколько она верна. Она должна вьmести все пары чи­ сел i, j, для которых i ~ j. Поскольку каждое последующее число в серии должно быть больше предыдущего, второй цикл будет работать с i + 1 (следую­ щего большего числа). Соответственно, если нет ряда из двух воз­ растающих чисел (а и Ь равны), второй цикл не выполнится и в кон­ соль ничего не будет вьmедено. Аналогичным образом остается реализовать вложенные циклы для четырех чисел. Мы таюке до бавим возрастающий счетчик, ко­ торый мы инициализировали в начале, чтобы узнать, существует ли такая серия:
Задачи с вложенными циклами с более сложной логикой 363 for (let i = а; i <= Ь; i++) { for (let j = i + 1; j <= Ь; j++) { for (let k = j + 1; k <= Ь; k++) { for (let 1 = k + 1; 1 <= Ь; 1++) { console.log(i + ' ' + j + ' ' + k + ' ' +1); count++; } } } } Наконец, мы проверим, равен ли счетчик нулю, и в случае поло­ жительного ответа выведем в консоль сообщение «No». if (count === 0) console.log('No'); Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/939#10. Задача: создание прямоугольников Задав число n и минимальную площадь m, сгенерируйте все прямоугольники с целочисленными координатами в интервале [ -n ...n], площадь которых не меньше m. Выведите сгенерированные прямоугольники в следующем формате: (left , top) (right, bottom) -> area Прямоугольники задаются левым верхним и правым нижним углами. Применяются следующие неравенства: • -n • -n i top < bottom i n < left < right i n Входные данные В качестве параметров функции мы вводим два числа: • Целое число n в диапазоне (1 ... 100] - задает минималь­ ную и максимальную координаты вершины. • Целое число m в диапазоне (0 ... 50 000] - задает мини­ мальную площадь генерируемых прямоугольников.
Глава 364 8.1 . Подготовка к практическому экзамену - часть 1 Вывод данных Описанные прямоугольники должны быть выведены в кон­ • соль в том же формате, что и в примерах ниже. • • Если для чисел n и mнет прямоугольника, выведите «No». Порядок вьmода данных прямоугольников не имеет значения. Примеры ввода и вывода Ввод Вывод 1 (-1, -1) (0, 1) -> 2 (-1, -1) (1, 0) -> 2 (-1, -1 ) (1, 1) - > 4 (-1, 0) (1, 1) -> 2 (0, -1) (1, 1) -> 2 1 2 ' Ввод Вывод 2 No 17 Ввод Вывод 1 iб (-3, -3) (3, 3) -> 36 1 Рекомендации и подсказки Считайте параметры функции. Мы таюке создадим счетчик для хранения количества найденных прямоугольников: n = Number (n); m = Number (m); let count = 0; Очень важно уметь визуализировать задачу, прежде чем присту­ пать к ее решению. В нашем случае мы должны искать прямоуголь­ ники в системе координат. Мы знаем, что левая точка всегда будет иметь координату х меньше, чем правая. Соответственно, верхняя точка всегда будет иметь координату у больше, чем нижняя. Чтобы найти все прямоугольники, нам нужно создать цикл, аналогичный
Задачи с вложенными циклами с более сложной логикой 365 циклу из предыдущей задачи, но на этот раз не каждый последую­ щий цикл будет начинаться со следующего числа, так как некото­ рые координаты могут быть равны (например, left и top): for (let left = -n; left < n; left++) { for (let top = -n; top < n; t op++) { for (let right = left + 1; right <= n; right++) { for (let bottom = top + 1; bottom <= n; bottom++) { // TODO } } } } С помощью переменных left и right мы будем отслеживать ко­ ординаты по горизонтали, а с помощью top и bottom - по верти­ кали. Здесь важно знать координаты, чтобы правильно вычислить стороны прямоугольника. Теперь нам нужно найти площадь пря­ моугольника и проверить, больше или равна ли она на будет разницей между tom. left и right, m. Одна сторо­ а другая между top и bot- Поскольку координаты могут поменяться местами, мы будем использовать абсолютные значения. Снова добавляем счетчик в цикл, считая только те прямоугольники, которые выписываем. Важно заметить, что порядок записи - left, top, right, bottom, по­ скольку именно такой порядок указан в условии: for (let left = -n; left < n; left++) { for (let top = -n; top < n; top++) { for (let right = left + 1; right <= n; right++) { for (let bottom = top + 1; bottom <= n; bottom++) { let area = Math.abs(right - left) * Math . abs(bottom - top); if (area >= m) { console.log( '(' + left +', ' + top +') (' + right + ', ' + bot tom + ') -> '+ area ); count++; } } } } }
366 Глава 8.1. Наконец, мы выводим Подготовка к практическому экзамену «No», - часть 1 если таких прямоугольников не су­ ществует: if (count === 0) console . log('No'); Проверка в системе Judge Проверьте свое решение: Index/939#11. https://judge.softuni.bg/Contests/Practice/
Глава 8.2. Подготовка к практическому экзамену часть - 11 В этой главе мы рассмотрим задания практического экзамена по основам программирования, проведенного в SoftUni ранее. Зада­ чи да-дут вам представление о том, что вас может ожидать на всту­ пительном экзамене по программированию. Экзамен охватьmает материал, изученный в данной книге и на курсе « Основы програм­ мирования» в SoftUni (https://softuni.org/curricu1um). Типы экзаменационных задач Традиционно вступительный экзамен в сти SoftUni практических задач по программированию, состоит из ше­ перечисленных ниже: • задача с простыми вычислениями (без условий); • задача с простым условием (простые проверки); • задача с более сложными условиями (вложенные проверки и множественные проверки); • задача с простым циклом (например, итерация от 1 до N); • задача с вложенными циклами (например, рисование 2D-фигуры в консоли); • задача с вложенными циклами и более сложной логикой (цикль1 и проверки вместе). Давайте рассмотрим реальную экзаменационную тему: шесть экзаменационных задач и их решения.
Глава 368 8.2. Подготовка к практическому экзамену - часть 11 Задача : расстояние Напишите программу, которая вычисляет, какое расстояние про­ ехал автомобиль (в километрах), если известны начальная скорость (км/ч), начальный отрезок времени в минутах, затем скорость уве­ личивается на шается на 10 %, второй отрезок времени, затем скорость умень­ 5 %, и время до конца поездки. Чтобы рассчитать рас­ стояние, нужно перевести минуты в часы (например, 70 минут = 1,1666 часа). Входнъ1е даннъ1е Входные данные поступают из консоли и состоят из четырех строк: • Начальная скорость в км/ч - целое число в диапазоне [1 ... 300]. • Первый временной интервал (таймфрейм) в минутах лое число в диапазоне • • [1 ... 1000]. Второй временной интервал в минутах - апазоне це­ целое число в ди­ [1 ... 1000]. Третий временной интервал в минутах- целое число в ди­ апазоне [1 ... 1000]. Выходнъ1е даннь1е Выведите в консоль число проЙДенных километров, отформати­ рованное до второй цифры после десятичной точки. Примеры ввода и вьmода Ввод Вывод Комментарии Расстояние с начальной скоростью: 90 60 70 80 1 1 час (60 мин)= 90 90 км/ч * км 90 + 10 % = 330.90 99 .00 км/ч * 1,166 часа (70 мин)= 115.50 км После снижения скорости: 99 - 5 % = 94 . 05 км/ч * 1 . 33 часа (80 мин)= 125.40 км Общее количество пройденных километров: 330.9 км После увеличения скорости:
Задача: расстояние Ввод 369 вывод Комментарии Расстояние с начальной скоростью : 1.86 (112 140 км/ч * 261.33 км После увеличения скорости : 140 + 10 % = 140 112 917 . 12 154.00 км/ч * 1.25 часа (75 мин)= 192.5 км 75 После снижения скорости: 154,00 - 5 % = 190 146.29 км/ч * 3,16 часа (190 мин) = 463.28 км часа мин)= Общее количество пройденных к илометров: 917.1166 км РекомендаЦIПI и советь~ Возможно, на первый взгляд такое описание может показаться обманчивым и неполным, что еще больше усложняет относитель­ но простую задачу. Давайте разделим ее на несколько подзадач и попробуем решить каждую из них по очереди, что приведет нас к конечному результату: • Наша начальная подзадача будет заключаться в считыва­ нии входных данных, введенных пользователем, и сохране­ нии их в соответствующих переменных. • Выполнение основной логики программы, которая в нашем случае представляет собой пакет про стых вычислений чис­ ловъrх значений, которые у нас уже есть. • Расчет и формирование конечного результата. Основная часть логики программирования заключается в вы­ числении того, каким будет пройденное р асстояние после всех из­ менений скорости. Поскольку во время выполнения программы часть имеющихся у нас данных изменяется, мы можем разделить программный код на несколько логически разделенных частей: • Вычисление расстояния, проЙДенного с начальной скоростью. • • • Изменение скорости и подсчет пройденного расстояния. Последнее изменение скорости и расчет. Подведение итогов. По условию функция должна считать четыре аргумента, кото­ рые необходимо преобразовать в числа, чтобы въmолнить необ-
Глава 370 8.2. Подготовка к практическому экзамену - часть 11 ходимые вычисления. Мы выполним преобразование с помощью Number( ... ): let initialSpeed = Number(args[0)); // let firstinterval = TODO // let secondinterval = TODO // let thirdinterval = TODO Таким образом, мы смогли успешно справиться с первой подза­ дачей - приемом входных данных. Изначально мы сохраняем переменную, которую будем ис­ пользовать многократно. Такой подход к централизации дает нам гибкость и возможность изменять общий результат программы с минимальными усилиями. Если нам нужно изменить значение, мы должны сделать это только в одном месте кода, что экономит наше время и силы: let minutesPerHour = 60; Избегание повторяющегося кода (централизация логики програм­ мы) в задачах, которые мы рассматриваем в этой книге, поначалу может показаться излишним, но этот подход крайне важен при создании масштабных приложений в реальной среде, и отработ­ ка его на ранних этапах обучения только поможет в приобрете­ нии качественного стиля программирования. Мы вычисляем прошедшее время в часах, разделив представ­ ленное время на 60 (минут в часе). Мы находим пройденное рас­ стояние, умножая начальную скорость на прошедшее время (в ча­ сах). Затем мы меняем скорость, увеличивая ее на 10 % (условно). Вычисляем процентное соотношение, а также следующие пройден­ ные расстояния следующим образом: • Находим интервал времени (в часах), разделив данный ин­ тервал в минутах на количество минут, содержащихся в од­ ном часе • (60). Находим пройденное рассгояние, умножая интервал (в ча­ сах) на скорость, которую мы получаем после увеличения. • Следующим шагом будет уменьшение скорости на 5 %, как указано в условии. • Находим оставшееся расстояние, как описано в первых двух пунктах.
Задача: замена плитки 371 let firstintervalHours = firstinterval / minutesPerHour; let firstDistance = initialSpeed * firstintervalHours; let speedAfterincrease initialSpeed + ((initialSpeed * 10) / = 100); let secondintervalHours let secondDistance // TODO: вычислите = secondinterval / minutesPerHour; speedAfterincrease * secondintervalHours; третье расстояние (thirdDistance) = До этого момента нам удалось выполнить две самые важные подзадачи - получение данных и их обработку. Осталось только вычислить конечный результат. Поскольку по условию он должен быть отформатирован до двух десятичных знаков, мы можем сде­ лать это следующим образом: let finalDistance = firstDistance + secondDistance + thirdDistance; console . log(finalDistance.toFixed(2)); В случае корректной работы и запуска программы с данными из условия задачи проведите еще пару тестов, чтобы убедиться, что она работает правильно . Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/940#0. Задача: замена плитки Гарри собрал деньги, на которые он хочет заменить плитку на полу в ванной. Пол прямоугольный, а плитка треугольная. На­ пишите программу, которая вычислит, хватит ли ему собраннь1х денег. Даны ширина и длина пола, а также одна сторона треуголь­ ника и его высота. Необходимо вычислить, сколько плиток нужно, чтобы покрыть пол. Количество плиток нужно округлить до боль­ шего целого числа и добавить еще 5 штук для подгонки. Кроме того, нам также даны цена за плитку и сумма на оплату работы. Входные дан..н.ые В качестве параметров функции мы передаем семь чисел: • Сбережения Гарри.
Глава 372 • • • • • • 8.2. Подготовка к практическому экзамену - часть 11 Ширина пола. Длина пола. Сторона треугольника. Высота треугольника. Цена плитки в 1v (болгарских левах, BGN). Вознаграждение, выплачиваемое мастеру. Все числа - вещественные в диапазоне [0.00 ... 5000.00]. Выходные данные В консоль должна быть выведена одна строка: • Если денег достаточно : "{Остаток lv"). "You' 11 need средств} lv left." (Осталось {Остаток средств} • Если денег не хватает: lv more." {Недостаточно средств} ("Вам понадобится на {Недостаточно средств} lv больше") . Результат должен быть отформатирован до второй цифры после десятичной точки. При.меры ввода и вывода Ввод Вывод 500 25.60 lv left. 3 2.5 0. 5 0.7 7.80 1100 Ввод Вывод Комментарии ! площадь пола ➔ 3 * 2.5 = 7.5 Площадь плитки ➔ 0.5 * 0.7 / 2 = 0.175 Необходимо плитки ➔ 7. 5 / 0 . 175 = 42.857 ... = 43 + 5 запасных плиток= 48 Общая сумма ➔ 48 * 7.8 + 100 (мастеру)= 474.4 1474.4 < 500 ➔ 25 . 60 lv останется Комментарии 1000 You'll пееd l nлощадь пола ➔ 5.55 * 8.95 = 49.67249 5.55 1209.65 lv Площадь плитки ➔ 0.9 * 0.85 / 2 = 0.3825 8. 95 more . Необходимо плитки ➔ 49 . 67249 / 0 . 3825 = 0 . 90 129 . 86... 0.85 = 130 + 5 запасных плиток= 135 13.99 Общая сумма ➔ 135 * 13.99 + 321 (мастеру)= 321 2209 . 65 12209 . 65 > 1000 ➔ 1209 . 65 lv недостаточно 1
Задача: замена плитки 373 Рекомендации и советы В текущей задаче наша функция должна принимать больше входных данных и вьmолнять большее количество вычислений, хотя решение достаточно простое. Мы принимаем данные от поль­ зователя привычным способом. Теперь, когда у нас есть все необходимое для выполнения логики программы, мы можем перейти к сле,цующей части. Как рассчитать необходимое количество плиток, которого хватит для покрытия всего пола? Предположение о том, что плитки имеют треуголь­ ную форму, может привести к путанице, но на практике проблема сводится к очень простому расчету. Мы можем вычислить общую площадь пола, используя формулу для нахождения площади пря­ моугольника, а площадь плитки - используя соответствующую формулу для треугольника. Чтобы вычислить, сколько нужно плиток, разделим площадь пола на площадь одной плитки (не забыв добавить 5 дополнитель­ ных плиток по условию) . Обратите внимание, что в условии указано округлить получен­ ное в результате деления количество плиток до большего целого числа, а затем прибавить документации: 5. Подробнее об этом можно узнать из math.ceil( ... ). К итоговому результату мы можем прийти, вычислив общую сум­ му, необходимую для покрытия всего пола, сложив стоимость плит­ ки и стоимость услуг мастера, которые мы получили из исходньIХ даннь~х. Мы можем догадаться, что общую стоимость плитки можно получить, умножив количество плиток на цену за плитку. Мы мо­ жем узнать, хватит ли нам имеющейся суммы, сравнив собранные на данньrй момент деньги (из исходньIХ даннь~х) и общую стоимость: if (budget >= totalCost) { // TODO: вывести сообщение } else { // TODO: вывести сообщение } Проверка в системе Judge Проверьте свое решение: Index/940#1. https://judge.softuni.bg/Contests/Practice/
Глава 374 8.2. Подготовка к практическому экзамену - часть 11 Задача: цветочный магазин Цветочный магазин предлагает три вида цветов: хризантемы, розы и тюльпаны. Цены зависят от сезона . Сезон Розы Хризантемы Тюл ьпаны весна / лето 2 . 00 ВGN/шт 4.10 ВGN/шт 2.50 ВGN/шт осень / зима 3.75 ВGN/шт 4 .50 ВGN/шт 4.15 ВGN/шт В праздничные дни цены на все цветы увеличиваются на 15 %. Предоставляются следующие скидки: • При покупке более 7 тюльпанов весной - 5 % от стоимости всего букета. • При покупке 10 и более роз в зимний период - 10 % от сто­ имости всего букета. • При покупке более сезон - 20 % 20 цветов в общей сложности в любой от стоимости всего букета. Скидки предоставляются в вышеописанном порядке и могут комбинироваться. Все скидки действуют после повышения цены в праздничный день. Цена за составление букета всегда равна 2 BGN. Напишите программу, которая вычисляет стоимость букета. Входнъ1е даннъ1е Функция принимает пять аргументов: • В 1-й строке указывается количество купленных хризан­ тем • - целое число в диапазоне [О Во 2-й строке указывается количество купленных роз лое число в диапазоне [О • це­ ... 200]. 3-я строка содержит количество купленных тюльпанов целое число в диапазоне [О • ... 200]. - ... 200]. 4-ястрока-времягода-[Sрring, Summer, Autumn, Winter] ([Весна, Лето, Осень, Зима]). • В 5-й строке указывается, является ли этот день празднич­ ным - [У= да / N = нет]. Вывод данных Выведите в консоль одно число - цену цветов, округленную до второго символа после десятичной точки.
375 Задача: цветочный магазин Примеры ввода и вывода Ввод Вывод 2 46.14 4 8 Spring у Ввод Комментарии 2*2 .00 + 4*4. 10 + 8*2 . 50 = 40 .40 BGN 40.40 + 15 % = 46.46 BGN Скидка 5 % при покупке> 7 тюльпанов весной:44.14 Цветы в количестве 20 или менее : без скидки 44. 14 + 2 за составление букета= 46. 14 BGN Цена: Праздник: 1 Комментарии Вывод 3*3.75 + 10*4.50 + 9*4 . 15 = 93 . 60 BGN 3 Цена : 10 Не праздник: 9 69 . 39 Winter Скидка N Всего цветов более период: без повышения 10 % при покупке 10 цены и более роз в зимний 84.24 67 . 392 + 2 20: 20 % = 67 . 392 букета= 69.392 BGN скидка за составление Рекомендации и подсказки Внимательно прочитав условие, мы понимаем, что нам сно ­ ва придется выполнять простые вычисления, но с той разницей, что на этот раз потребуется больше логических проверок. Мы долж­ нъ1 уделять больше внимания тому, в какой момент происходит из­ менение конечной цены, чтобы правильно выстр оить логику на­ шей прогр аммы. Для начала мы записываем известные данные, создавая переменные, как мы делали это в предыдущих задачах: / / Изначальный прайс-лист let roseAutumnWinterPrice = 4. 5; let roseSpringSummerPrice = 4 . 1; let tulipAutumnWinterPrice = 4.15; let tulipSpringSummerPrice = 2.5; let chrysanthemumAutumnWinterPrice let chrysanthemumSpringSummerPrice let arrangePrice = 2; = = 3.75; 2; То же самое мы делаем и с другими известными значениями:
376 Глава 8.2. Подготовка к практическому экзамену - // Увеличение цены let priceincreasePercentage = часть 11 15; // Скидки let t ulipPriceDecreasePercentage = 5; let rosePriceDecreasePercentage = 10; let totalPriceDecreasePercentage = 20; // Пороги скидок let tulipPriceDecreaseThreshold = 7; let rosePriceDecreaseThreshold = 10; let totalPriceDecreaseThreshold = 20; Наша следующая подзадача - правильно обработать входные данные. Мы используем привычный подход - преобр азуем их в числовы е типы данных: let chrysantemumsPurchased = Number(args[0)); // let rosesPurchased = ••• Давайте подумаем, как лучше структурировать логику нашей программы. Из условия видно, что путь программы в основном де­ лится на две части: весна/лето и осень/зима. Мы сделаем разделе­ ние с п омощью условного оператора i f-else, а перед этим зададим переменные для цен на отдельные цветы, а таюке для конечного результата: if (season === "Winter" 11 season === "Autumn") { rosesPrice = rosesPurchased * roseAutumnWinterPrice; chrysantemumsPrice = chrysantemumsPurchased * chrysantemumAutumnWinterPrice; tulipsPrice = tulipsPurchased * tulipAutumnWinterPrice; totalCost = rosesPrice + chrysantemumsPrice + tulipsPrice; } else { // эту часть программы допишите самостоятельно } Нам еще нужно выполнить несколько проверок скидок на раз­ ные виды цветов в зависимости от сезона и изменить конечный результат. Проверка в системе Judge Проверьте свое решение: Index/940#2. https://judge.softuni.bg/Contests/Practice/
Задача:оценки 377 Задача:оценки Напишите программу для вычисления статистики экзаменаци­ онных оценок. Вначале программа считывает количество студен­ тов, присутствовавших на экзамене, и для каждого студента - его оценку. В конце программа должна вывести процент студентов, имеющих оценки от 2.00 до 2.99, от 3.00 до 3.99, от 4.00 до 4.99, 5.00 и выше, а таюке средний балл за экзамен. Примечание: мы используем болгарскую систему оценки зна­ 2.00 (неудовлетворительно) и заканчивается 6.00 (превосходно): https://en.wikipedia.org/wiki/ Grading_systems_by_country#Bulgaria. ний, где шкала оценок начинается с Входные данные Считайте из консоли последовательность чисел, каждое в от­ дельной строке: • • ших на экзамене В первой строке количество студентов, присутствовав­ целое число в диапазоне [1 ... 1000]. Для каждого отдельного студента в отдельной строке оценка на экзамене - - вещественное число в диапазоне [2.00 ... 6.00]. Выходные да нные Выведите в консоль пять строк, содержащих следУЮщую инфор­ мацию: • «Тор students: 5.00 и выше}%» {процент студентов, получивших оценку («Лучшие студенты: {процент студентов, по­ 5,00 и выше}%»). «Between 4.00 and 4 . 99: {от 4.00 до 4.99 включительно}%». («Между 4.00 и 4.99: {от 4.00 до 4.99 включительно}%»). «Between з . 00 and з . 99: {от 3.00 до 3.99 включительно}%». («Между 3.00 и 3.99: {от 3.00 до 3.99 включительно}%»). «Fail : {менее 3.00}%». (« Неудовлетворительно: {менее 3.00}%»). «Average: {средняя оценка}» («Среднее: {средняя оценка}».) лучивших оценку • • • • Результаты должны быть отформатированы до второй цифры после десятичной точки.
378 Глава 8.2. Подготовка к практическому экзамену - часть 11 Примеры ввода и вывода Ввод ~ Вывод Комментарии 1 5 и более: 2 ученика = 33, 33% от 6 students: 33 . 33% 3 Between 4.00 and 4.99: 16 _67% Между 4.00 и 4 . 99: 1 студент 3. 00 и 3. 99: 1 студент 4 Bet ween 3.00 and 3.99: 16 . 67% Между Ниже 3: 2 студента 5 Fail: 33,33% Средний балл: 2 + 3 + 4 + 5 + 6 + 6 1 Average: 3. 70 12, 2 = 22. 2 / 6 = 3. 70 1 2.2 1 Тор Вывод Ввод Комментарии 10 1 1 3.00 5 и более: 3 студента= 30% от 10 2.99 Между 4.00 и 4.99: 3 студента= 5.68 Тор students: 30.00% 30% от 10 3.01 Between 4.00 and 4.99: 30.00% От 3,00 до 3,99: 2 студента= 20% 4 Between 3.00 and 3.99: 20.00% от 10 4 Fail: 20.00% Ниже 3: 2 студента= 20% от 10 6.00 Average: 4.06 Средний балл составляет: 3 + 2.99 4.50 + 5.68 + 3.01 + 4 + 4 + 6 + 4. 50 2. 44 1 + 2.44 + 5 = 40 . 62 / 10 = 4.062 l5 1 Рекомендации и подсказки Из условия видно, что сначала нам будет пр едоставлен о количе­ ство студентов, а затем их оценки. По этой причине мы будем вво­ дить сначала количество студентов. Для о бработки самих оценок мы будем использовать цикл for. Каждая итерация цикла будет считывать и обр абатывать одну оценку: let numberOfStudents = Number(args[0]); for (var i = 1; i < numberOfStudents; i++) { // TODO Пер ед выполнением кода цикла for мы определяем перемен­ ные , в которых будем хранить количество студентов для каждой группы : плохие оценки (до до 2.99), оценки от 3 до 3.99, оценки от 4 4.99 и оценки выше 5. Таюке нам понадобится еще одна перемен­ ная для хранения суммы всех оценок, которую мы будем использо­ вать для вычисления ср еднего балла всех студентов: let let let let let numberOfFailedStudents = 0; numberOfAverageStudents = 0; numberOfGoodStudents = 0; numberOfExcellentStudents = 0; t otalResult = 0;
Задача: рождественская шапка 379 Вернемся назад и объявим еще одну переменную, в которой будет храниться текущая оценка. Переменная будет иметь тип Number, и на каждой итерации мы будем проверять, каково ее значе­ ние. В соответствии с этим значением мы увеличиваем количество студентов в соответствующей группе на 1, не забьmая при этом уве­ личивать общую сумму оценок, которую мы таюке отслеживаем: for (var i = 1; i < numberOfStudents; i++) { let grade = Number(args[i]); totalResult += grade; if (grade < 3) { numberOfFailedStudents++; } else { / / TODO: напишите аналогичный код для других групп } Мы можем р ассчитать, какой процент от общего числа студентов занимает та или иная группа, умножив число студентов в этой груп­ пе на 100, а затем разделив на общее число студентов. Итоговый ре­ зультат мы округляем до второго символа после десятичной точки. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/940#3. Задача: рождественская шапка Напишите программу, которая считьmает целое число соли и рисует рождественскую шапку шириной и высотой 4 + 1 2 * n + 5 строк, как показано в примерах ниже. Примеры ввода и вывода Ввод 4*n Вывод . . . . ./,\ . . . . . . . . . . .\ / . . . . . . . . . *** . . . . . . . . . .*-*-* . . . . . . .*--*--* . . . . . .*---*---* . . .*----*----* . . . *-----*-----* . . *------*------* . *-------*-------* ***************** * * .* .* . * * .* * .* ***************** n из кон­ столбцов
380 Глава Ввод 8.2. Подготовка к практическому экзамену - часть 11 Вывод ••••••••••••• / 1\ ••••••••••••• • • • • • • • • • • • • • \ 1/ ••••••••••••• 7 *** . .. ...... .. . *-*-* .... ... .... . . . . . . . . . . . . *--*--* .......... . . . . . . . . . . . *---*---* ......... . . . . . . . . . . *----*----* ........ . . . . . . . . . *- ----*----- *... .. .. . . . . . . . . *------*------* ...... . *-------*-------* *--------*--------* *---------*--------- * *----------*----------* *-----------*-----------* *------------*------------* *-------------*-------------* ***************************** * * * * * * * * * * * * * * * ***************************** Рекомендации и подсказки В задачах консольного рисования пользователь чаще всего вводит целое число, связанное с общим размером рисуемой фи­ гуры. По скольку в условии указано , как вычисляется общая дли­ на и ширина фигуры, мы можем использовать эти данные в ка­ честве ориентиров. Из примеров хорошо видно, что независимо от вводимых данных первые две строки всегда практически иден­ тичны: ....... / 1\ .. .. .. . . . . . . . . \ 1/ . . . . . . . Мы также замечаем, что всегда присутствуют три последние строки, две из которых абсолютно одинаковы: ***************** * * * * * * * * * ***************** Исходя из этих наблюдений, мы можем вывести формулу для вы­ соты изменяемой части рождественской шапки. Используем фор­ мулу, полученную из условия для общей высоты, вычитая размер неизменной части. Получаем (2 * п + s) - s или 2 * п.
Задача: рождественская шапка 381 Для рисования постоянно меняющейся части фигуры мы будем использовать цикл. Размер цикла будет от О до ширины, которую мы имеем по условию, а именно 4 * n + 1. Поскольку мы будем ис­ пользовать эту формулу в нескольких местах в коде, целесообразно вывести ее в отдельную переменную. Перед выполнением цикла cлe'fJYeT выделить переменные для количества отдельных симво­ лов, участвующих в изменяемой части: точек и тире. Изучив при­ меры, мы таюке можем вывести формулы для начальных значений этих переменных. Изначально количество тире равно О, но количе­ ство точек хорошо видно, его мы можем получить, вычтя 3 из об­ щей ширины (количество символов, составляющих верхнюю часть рождественской шапки), а затем разделить на 2, поскольку количе­ ство точек по обе стороны шапки одинаково: *** . .... . *-*-* ..... . *--*--* *---*---* *----*----* *--- --*--- -- * *------*------* *-------*-------* Осталось только выполнить тело цикла, уменьшая количество 1 после каждой нарисованной линии и увеличивая коли­ тире на 1. Не забудем нарисовать звездочку меЖ'fJУ ними. точек на чество Последовательность рисования в теле цикла выглядит следующим образом: • Строка точек • Звезда • Строка тире • Звезда • Строка тире • Звезда • Строка тире
Глава 382 8.2. Подготовка к практическому экзамену - часть 11 В случае правильной работы программы мы получаем цифры, идентичные приведенным в примерах. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/940#4. Задача: сочетания букв Напишите программу, которая выводит в консоль все сочетания из трех букв в заданном диапазоне, пропуская комбинации, содер­ жащие определенную букву. Вьmедите количество сочетаний. Входные данные Входные данные считьmаются из консоли и содержат три строки: Строчная (малая) буква из английского алфавита, обознача­ • ющая начало диапазона - между «а» и «z». Строчная английская буква для конца диапазона • - между первой буквой и «z». Строчная английская буква • - от ((а» до «z» - поскольку со­ четания, содержащие эту букву, пропускаются. Выходные данные Выведите на одной строке все сочетания, соответствующие тре­ бованиям, с указанием их номера, отделенного пробелом. Примеры ввода и вывода Ввод Вывод Комментарии Все возможные сочетания с буквами "а", 11 а ааа аас аса асс с саа сас сса ссс ь 8 ь 11 и II с 11 : ааа ааЬ аас аЬа аЬЬ аЬс аса ась асс Ьаа ЬаЬ Ьас ЬЬа ЬЬЬ ЬЬс Ьса ЬсЬ Ьсс саа саЬ сас сЬа сЬЬ сЬс сса ссЬ ссс Сочетания , содержащие 'Ь', недействи- тельны . Осталось 8 правильных сочетаний .
Задача: сочетания букв 383 Ввод а вывод ааа ааЬ аас аЬа аЬЬ аЬс аса асЬ асс Ьаа ЬаЬ Ьас ЬЬа ЬЬЬ с ЬЬс Ьса ЬсЬ Ьсс саа саЬ сас сЬа сЬЬ сЬс сса ссЬ ссс z Ввод f k h 27 вывод fff fik gfj gji igg ikf jgk jkj kii ffg fjf gfk gjj igi ikg jif jkk kij ffi fjg ggf gjk igj iki jig kff kik ffj fji ggg gkf igk ikj jii kfg kjf ffk fjj ggi gkg iif ikk jij kfi kjg fgf fjk ggj gki iig jff jik kfj kji fgg fkf ggk gkj iii jfg jjf kfk kjj fgi fkg gif gkk iij jfi jjg kgf kjk fgj fki gig iff iik jfj jji kgg kkf fgk fkj gii ifg ijf jfk jjj kgi kkg fif fkk gij ifi ijg jgf jjk kgj kki fig gff gik ifj iji jgg jkf kgk kkj fii gfg gjf ifk ijj jgi jkg kif kkk fij gfi gjg igf ijk jgj jki kig 125 1 Рекомендации и подсказки В последней задаче у нас присутствует ввод трех аргументов, которые представлены одним символом из таблицы ASCII (http:// www.asciitahle.com/) каждый. Мы можем использовать метод, уже определенный в JavaScript, . charCodeAt( ), который будет использо­ ваться для получения АSСП-кода введенного символа: let startlet ter = args[9].charCodeAt( ) ; / / TODO: п охожим образом считать и остальные символы Давайте подумаем, как мы можем получить конечный резуль­ тат. Если условием задачи является вывод всех символов от начала до конца (опуская определенную букву), то как мы поступим? Самый простой и лучший способ - использовать цикл, чтобы пройтись по всем символам и найти те, которые отличаются от бук­ вы, которую нам нужно пропустить. В JavaScript мы можем перебрать все символы от 'а ' до 'z' следу­ ющим образом: let resul t = for (let i = 11 11 ; ' а' . charCodeAt( ) ; i <= 'z ' . charCodeAt(); i++) {
Глава 384 8.2. Подготовка к практическому экзамену - часть 11 result += String.fromCharCode(i) +" ''; } console.log(result); Метод String. fromCharCode ( ... ) преобразует заданный АSСП­ код в символ. В результате выполнения приведенного выше кода все буквы от а до z включительно будут выведены на одной строке и разделены пробелом. Похоже ли это на конечный результат нашей задачи? Нам нуж­ но найти способ вывести не один, а три символа, как указано в ус­ ловии. Запуск программы очень похож на игровой автомат. Там мы в основном выигрываем, если нам удается выстроить в ряд не­ сколько одинаковых символов. Допустим, в автомате есть места для трех символов. Когда мы останавливаемся на символе в пер­ вом месте, в двух других местах продолжают выстраиваться сим­ волы из всех возможных мест. В нашем случае все возможные буквы - от начальной до конечной, указанной пользователем, и решение нашей программы идентично тому, как работает игро­ вой автомат. Мы используем цикл, который перебирает все символы от на­ чальной до конечной буквы включительно. На каждой итерации первого цикла мы запускаем второй цикл с теми же параметрами (но только в том случае, если в первом ци­ кле буква является правильной, то есть не совпадает с той, которую мы должны исключить по условию). На каждой итерации второго цикла мы запускаем еще один с теми же параметрами и той же проверкой. Таким образом, у нас получится три вложенных цикла, а в теле последнего мы добавим символы к конечному результату: for (char i = startletter; i <= endletter; i++) { if (i != exceptletter) { // TODO: } } запускаем второй и третий циклы
Задача: сочетания букв 385 Не будем забывать, что от нас требуется также вывести общее ко­ личество наЙДенных правильных комбинаций, причем они долж­ ны бьпь выведены на одной строке, разделенные пробелом. Эту подзадачу мы оставляем читателю . Проверка в системе Ju.dge Проверьте свое решение: Index/940#5. https://judge.softuni.bg/Contests/Practice/
Глава 9.1. Задачи для чемпионов - часть 1 В этой главе мы предлагаем читателю несколько более сложных задач, направленных на развитие алгоритмических навыков и ос­ воение приемов программирования для решения задач повышен­ ной сложности. Более сложные задачи по изученному материалу Мы вместе решим несколько задач по программированию, кото­ рые охватывают материал, изученный в книге, но они более слож­ ные, чем обычные задачи вступительных экзаменов в SoftUni. Если вы хотите стать чемпионом по основам программирования, реко­ мендУем потренироваться в решении таких сложных задач, чтобы облегчить себе сдачу экзаменов. Задача: пересекающиеся последовательности У нас есть две последовательности: • последовательность Трибоначчи (аналогия ряда Фибонач­ чи), где каждое число является суммой трех предыдущих (при заданных трех числах); • последовательность, генерируемая числовой спиралью, определяется путем зацикливания по спирали (справа, вниз, влево , вверх, вправо, вниз, влево, вверх и т. д.) матри­ цы чисел, начиная с ее центра, с заданным начальным чис­ лом и шагом приращения, сохраняя текущие числа в по­ следовательности при каждом осуществленном повороте. Напишите программу, которая находит первое число, встречаю­ щееся в обеих последовательностях, заданных вышеупомянутым способом.
Задача: пересекающиеся последовательности 387 Пример Пусть последовательность Трибоначчи начинается с 1, 2 и 3. Это значит, что пер­ вая последовательность будет содержать 1, 2, 3, 6, 11, 20, 37, 68, 125, 230, 423, 778, 1431, 2632, 4841, 8904, 16377, 30122, 55403, 101902 и так далее. числа При этом пусть числа в спирали начи­ наются с 5, а спираль увеличивается на 2 45 ... ... ... ... 17 19 21 ... 55 23 ... ... ... ' ... 15 ... 13 37 ... s --t ►7 _11 9 • ... ... ... ... ... 29 ... ... ... ... ... 65 - на каждом шаге. Тогда вторая последовательность будет содержать числа 13, 17, 23, 29, 37 и так далее. Мы видим, что 37 - 5, 7, 9, это первое чис­ ло, которое встречается в последовательности Трибоначчи и в спи­ ральной последовательности, и это и есть искомое решение задачи. Входнъ1е даннъ1е Входные данные должны считываться из консоли. • В первых трех строках входных данных мы считаем три це­ лых числа, представляющих первые три числа в последова­ тельности Трибоначчи, положительные ненулевые числа, отсортированные в порядке возрастания. • В следующих двух строках ввода мы считаем два целых числа, представляющих первое число и шаг для каждой ячейки матрицы для спирали чисел. Числа, представля­ ющие спираль, являются положительными ненулевыми числами. Входные данные всегда будут действительны и всегда будут иметь описанный формат. Проверять не нужно. Выходнъ1е даннъ1е Результат должен быть выведен в консоль. В единственной строке вывода мы должны вывести наименьшее число, которое встречается в обеих последовательностях. Если в диапазоне [1 ... 1 ООО ООО] нет числа, которое встречается в обеих последовательностях, выведите «No».
Глава 388 9.1. Задачи для ч емпионов - часть 1 Ограничения • Все числа на входе бу-дут находиться в диапазоне [1 ... 1 ООО ООО]. • • Допустимое время вьmолнения программы: Разрешенная память : 0,25 секунды. 16 МБ. Примеры ввода и вывода Ввод 1 Вывод Вывод 13 1 2 3 5 2 37 Ввод Вывод 99 99 99 1 Ввод 25 99 5 2 Ввод 13 Вывод 4 1 No 7 71 23 3 2 2 Рекомендации и советы Задача представляется достаточно сложной, поэтому мы разо­ бьем ее на более простые подзадачи: обработка входных данных, генерация ряда Трибоначчи, генерация числовой спирали и нахож­ дение наименьшего общего числа для двух рядов. Обработка входных данных Первым шагом в решении задачи является обработка входньrх данньrх. Они состоят из пяти цельrх чисел: трех для ряда Трибонач­ чи и двух для числовой спирали: let let let let let tribonacciFirst = Number(args[0]); tribonacciSecond = Number (args[l ] ); t ribonacciThird = Number(args[2]); spiralCurrent = Number(args[З]); spiralStep = Number(args[4]);
Задача: пересекающиеся последовательности 389 После того как мы получили исходные данные, нам нужно поду­ мать о том, как мы будем генерировать числа в двух рядах. Генерация ряда Трибоначчи Для ряда Трибоначчи мы будем каждый раз складывать три пре­ дыдущих значения, а затем смещать значения этих чисел (трех предыдущих) на одну позицию вперед в ряду, то есть значение пер­ вого числа должно принимать значение второго и так далее. Ког­ да мы закончим работу с числом, мы будем хранить его значение в массиве. Поскольку в постановке задачи сказано, что числа в ряду не превышают ряда ровно на 1 ООО ООО, мы можем остановить генерацию этого 1 ООО ООО: let tribonacciNumbers = [tribonacciFirst, tribonacciSecond, tribonacciThird]; let tribonacciCurrent = tribonacciThird; while (tribonacciCurrent < 1000000) { tribonacci(urrent = tribonacciFirst + tribonacciSecond + tribonacciThird; tribonacciNumbers . push(tribonacciCurrent); tribonacciFirst = tribonacciSecond; tribonacciSecond = tribonacciThird; tribonacciThird = tribonacciCurrent; Генерация числовой спирали Нам нужно придумать зависимость между числами в числовой спирали, чтобы мы могли легко генерировать каждое последующее число, не обращаясь к матрицам и их обходам. Если внимательно посмотреть на рисунок из условия, то можно заметить, что за каж­ дые два «витка » спирали числа, которые мы пропускаем, увеличи­ ваются на 1, то есть с 5 до 7 и с 7 до 9 мы не пропускаем ни одного числа, а напрямую прибавляем с шагом ряда. От 9 до 13 и от 13 до 17 мы пропускаем одно число, то есть прибавляем в два раза больше шага. От 17 до 23 и от 23 до 29 мы пропускаем два числа, то есть при­ бавляем три раза шаг и т. д.
Глава 390 9.1. Задачи для ч емпионов - часть 1 Таким образом, мы видим, что для первых двух у нас есть последнее по 2 * число + 1 * шаг , для следующих двух мы прибавляем шаг и так далее. Каждый раз, когда мы захотим перейти к сле­ дующему числу в спирали, нам придется выполнять подобные вы­ числения: spiralCurrent += spiralStep * spiralStepMul; Нам нужно позаботиться о том, чтобы каждые два числа наш множитель (назовем его «коэффициент») увеличивался на 1 (spiralStepMul++), чего можно добиться простой проверкой (spiralCount % 2 == 0). Весь код генерации спирали в массиве при­ веден ниже: let spiralNumbers = [spiralCurrent]; let spiralCount = 0, spi ralStepMul = 1; while (spiralCurrent < 1000000) { spiralCurrent += spiralStep * spiralStepMul; spiralNumbers . push(spiralCurrent); spiralCount++; if (spiralCount % 2 == 0 ) { spiralStepMul++; } } Поиск общего числа для двух строк После того как мы сгенерировали числа в обоих рядах, можно приступать к их объединению и построению окончательного ре­ шения. Как оно будет выглядеть? Для каждого из чисел в одном ряду (начиная с меньшего) мы проверим, существует ли оно в дру­ гом ряду. Первое число, удовлетворяющее этому критерию, и будет ответом на задачу. Поиск во втором массиве мы проведем линейно, а более любо­ пытным дадим возможность оптимизировать его с помощью тех­ ники, назьшаемой Binary Search, поскольку второй массив гене­ рируется отсортированным, то есть удовлетворяет требованию применения такого типа поиска. Код для поиска решения будет вы­ глядеть следующим образом: let found = false; for (let i = 0; i < tribonacciNumbers.length; i++) { for (let j = 0; j < spiralNumbers.length; j++) {
Задача: пересекающиеся последовательности 391 if (tribonacciNumbers[i] == spiralNumbers[j] && tribonacciNumbers[i] <= 1000000) { console . log(tribonacciNumbers[i]); found = true; break; } } if (found) { break; } } i f ( ! found) { console . l og( "No"); } В решении задачи для хранения значений используются масси­ вы. Массивы не являются необходимым условием решения задачи. Существует альтернативное решение, которое генерирует числа и работает с ними напрямую, а не хранит их в массиве. На каждом шаге мы можем проверять, совпадают ли числа в двух строках. Если да, то мы выведем число в консоль и завершим выполнение про • граммы. В противном случае мы увидим текущее число в том ряду, который растет менее прогрессивно, и сгенерируем следующий, в котором мы «отстаем » . Идея заключается в том, что мы будем ге­ нерировать числа из ряда, который «далеко позади», пока не про­ пустим текущее число в дРуrом ряду, а затем наоборот, и если за это время мы найдем совпадение, то завершим выполнение: while (tribonacciCurrent <= 1000000 && spiralCurrent <= 1000000) { if (tribonacciCurrent == spiralCurrent) { // вывести совпавшее число на экран и остановить / / выполнение программы } else if (tribonacciCurrent < spiralCurrent) { // сгенерировать очередное ч исло Трибоначчи } else { // } } сгенерировать очередное число спирали
Глава 392 9.1. Задачи для чемпионов - часть 1 Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/941#0. Задача: магические даты Дана дата в формате «dd-mm-yyy», например 17-03-2007. Вычис­ лите вес этой даты, взяв вс е ее цифры последовательно, умножив каждУЮ цифру на все стоящие после нее и сложив все результаты. В нашем случае у нас 8 цифр: 17032007, поэтому вес равен 1 *7 + 1 *0 + 1*3 + 1*2 + 1*0 + 1*0 + 1*7 + 7*0 + 7*3 + 7*2 + 7*0 + 7*0 + 7*7 + 0*3 + 0*2 + 0*0 + 0*0 + 0*7 + 3*2 + 3*0 + 3*0 + 3*7 + 2*0 + 2*0 + 2*7 + 0*0 + 0*7 + 0*7 = 144. Н аша задача гические даты - написать программу, которая находит все ма­ даты между двумя заданными годами (вклю­ чительно), которые соответствуют весу, вводимому пользова­ телем. Даты должны быть выведены в порядке возрастания (по дате) в формате «dd-mm-yy». Мы будем использовать только дей­ ствительные даты в традиционном календаре (в високосные годы 29 дней в феврале). Примеры ввода и вывода Ввод Вывод 2007 2007 144 Ввод 1 2003 2004 1500 Ввод 2011 2012 14 17-03-2007 13-07-2007 31-07-2007 J Вывод No Вывод 01-01-2011 10-01-2011 01-10-2011 10-10-2011
Задача: магические даты 393 Ввод Вывод 2012 2014 80 09 - 01 - 2013 17-01 - 2013 23 - 03 - 2013 11-07-2013 01-09-2013 10-09-2013 09-10-2013 17-10-2013 07-11-2013 24-11-2013 14-12-2013 23-11 - 2014 13-12- 2014 31-12- 2014 Входнъ1е данные Входные данные содержат три целых числа: • Первое целое число : начальный год. • • Втор ое целое число: конечный год. Третье целое число: вес для поиска дат. Входные данные в сегда будут действительны и всегда будут иметь описанный формат. Пров ерять их не нужно. Въmод данных Результат должен быть выведен в консоль в виде последователь­ ных дат в формате «dd-mm-dd», отсортированных по дате в порядке возрастания. Каждая дата должна быть в отдельной строке. Если магических дат не существует, выведите «No». Ограничения • Начальный и конечный годы - целые числа в диапазоне [1900 - 2100]. Магический в ес - цело е число в диапазоне • • Допустимое время р аботы программы: • Разрешенная память: 16 МБ. 0,25 [1 .. . 1000]. секунды.
Глава 394 9.1. Задачи для чемп ионов - часть 1 Рекомендации и подсказки Начнем с входных данных. В данном случае у нас есть три целых числа : let firstYear = Number (args[0)); let secondYear = Number(args[l]); let numberToSearchFor = Number(args[2]); Имея начальный и конечный год, можно понять, как мы будем перебирать все даты, не путаясь в том, сколько дней в месяце, висо­ косный ли это год и т. д. Перебор всех дат Для перебора мы воспользуемся функциональностью, которую предоставляет объект Date в JavaScript. Мы определим перемен­ ную для начальной даты, что можно сделать с помощью конструк­ тора, который принимает год, месяц и день. Мы знаем, что год - это начальный год, который мы получили в качестве параметра, а месяц и день должны быть январем и 1 -м числом соответственно. В JavaScript «конструктор » Date принимает год в качестве первого аргумента, месяц - в качестве второго (О - январь, 11- декабрь), - в качестве третьего аргумента: new Date(firstYear, 0, 1); а день месяца let date = Получив начальную дату, мы создаем цикл, который будет вы­ полняться до тех пор, пока мы не превысим конечный год (или пока мы не перейдем 31 декабря в конечный год, если мы сравни­ ваем целые даты), увеличиваясь на 1 день на каждом шаге. Для увеличения на один день при каждом обороте мы будем ис­ пользовать метод из Date - setDate( ... ), который добавит один день к текущей дате, которую мы, в свою очередь, возьмем с по­ мощью getDate (). Метод позаботится о том, когда нам переходить к следующему месяцу, сколько дней в месяце, и обо всем, что связа­ но с високосными годами: date.set Date(date.getDate() + 1); В JavaScript мы должны использовать метод getFullYear(), что­ бы получить год в формате, аналогичном тому, который был задан во вводимых данных. Если мы воспользуемся методом то получим количество лет, прошедших с 1900 getYear( ), года до искомой
Задача: магические даты 395 даты, что не подходит для данной задачи. В итоге наш цикл будет выглядеть следующим образом: while (date.getFullYear() <= secondYear) { // проверяем дату для numberToSearchFor dat e . setDate(date .getDate() + 1); } ПримечаIШе : мы можем достичь того же результата с помощью цикла for, инициализация даты происходит в первой части f or, ус­ ловие сохраняется, а шаг увеличивается на один день. Расчет веса Каждая дата состоит р овно из 8 символов (цифр) - 2 для дня (dl, d2), 2длямесяца (dз, d4) и4длягода (d5-d8). Это означает, что каждый раз у нас будет один и тот же расчет, и мы можем воспользоваться этим, чтобы определить формулу (то есть не обращаться к разным цифрам даты, а записать всю формулу). Чтобы записать ее, нам по­ надобятся все цифры даты в отдельных переменных для выполне­ ния всех необходимых умножений. Используя операции деления и в зятия остатка над отдельными компонентами даты, с помощью методов getDay(), getMonth() и getFullYear() мы можем извлечь каждую цифру. Нам нужно быть осторожнь1ми с getMonth(), пото­ му что по аналогии с конструктором этот метод возвращает число от О (январь) до 11 (декабрь) и требует прибавления +1, чтобы полу­ [ 1-12]. Еще один момент, которого следует - целочисленное деление на 10 (/10), которое здесь чить месяц в интервале остерегаться, не будет целочисленным, поэтому после каждого целочисленного деления мы будем явно округлять до наименьшего целого числа, используя метод let dl let d2 = = Math. floor( ...): Math.floor(date.getDate() / 10); // Первая date .getDate() % 10; // Вторая цифра дня let dЗ = Math.floor((date.getMonth() + 1) / 10); let d4 = (date.getMonth() + 1) % 10; // Первая и вторая цифры месяца let dS let dб = = Math .floor(date.get FullYear () / 1000); Math .floor(date .getFullYear() / 100) % 10; цифра дня
Глава 396 9.1. Задачи для ч емпионов - часть 1 let d7 = Math . floor(date.getFullYear() / 10) % 10; let d8 = date.getFullYear() % 10; // Первая, вторая, третья и четвертая цифры года Поясним одну из наиболее интересных строк. Возьмем пример с получением второй цифры года (dб). Здесь мы делим год на 100 и берем остаток от деления на 10. Что мы получаем? Сначала при де­ 100 мы убираем последние 2 цифры года (пример : 2018 / 20). Вычислив остаток от деления на 10, мы получаем послед­ лении на 100 = нюю цифру получившегося числа (20 % 10 = лучаем О, который является второй цифрой 0) и таким образом по­ 2018 года. Осталось произвести вычисления, которые дадут нам магиче­ ский вес даты . Чтобы не прописывать все умножения, как показа­ но в примере, мы применим простую группировку. Нам нужно ум­ ножить каждую цифру на те, что стоят после нее. Вместо того чтобы dl * d2 + dl * dЗ + . . . + dl * d8, мы можем сократить это выражение до dl * (d2 + dЗ + . . . + d8), следуя математическим писать правилам группировки при умножении и сложении. Применив та­ кое же упрощение к оставшимся умножениям, мы получим следу­ ющую формулу: weight = dl * d2 * dЗ * d4 * dS * dб * d7 * (d2 + dЗ + d4 + dS + dб + d7 + d8) + + d4 + dS + dб + d7 + d8) + (d4 + dS + dб + d7 + d8) + (dS + dб + d7 + d8) + (dб + d7 + d8) + (d7 + d8) + (dЗ d8; Вывод результата После того как мы вычислили вес даты, нам нужно проверить, соответствует ли он искомому магическому весу, чтобы знать, нуж­ но ли его выводить или нет. Проверку можно выполнить с помо­ щью стандартного условного оператора i f, а при выводе необ­ ходимо следить за тем, чтобы дата была в пр авильном формате. К счастью, у нас уже есть все цифры, которые нам нужно вывести, а именно от dl до d8. Здесь следует быть осторожным с типами дан­ ных. Поскольку объединение строк и операция сложения вьmолня­ ются с помощью одного и того же оператора, нам нужно преобра­ зовать цифры в строки или начать объединение с пустой строки:
Задача: пять особых букв 397 if (weight == numberToSearchFor) { console.log("" + dl + d2 + " -" + "-" + d7 + d8); found = true; dЗ + d4 + " " + dS + dб + } Внимание: поскольку мы перебираем даты от начального года к конечному, они всегда будут располагаться в порядке возрастания в соответствии с условием. Наконец, если мы не нашли ни одной даты, соответствующей ус­ ловию, в переменной found будет ложное значение (false), и можно вывестиNо : i f ( ! found) { console.log(''No''); } Проверка в системе Ju.dge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/941#1. Задача: пять особых букв Даны два числа: начальное (start) и конечное (end). Напиши­ те программу, которая генерирует все сочетания из пяти букв, ка­ ждая из которых входит в набор {'а', 'Ь', 'с ', 'd ·, • е ·},такие, что вес этих пяти букв является числом в интервале [start ... end] включительно. Выведите их в алфавитном порядке в одну строку, разделяя пробелом. Вес буквы вычисляется следующим образом: weight('a') weight('b') weight('c') weight (' d' ) weight( ' e') = = = = = 5; -12; 47; 7; -32; Вес строки букв cl, с2, ... , cn вычисляется путем удаления всех повторяющихся букв (справа налево), а з атем вычисляется по формуле: weight(cl, с2, ... , cn) = 1 * weight(cn) * weight(cl ) + 2 * weight(c2 ) + ... + n
Глава 398 Например, вес 9.1. - Задачи для ч емпионов часть 1 bcddc вычисляется следующим обр азом: Сначала мы удаляем повторяющиеся буквы и получаем 1 + * weight( ' b') + 2 * weight('c') 2 * 47 + 3 * 7 = 103. + 3 weight ( ' cadae' ) = weight ( 'cade' ) Другой пример: * * 5 + 3 7 + 4 * ( -32) * weight('d ' ) = 1 = * bcd. (-12) 1 * 47 + 2 = -50. Входнъ1е даннъ1е Входные данные содержат два целых числа: • • Начальное число. Конечное число. Входные данные всегда будут действительны и всегда будут иметь описанный формат. Проверять их не нужно. Вывод даннъ~х Результат должен быть выведен в консоль в виде ряда строк, расположенных в алфавитном порядке. Каждая строка должна быть отделена от следующей одним пробелом. Если вес любой из пятибуквенных строк не существует в указанном интервале, выведите «No». Оrра1П1чения • Начальный и конечный номера должны быть целыми чис­ лами в диапазоне • • [-10000 . .. 10000]. Допустимое время работы программы: Разрешенная память : 0,25 секунды. 16 МБ. Примеры ввода и вывода Ввод 40 142 Ввод 300 1400 вывод l ьcead bdcea Комментарии lweight("bcead") weight("bdcea") 1 1 вывод No = = 41 40
Задача: пять особых букв Ввод -1 1 Вывод bcdea eaadd eadad eadde eaead eaeed eeade cebda eaade eadae eadea eaeda eeaad eeaed Ввод 200 300 399 eaaad eaaed eadda eaded eaedd eeada eeead eaada eadaa eaddd eadee eaede eeadd Вывод baadc badca baddc bdabc bdacd beadc ebdac babdc badcb bbadc bdaca bdadc bedac edbac - badac badcc bbdac bdacb bdbac eabdc badbc badcd bdaac bdacc bddac ebadc Рекомендации и подсказки Как и в любой дРуrой задач е, мы начинаем решение с обработки входных данных: let firstNumber = Number(args[0]); let secondNumber = Number(args [l] ) ; В задаче есть несколько ключевых моментов комбинаций длины составление всех 5 из 5 заданных букв, удаление повторяющих­ ся букв и вычисление веса для уже упрощенного слова . Отв ет будет состоять из любого слова, вес которого находится в заданном ин­ тервале [ firstNumber , secondNumbe r ]. Генерация всех комбm1аций Чтобы сгенерировать все комбинации длины волов, мы применим цикл 0...4, 1, исп ользуя 5 сим­ и мы хотим, чтобы каждое число в цикле соответствовало одному символу. Чтобы сгенерировать все комбинации длины 2, используя 5 символов (то есть « аа» , «аЬ» , ..., « Ьа », ...), мы создадим два вложенных цикла, каждый из ко­ торых будет перебирать цифры от О до 4, снова заставляя каждую «ас », цифру соответствовать определенному символу. Мы повторим этот
Глава 400 9.1. Задачи для чемпионов шаг 5 раз, чтобы в итоге получилось 5 вложенных циклов сами il, i2, iЗ, i4 и i5: - часть 1 с индек­ for (let il = 0; il < 5; il++) { for (let i2 = 0; i2 < 5; i2++) { for (let iЗ = 0; iЗ < 5; iЗ++) { for ( let i4 = 0; i4 < 5; i4++) { for (let i5 = 0; i5 < 5; i5++) { } } } } } Учитывая все 5-значные комбинации, нам нужно найти способ «преобразовать» пять цифр в слово с буквами от « а » до «е». Один из способов сделать это - определить простую переменную , содер­ жащую имеющиеся у нас буквы в виде строки: let pattern ''abcde''; = и для каждой цифры мы берем букву из данной позиции. Та­ ким образом, число 00000 станет «ааааа», а число Мы можем составить строку из let fullWord = 02423 - «acecd». 5 букв следующим образом: pattern[i l] + pattern[i2] + pattern[iЗ] + pattern[i4] + pattern[i5]; Другой способ: мы можем преобразовать цифры в буквы, ис­ пользуя их порядок в таблице Выражение нам результат ASCII. String. fromCharCode(' а'. charCodeAt(0) + i) даст 'а ' при i = 0, ' ь ' при i = 1, ' с ' при i = 2 и так далее. Итак, теперь у нас есть все 5-буквенные комбинации, и мы мо­ жем продолжить работу над следующей частью задачи. Внимание : поскольку мы выбрали паттерн, соответствующий алфавитному порядку букв, и циклы осуществляются соответствую­ щим образом, алгоритм будет генерировать слова в алфавитном по­ рядке, и дополнительная сортировка перед выводом не требуется.
Задача: пять особых букв 401 Удаление повторяющихся букв После того как мы получили готовую строку, нам нужно удалить все повторяющиеся символы. Для этого мы будем добавлять буквы слева направо в новую строку, причем каждый раз перед добавле­ нием буквы мы будем проверять, есть ли она там уже - если есть, то мы ее пропустим, а если нет, то добавим. Для начала мы добавим первую букву в начальную строку: let word = pattern(il]; Затем проделаем то же самое с остальными четырьмя, каждый раз проверяя, есть ли они там, с помощью и метода Word indexOf( ...). следующего условия Это можно сделать с помощью цикла full- (оставим это читателю для практики), а можно и «ленивым» способом - с помощью copy-paste: let word = pattern[il]; if (word . indexOf(pattern[i2]) -if (word.indexOf(pattern[iЗ]) -if (word.indexOf(pattern(i4]) -if (word.indexOf(pattern[i5]) -Метод indexOf( ... ) возвращает -1 ) word += pattern[i2]; -1) word += pattern[iЗ]; -1) word += pattern [ i4]; -1) word += pattern[i5]; индекс конкретного элемента, если он найден, или -1, если элемент не найден. Таким образом, каждый раз, когда мы получаем -1, это будет означать, что у нас еще нет этой буквы в новой строке уникальных букв и мы можем ее добавить, а если мы получим значение, отличное от -1, это будет означать, что у нас уже есть эта буква и мы не будем ее добавлять. Вычисление веса Вычисление веса сводится к перебору уникального слова (word), полученного на последнем шаге, для каждой буквы необходимо взять ее вес и умножить на позицию. Для каждой буквы в переборе необходимо вычислить, на какую величину мы будем умножать ее позицию, например, с помощью оператора switch: let multiplier = 0; switch (word[i]) { case 'а': multiplier = 5;
Глава 402 break; case 'Ь': multiplier break; case 1с 1 : multiplier break; case 'd': multiplier break; case , : multiplier break; default: break; 9.1. Задачи для чемпионов - часть 1 = -12; = 47; = 7·, е, = -32; } Получив значение текущей буквы, нужно умножить его на ее позицию. Поскольку индексы в строке отличаются на ных позиций, то есть индекс О - это позиция 1 от 1, индекс 1 - реаль­ позиция 2 и т. д., прибавим к индексам 1: weight += multiplier * (i + 1) ; Все полученные промежуточные результаты необходимо сло­ жить, чтобы получить результат веса 5-буквенной комбинации. Оформление вывода Выводить ли слово на экран, определяется его весом. Нам нуж­ но условие, определяющее, находится ли текущий вес в интерва­ ле [start ... end], заданном нам на входе в начале программы. Если да, то мы печатаем полное слово (fullWord). Будьте внимательны, чтобы не вывести слово из уникальных букв. Оно нам нужно только для вычисления веса! Слова разделяются пробелом, и мы будем накапливать их в про­ межуточной переменной result, которая в начале определяется как пустая строка: if (weight >= firstNumber && weight <= secondNumber) { result += f ullWord +" " ; }
Задача: пять особых букв 403 Последние штрихи Условие выполнено, за исключением случаев, когда в заданном пространстве нет ни одного слова. Чтобы узнать, нашли ли мы та­ resul t свое на­ если да - вывести No, кое слово, можно просто проверить, имеет ли строка чальное значение (а именно пустую строку), иначе вывести всю строку без последнего пробела (с помощью ме­ тода . trim( ... )): if (result == '''') { console . log(''No''); } else { console.log(resul t.trim()); } Проверка в системе Judge Проверьте свое решение: Index/941#2. https://judge.softuni.bg/Contests/Practice/
Глава 9.2. Задачи для чемпионов - часть 11 В этой главе мы рассмотрим еще три задачи, которые мы отно­ сим к категории «для чемпионов», то есть более сложные, чем стан­ дартные задачи в этой книге. Более сложные задачи по изученному материалу Прежде чем перейти к конкретным задачам, уточним, что их можно решить проще, имея дополнительные знания о програм­ мировании и JavaScript (функции, массивы, коллекции, рекурсия и так далее), но любое решение, которое мы дадим сейчас, будет ис­ пользовать только материал, рассмотренный в этой книге. Цель - научиться строить более сложные алгоритмы на основе ваших те­ кущих знаний. Задача: дни страстного шопинга Лина испытывает настоящую страсть к шопингу. Как только у нее появляется немного денег, она сразу же отправляется в первый по­ павшийся торговый центр (молл) и старается потратить как можно больше на одежду, сумки и обувь. Но больше всего она любит зим­ ние распродажи. Наша задача - проанализировать ее странное по­ ведение и подсчитать стоимость покупок, которые Лина совершает при входе в торговый центр, а также деньги, которые у нее остают­ ся после завершения шопинга. Первым аргументом функции будет сумма, которой Лина распо­ лагает перед началом шопинга. Вторым аргументом будет список команд (строк), которые Лина будет выполнять. Получив командУ «mall. Enter», Лина войдет в торговый центр и начнет совершать покупки, пока не получит командУ «mall. Exi t». Как только ЛИна
Задача: дни страстного шопинга 405 начнет совершать покупки, каждый последующий элемент масси­ ва будет представлять действия, которые ЛИНа вьmолняет. Каждый символ в строке представляет собой покупку или другое действие. Строковые команды могут содержать только символы из таблицы ASCII. АSСП-код каждого символа связан с тем, сколько Лина долж­ на заплатить за каждый товар. Интерпретируйте символы следую­ щим образом: • Если символ представляет собой заглавную букву, Лина получает скидку 50 %, а это означает, что стоимость това­ ра будет равна 50 % от числового представления символа из таблицы ASCII. • Если символ - строчная буква, Лина получает скидку на 70 %, а это означает, что товар, который она хочет купить будет стоить на 30 % меньше от числового представления символа из таблицы ASCII. • Если символ - «%», Лина совершает покупку, которая уменьшает сумму ее денег наполовину. • Если символ - «*», Лина снимает деньги с дебетовой карты и добавляет • 10 левов к имеющимся средствам. Если символ отличается от вышеупомянутых, Лина просто совершает покупку без каких-либо скидок, в этом случае просто вычтите значение символа из таблицы ASCII из ее доступных средств. Если лю бое из значений покупки больше, чем текущие доступ­ ные средства, Лина НЕ совершает покупку. Деньги Лины не могут быть меньше О. Шопинг заканчивается, когда поступает команда «mall . Exit». Когда это произоЙДет, вы должны вывести количество совершен­ ных покупок и сумму денег, которые остались у Лины. Входн ые данные Входные данные передаются в двух аргументах. Первым будет сумма, которой Лина располагает перед началом покупок. Вторым аргументом будет массив команд, который обрабатывается после­ довательно. При передаче команды «mall . Enter» каждый последу-
Глава 406 9.2. Задачи для чемпионов - часть 11 ющий элемент будет представлять собой строку, содержащую ин­ формацию о покупках/действиях, которые Лина хочет совершить. В массиве будут команды, которые должны быть выполнены до по­ «mall. Exit ». лучения команды «mall. Enter» Будет дана только одна команда манда и только одна ко­ «mall.Exit». Выходные данные должны быть выведены в консоль. Когда ша­ пинг завершится, вы должны вывести в консоль определенный вы­ вод в зависимости от того, какие покупки были сделаны. • Если покупок не было - «No purchases. Мопеу left: {оставшиеся средства}lv. » (« Покупок нет . Осталось денег: {оставшиеся средства} • lv.». Если сделана хотя бы одна покупка purchases . Money left : покупок} lv . » (''{количество покупок} {оставшиеся средства} - «{количество {оставшиеся средства} покупок'' . Осталось денег: lv"). Суммы должны быть выведены с точностью до двух символов после десятичной точки. Ограничения • Деньги [0 - 7. 9 • это число с плавающей точкой в диапазоне: х 1028]. Количество строк между ((mall. Enter» и «mall. Exi t» будет находиться в диапазоне: [1-20]. • Количество символов в каждой строке, представляющей собой команду, будет находиться в диапазоне: • Допустимое время выполнения: • Разрешенная память: Примеры ввода и вывода Ввод 110 mall.Enter % lmall.Exit Вывод 1 purchases . Money left: 55.00 lv. 16 МБ. 0,1 секунды. [1 -20].
Задача: дни страстного шопинга Ввод 407 вывод 100 mall . Enter АЬ ** purchases . Money left: 58.10 lv. 2 mall . Exit Ввод 1 вывод Комментарии 1 purchases. 'd' 110 mall.Enter Money left: d 80 . 00 lv . mall . Exit имеет ASCII-кoд с т рочная буква, и 100. 'd' - за это Лина полу- 70 %, поэтому она тратит 30 % * 100 = 30 левов . После покупк и у нее остае тся 110 - 30 = 80 лв. чает скидку 1 Рекомендации и подсказки Разделим решение задачи на три основные части: • Обработка входных данных. • Ашоритм решения. • Форматирование вывода данных. Рассмотрим каждую часть подробнее. Обработка входных данных Входные данные для нашей задачи состоят из нескольких ком­ понентов: • В первом аргументе у нас есть все деньги, которые Лина сможет потратить на покупки. • Во втором массиве у нас будет серия команд. Имея непосредственно деньги, которыми располагает Лина, мы можем приступить к обр аботке полученных команд. Однако здесь есть одна деталь, с котор ой нужно быть осторожнь1м. Усло ­ вие выглядит следующим образом: «Вторым аргументом будет ма с­ сив команд, который обрабатывается последовательно. При полу­ чении команды «mall. Enter» каждый последующий элемент будет пр едставлять собой стр оку, содержащую информацию о покупках/ действиях, которые хочет совершить Лина».
Глава 408 9.2. Задачи для чемпионов - часть 11 В этот момент нам нужно помнить, что мы должны начать об­ рабатывать команды в массиве, но только после того, как получим команду цикла «mall . Enter». while или Как мы можем это сделать? Использование do-while будет хорошим выбором. Вот пример ре­ шения, как мы можем перебрать все команды до получения коман­ ды «mall. Enter»: while (command !== 'mall . Enter') { i++; command = command[i]; // command = command[++i]; } Вы можете заменить этот цикл только условие и шаг while на цикл for, используя for. Здесь следует отметить, что вызов i++ в начале кода внутри цик­ ла используется для перехода к первой обрабатываемой команде, по­ скольку в конце цикла command [ i] указывает именно на которая не должна обрабатываться как действие «mall. Enter», mall. Алгоритм pemelПIЯ задачи Сам алгоритм решения задачи прост - мы продолжаем об­ рабатывать команды до тех пор, пока не будет выдана команда «mall. Exit». За это время мы проверяем каждый символ (char) ка­ ждой команды на соответствие правилам, указанным в условии, и одновр еменно изменяем количество денег, которые есть у Лины, и сохраняем количество покупок. Рассмотрим первые две проблемы, стоящие перед нашим алго­ ритмом. Первая проблема связана с тем, как мы можем считывать команды, пока не встретим «mall. Exi t». Решение, как мы видели выше, заключается в использовании цикла while. Вторая проблема заключается в том, чтобы получить доступ к каждому символу за­ данной команды. Учитывая, что входные данные команды имеют тип string, самый простой способ получить доступ к каждому сим­ волу во вводимых данных команды - это цикл for. Вот как будет выглядеть использование двух таких циклов: for (; commands[i] !== "mall.Exit"; i++) { command = commands[i];
Задача: дни страстного шопинга 409 for (let action of command) { // TODO: обработка на команды } } Следующая часть нашего алгоритма - обработка символов из команд в соответствии со следующими правилами из условия: • Если символ представляет собой заглавную букву, Лина по­ 50 %, лучает скидку дет равна 50 % что означает, что стоимость товара бу­ от числового представления символа из та­ блицы ASCII. • Если символ на 70 %, что строчная буква, Лина получает скидку - означает, что товар, который она хочет купить, будет стоить на 30 % меньше от числового представления символа из таблицы ASCII. • Если символ - «%», Лина совершает покупку, которая уменьшает ее деньги наполовину. • Если символ-«*», Лина снимает деньги с дебетовой карты и добавляет • 10 левов к имеющимся средствам. Если символ отличается от вышеупомянутых, Лина просто совершает покупку без каких-либо скидок, в этом случае просто вычтите значение символа из таблицы ASCII из ее доступных средств. Давайте рассмотрим про блемы в первом условии, с которыми мы сталкива емся . Первая - как определить, что символ представ­ ляет собой заглавную букву. Мы можем использовать один из двух способов: • Учитывая тот факт, что буквы в алфавите имеют порядок, мы можем использовать следующую проверку 'д' && action <= 'z ', чтобы action >= проверить, находится ли наш символ в диапазоне заглавных букв. • Мы можем использовать метод str. toUpperCase() и срав­ нить, совпадает ли символ с тем, который мы получим от str. toUpperCase( ). Другая проблема - как обработать символ, если он обозначает операцию, требующую больше денег, чем есть у Лины? Это можно сделать с помощью оператора continue.
Глава 41 0 9.2. Задачи для чемпионов - часть 11 Пример пр оверки первой части условия выглядит следующим образом: if (action >= let price 'А' && action <= 'Z') { action . charCodeAt() * 0.5; = if (shoppingMoney < price) { continue; } shoppingMoney purchases++; -= price; } Примечание: purchases - переменная целочисленного типа, в которой хранится количество всех покупок. Мы полагаем, что у читателя не возникнет проблем с реализаци­ ей всех остальных проверок, поскольку они очень похожи на первую. Форматирование въmода В конце задачи нам нужно вьmести некоторый вывод, завися­ щий от следующего условия: • Если покупок не было осталось } • - «No purchases. Money left: lv.». Если была совершена хотя бы одна покупка покупок} {денег purchases . Money left: «{количество {осталось денег} lv. ». Операции вывода тривиальны. Исходя из переменной количества покупок, мы можем определить, какая версия вьmода нам нужна. Единственное, о чем нужно помнить, - деньги должны быть вьmеде­ ны с точностью до двух символов после десятичной точки. Как мы мо­ жем этого добиться? Ответ на этот вопрос мы оставим читателю. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/942#0. Задача: числовое выражение Бонни - чрезвычайно могущественная ведьма. Поскольку силь1 природы недостаточно для успешной борьбы с вампирами и обо­ ротнями, она начала осваивать силу Выражений. Выражением
Задача: числовое выражение 411 очень сложно овладеть, так как заклинание опирается на способ­ ность быстро решать математические выражения. Чтобы использовать «заклинание Выражения», ведьма должна заранее знать результат математического выражения. Заклинание Выражения состоит из нескольких простых математических выра­ жений. Каждое математическое выр ажение может содержать опе­ раторы сложения, вычитания, умножения и/или деления. Выражение решается без учета математических правил оценки числовых выражений. Это означает, что порядок операторов име­ ет приоритет над тем, какое вычисление они производят. Выраже­ ние может содержать круглые скобки, при этом все, что находится в скобках, оценивается в первую очередь. Любое выражение может содержать несколько круглых скобок, но не может содержать вло­ женных круглых скобок: • • Выражение, содержащее (... (. ..)...), не является допустимым. Выражение, содержащее (. ..)... (. ..), является допустимым. Пример Выражение 4 + 6 / 5 + ( 4 * 9 - 8) / 7 * 2 решается следующим образом: 4 + 6 / 5 + (4 * 9 - 8) / 7 * 2 10 / 5 + (4 * 9 - 8) / 7 * 2 = 2 + (4 * 9 - 8) / 7 * 2 = 2 + (36 - 8) / 7 * 2 = 2 + 28 / 7 * 2 = 30 / 7 * 2 = 4.285714285714286 * 2 = 8.57172857142571 = 8.57 = Бонни очень красива, но не столь мудра, поэтому ей нужна наша помощь, чтобы овладеть силой Выражений. Входные данные Входные данные состоят из одного аргумента. Он содержит мате­ матическое выражение, которое нужно вычислить. Аргумент всег­ да заканчивается символом «=». Символ«=» указывает на конец ма-
Глава 412 9.2. Задачи для чемпионов - часть 11 тематического выражения. Входные данные всегда действительны и имеют описанный формат. Проверять их не нужно. Вывод данных Результат должен быть выведен в консоль. Вывод состоит из од­ ной строки -результата вычисленного математического выраже­ ния. Результат должен быть округлен до второй цифры после деся­ тичной точки. Ограничения • • Выражения состоят максимум из Числа каждого математического выражения будут нахо­ диться в диапазоне • [1 ... 9]. Операторы в математических выражениях всегда будут на­ ходиться в диапазоне ние) или • 2500 символов. + (сложение), - (вычитание), / (деле­ * (умножение) . Результат математического выражения будет находиться в диапазоне • • [-100000.00 ... 100000.00]. Допустимое время выполнения: 0,1 секунды. Допустимый объем памяти: 16 МБ. Примеры ввода и вывода Ввод Вывод 4+6/5+(4*9-8) / 7*2= 18.57 Ввод Вывод 3+(6/5)+(2*3/7)*7/2*(9/ 4+4*1)= 1110 . 63 Рекомендации и подсказки Обычно мы сначала считываем и обрабатываем входные дан­ ные, затем решаем задачу и, наконец, выводим результат, отформа­ тированный в соответствии с условием. В данном случае входные данные состоят из одного аргумента, который не нужно обрабаты­ вать . Поэтому мы переходим непосредственно к решению задачи. Алгоритм решения задачи Для решения нашей задачи нам понадобится несколько пере­ менных: • Одна переменная, в которой мы будем хранить текущий ре­ зультат.
Задача: числовое выражение • 41 3 Переменная, где мы будем хранить индекс, которого мы до­ стигли в процессе обхода нашего выражения. • Одна переменная, в которой будет храниться текущий сим­ вол, который мы обрабатываем. • И последняя переменная, в которой мы будем хранить текущий оператор нашего выражения. let let let let result = 0; index = 0; symbol = expression[index]; expressionOperator = '+'; Теперь, когда у нас есть начальные переменные, нам нужно подумать о том, какой будет основная структура нашей програм­ мы. Из условия мы понимаем, что каждое выражение заканчива­ ется на=, то есть мы должны будем обрабатывать символы до тех пор, пока не встретим =. СледУЮщим шагом будет написание цик­ ла while: while (symbol != '=') { // TODO: обработка символов } СледУЮЩИМ шагом будет обработка нашей переменной symbol. Для нее у нас есть три возможных случая: • Если символ является началом подвыражения, заключен­ ного в круглые скобки, то есть встречается символ • Если символ - это цифра от О до 9. (. Но как мы можем это проверить? Как проверить, является ли наш символ циф­ рой? Здесь на помощь приходит АSСП-код символа, по ко­ торому мы можем воспользоваться следующей формулой: (ASCII-кoд нашего символа] - [ASCII-кoд символа 0] = [цифра, обозначающая символ] . Если результат этой проверки находится в диапазоне от О до 9, то наш символ действитель­ но является числом. (В качестве альтернативы можно ис­ пользовать символы 'О ' и ' • Если символ является оператором, то есть это+, - , * или/. if (symbol == ""') { // TODO: обработка } 9' или их АSСП-коды напрямую). вложенного выражения
Глава 414 9.2. Задачи для чемпионов - часть 11 else if (0 <= symbol - '0' && symbol - ' 0' <= '9') { // TODO: обработка числа } else if (symbol -- '+' 1 1 symbol -- ' ' 11 symbol -- ' *' ) { // TODO: обработка оператора } Давайте рассмотрим, какие действия нам нужно выполнить в со­ ответствующих случаях, которые мы определили: • - Если наш символ сделать, это оператор, то все, что нам нужно установить новое значение переменной expressionOperator. • Если наш символ - цифра, то нам нужно изменить р е­ зультат текущего выражения в зависимости от текущего оператора, то есть если expressionOperator - это - , то нам нужно уменьшить результат на числовое представление текущего символа. Мы можем взять числовое представ­ ление текущего символа, используя формулу, которую мы применяли при проверке этого случая нашего символа] [ASCII-кoд символа0] ( [ASCII-кoд = [ цифра, представляющая символ]). else if (0 <= symbol - '0' && symbol - '0' <= 9) { switch (expressionOperator) { case ' + ' : result += symbol - '0'; break; / / TODO: дописать остальные операторы } } else if (symbol == ' +' 11 symbol -- ' ' 11 symbol == '/' 11 symbol == '*') { expressionOperator = symbol; } • Если наш символ - (, это означает начало подвыражения (выражение в круглых скобках). По определению подвыра-
Задача: числовое выражение 415 жение должно быть оценено до изменения результата все­ го выражения (сначала вьmолняются действия в круглых скобках). Это означает, что у нас будет локальный результат для нашего подвыражения и локальный оператор. if (symbol == '(') { let innerResult = 0; let innerOperator = '+ ' ; index++; symbol = expression[index]; / / ++index Затем, чтобы вычислить значение подвыражения, мы ис­ пользуем те же методы, что и для вычисления основного выра­ жения - с помощью цикла не встретим символ )). while обрабатываем символы (пока В зависимости от того, является ли счи­ танный символ цифрой или оператором, мы изменяем результат подвыражения. Реализация этих операций аналогична реализации вычисления выражений, описанной выше, поэтому мы думаем, что у читателя не возникнет с ней проблем. Закончив вычисление результата нашего подвыражения, мы изменяем результат всего выражения в зависимости от значения expressionOperator: swit ch (expressionOperator) { case '+': result += innerResult; break; / / TODO: Дописать остальные операторы } Форматирование вывода Единственный сти в консоль, - вывод, который программа должна выве­ это результат решения выражения с точностью до двух знаков после десятичной точки. Как отформатировать вы­ вод таким образом? Ответ на этот вопрос мы оставляем читателю. Проверка в системе Judge Проверьте свое решение: Index/942#1. https://judge.softuni.bg/Contests/Practice/
Глава 416 9.2. Задачи для чемпионов - часть 11 Задача: быки и коровы Все мы знаем игру «Быки и коровы» Bulls_and_cows). (http://en.wikipedia.org/wiki/ При наличии определенного четырехзначного се­ кретного числа и четырехзначного предлагаемого числа действу­ ют следующие правила: Если цифра в предложенном числе совпадает с цифрой в се­ • кретном числе и находится в той же позиции, у нас есть бык. Если цифра в предложенном числе совпадает с цифрой в се­ • кретном числе, но находится в другой позиции - корова. Вот несколько примеров: Тайное число Предполагаемое число 1 4 8 1 8 8 1 1 2 2 4 1 9 9 2 4 1 1 1 Тайное число Предполагаемое число Комментарий 1 1 Быки =1 ~ коровы = 2 Коммента рий Быки= ! коровы 0 = 2 Задано тайное число и количество быков и коров, наша зада­ ча найти все возможные предположения тайного числа в поряд­ - ке возрастания. Если не найдется ни одного угаданного числа, удовлетворяюще­ го заданным критериям, в консоль должно быть выведено сообще­ ние «No». Входнъ1е даннъ1е Входные данные состоят из трех аргументов: • • • Первый содержит тайное число. Второй - количество быков. Третий - количество коров. Входные данные всегда будут верными. Проверять их не нужно. Вывод даШiых Результат должен быть выведен в консоль. Вывод должен состо­ ять из одной строки - все предполагаемые числа, разделенные од-
Задача: быки и коровы 41 7 ним пробелом. Если не существует предполагаемых чисел, удов­ летворяющих критериям, заданным в консоли, то должно бьпь выведено «No». Оrраничеиия • Тайное число всегда будет состоять из [1 . . 9]. 4 цифр в диапазоне (Цифры должны быть уникальными. Если у меня есть секретное число 2132 и я угадьmаю 8762, то у меня есть 1 бык и 1 корова для одного числа.) • Количество коров и быков всегда будет находиться в диапазоне [0 .. . 9]. (Имеет ли смысл иметь коров и быков в ко- личестве 0... 9? При каком случае у меня будет 5 быков и 7 коров? Ввод должен быть корректным). • • Допустимое время выполнения: Разрешенная память: 0,15 секунды. 16 МБ . Примеры ввода и вывода Ввод вывод 1222 228 ~ 2286 2825 1 8224 2122 2287 2826 8225 2212 2289 2827 8226 2232 2292 2829 8227 2242 2322 2922 8229 1 2252 2262 2272 2281 2283 22842285 1 2422 2522 2622 2722 2821 2823 2824 3222 4222 5222 6222 7222 8221 8223 9222 1 вывод Ввод 1234 1134 1214 1224 1231 1232 1233 1235 1236 1237 1238 1239 1244 3 1254 1264 1274 1284 1294 1334 1434 1534 1634 1734 1834 1934 0 2234 3234 4234 5234 6234 7234 8234 9234 1 Рекомендации и подсказки Поскольку входные данные поступают напрямую, нам остаются следующие шаги решения в качестве аргументов функции: • Сгенерируем все возможные четырехзначные комбинации (кандидаты на проверку). • Для каждой сгенерированной комбинации подсчитаем, сколько в ней быков и сколько коров по отношению к се-
Глава 41 8 9.2. Задачи для чемпионов - часть 11 кретному числу. Если количество быков и коров совпадает с искомым числом, то мы вьmедем комбинацию на печать . Алгоритм pemelПIЯ задачи Прежде чем мы начнем писать алгоритм решения нашей зада­ чи, нам нужно объявить булеву переменную, котор ая будет пока­ зьmать, найдено ли решение: let solutioпFouпd = false; Если после завершения р аботы алгоритма этот флаг все еще бу­ дет ложным, то мы выведем в консоль No, как указано в условии : if (!solut ionFound) { console.log('No'); } Давайте начнем обдумывать нашу задачу. Нам нужно проана­ лизировать все числа от 1111 до 9999, исключая те, которые содер­ жат нули (например, 9011, 3401 и т. д. недействительны) . Как проще всего сгенерировать все эти числа? С помощью вложенных циклов. Поскольку у нас 4-значное число, у нас будет 4 вложенных цикла, каждый из которых будет генерировать отдельную цифру нашего числа для проверки. Альтернативным подходом является обход чисел от 1111 до в одном цикле и пропуск всех чисел с ' О ', но это немного 9999 изменит решение, которое мы реализуем ниже. for (let digitl = 1; digitl <= 9; digitl++) { for (let digit2 = 1; digit2 <= 9; digit2++ ) { for (let digitЗ = 1; digitЗ <= 9; digitЗ++) { for ( let di gi t4 = 1; digit4 <= 9; digit 4++) { Благодаря этим циклам у нас есть доступ к каждой цифре всех чисел, которые нам нужно проверить. Наш следующий шаг - раз­ делить секретное число на цифры. Этого можно легко добиться с помощью комбинации целочисленного деления и вычисления остатка от деления: let guessDigitl = Math.floor(guessNumber / 1000 ) % 10;
Задача: быки и коровы 419 Каким образом? При делении мы получаем дРобное число. Нуж­ но либо удалить дРобную часть перед делением по модулю 10 с по­ мощью Math. floor( ... ), либо привести к целому числу с помощью parseint( ... ). В примере выше мы удаляем дробную часть. Остались два последних шага перед тем, как мы начнем ана­ лизировать, сколько коров и быков в числе. Соответственно, пер­ вый - это объявление переменных-счетчиков (counter) в наших вложенных циклах для подсчета коров и быков для текущего чис­ ла. Второй шаг - создание копий цифр текущего числа, которое мы собираемся анализировать, чтобы избежать проблем с произ­ водительностью вложенных циклов, если мы внесем в них изме­ нения: let digitToChec kl let digitToCheck2 let digitToCheckЗ let digitToCheck4 = = digitl; digit2; = digitЗ; = digit4; let currentBulls = 0; let currentCows = 0; Теперь мы готовы приступить к анализу сгенерированных чи­ сел. Какую логику мы можем использовать? Самый элементарный способ проверить, сколько коров и быков содержится в числе, это серия проверок - if-else. Да, это не самый оптимальный способ, но ради того, чтобы не использовать знания, выходящие за рамки этой книги, мы выберем именно такой подход. Какие проверки нам нужны? Проверка на наличие быков элементарна - мы проверяем, со­ впадает ли первая цифра генерируемого числа с той же цифрой тайного числа. Затем удаляем проверенные цифры, чтобы избе­ жать повторения быков и коров: / / Находим всех быков, считаем и удаляем (присваиваем -1 и -2) if (digitToCheckl == guessDigitl) { // Бык на позиции #1 найден-> подсчитываем и удаляем currentBulls++; guessDigitl = -1; digitToCheckl = -2; }
Глава 420 9.2. Задачи для чемпионов - часть 11 Повторяем действия для второй, третьей и четвертой цифр. Проверка на наличие коров может быть вьmолнена следующим образом - сначала проверяем, совпадает ли первая цифра сгенери­ рованного числа со второй, третьей или четвертой цифрой тайно­ го числа. Мы можем объединить все проверки в одно условие, зная, что во всех трех случаях у нас есть корова, но мы не будем знать, какую цифру нужно удалить, поэтому вьmисываем их по очереди: // Находим всех коров для digitToCheckl, считаем их / / и удаляем (присваиваем - 1) if (digitToCheckl == guessDigit 2) { / / Корова на позиции #2 найдена-> и удаляем увеличиваем счетчик ее currentCows++; guessDigit2 = -1; } Затем мы последовательно проверяем, совпадает ли вторая циф­ ра сгенерированного числа с первой, третьей или четвертой циф­ рой секретного числа, совпадает ли третья цифра сгенерированно­ го числа с первой, второй или четвертой цифрой секретного числа, и, наконец, проверяем, совпадает ли четвертая цифра сгенериро­ ванного числа с первой, второй или третьей цифрой секретного числа. Вывод результата После того как мы выполнили все проверки, нам остается только проверить, совпадают ли быки и коровы в текущем сгенерирован­ ном числе с желаемыми быками и коровами, считанными из кон­ соли. Если да, то вьmодим текущее число в консоль:
Задача: быки и коровы 421 if (currentBulls == targetBulls && currentCows -- targetCows) { if (solutionFound) { console.log('' ''); } console . log(digitl + ' ' + digit2 + '' + it4); solutionFound = true; digitЗ + '' + dig- } Проверка в системе Judge Пр оверьте свое решение: Index/942#2. https://judge.softuni.bg/Contests/Practice/
Глава 10. Функции JavaScript известен как функциональный язык программирова­ ния. Само название подРазумевает, что функции являются чрезвы­ чайно важной частью этого языка. В данной главе мы узнаем о функциях и о том, что они собой представляют, а таюке об основных концепциях работы с ними. Мы узнаем, почему их использование является хорошей практикой, как их объявлять и как вызывать. Мы узнаем о параметрах и воз­ вращаемом значении функции, а таюке о том, как использовать это возвращаемое значение. В конце главы мы рассмотрим сложившу­ юся практику использования функций. Что такое функция? К данному моменту мы убедились, что при написании кода про­ граммы, решающей проблему, проще разделить ее на части. Ка­ ждая часть отвечает за определенное действие, и это не только об­ легчает решение задачи, но и значительно улучшает читаемость кода и возможность отследить ошибки. Каждый кусок кода, который выполняет заданную функцио­ нальность и который мы логически разделили, называется функ­ цией. Вот что такое функции - части кода, которые мы именуем определенным образом и которые можно вызывать столько раз, сколько нам нужно, и они будут вьmолнены соответствующее ко­ личество раз. Функцию можно вызьmать столько раз, сколько нам нужно для решения задачи. Это избавляет нас от необходимости повто­ рять один и тот же код несколько раз и снижает вероятность про­ пустить ошибку при возможном исправлении кода.
Что такое фун кция? 423 Простые функции Простые функции отвечают за выполнение действия, которое помогает решить конкретную задачу. Такими действиями могут быть вьmод строки в консоль, выполнение некоторой проверки, выполнение цикла и т. д. Рассмотрим следующий пример простой функции: function printHeader( ) { conso 1 е . 1 og ( " ---------- " ) ,· } Эта функция вьmолняет задачу вывода заголовка, который пред­ ставляет собой строку символов Круглые скобки -. Поэтому ее имя - printHeader. ( и ) всегда следуют за именем, независимо от того, как мы назвали функцию. Позже мы рассмотрим, как следует на­ зывать функции, с которыми мы работаем, а пока просто отметим: важно, чтобы имя функции описьmало действие, которое она вы­ полняет. Тело функции содержит программный код, который находится между фигурными скобками { и }. Между ними помещается код, ко­ торый решает задачу, описанную именем функции. Зачем использовать функции? К данному моменту мы выяснили, что функции помогают раз­ бить большую задачу на более мелкие части, что приводит к более легкому решению поставленной задачи. Это делает нашу програм­ му не только лучше структурированной и легче читаемой, но и бо­ лее понятной. С помощью функций мы избегаем повторения программного кода. Повторяющийся код - это плохая практика, так как он делает программу очень сложной для сопровождения и приводит к ошиб­ кам. Если кусок кода присутствует в нашей программе несколь­ ко раз и нам нужно что-то изменить, то изменения должньr вно­ ситься в каждую итерацию кода, о котором идет речь. Вероятность пропустить место, где нужно сделать исправление, очень высока, что приведет к некорректному поведению программы. Именно по­ этому, если фрагмент кода используется в программе более одного раза, рекомендуется оформлять его в виде отдельной функции.
Глава 424 1О. Функции Функции дают нам возможность использовать фрагмент кода несколько раз. Решая все больше и больше задач, вы обнаружи­ те, что использование уже объявленных функций экономит много времени и сил. Объявление функций В JavaScript мы можем объявлять функции буквально в любом месте, точно так же, как мы можем объявлять переменные в любом месте. Объявление - это регистрация функции в программе, чтобы она распознавалась в остальной части программы. JavaScript не является сильно типизированным языком. Поэто­ му, когда мы объявляем функцию, у нее нет типа (строка, число, массив и т. д.), как у методов и функций в дРуrих языках програм­ мирования. В JavaScript существует два основных способа объявления функ­ ций: декларативный - объявление функции и экспрессивный выражение функции. Декларативно (function declaration) В следующем примере мы рассмотрим необходимые элементы при декларативном объявлении функции (объявление функции): function getSquare(n) { return n * n; } • Ключевое слово ключевого function. Мы начинаем с использования слова function, чтобы объявить, что сейчас бу­ дет происходить объявление функции. Мы назьmаем его ключевым словом, потому что оно зарезервировано в языке JavaScript, или, дРуrими словами, мы не можем так назвать переменную. • Имя функции. Имя функции задаем мы сами, помня, что оно должно описывать задачу, которую выполняет код в теле функции. В примере имя о том, что задача этой квадРата. getSquare, что говорит нам функции - вычислить площадь
Объявление функций • 425 Список параметров. Он объявляется между скобками ( и ), которые мы пишем после имени. Здесь перечисляется по­ следовательность параметров, которые будет использовать функция. Может присутствовать только один параметр, несколько параметров или это может быть пустой список. Если параметров нет, мы просто напишем круглые скобки ( ) . В данном примере мы объявляем параметр n. • Тело функции. Оно объявляется между фигурными скобка­ ми {и}, которые мы пишем сразу после закрывающей ). В теле функции мы описываем в коде все операции, кото­ рые должна въmолнить функция. В теле функции мы опи­ сываем алгоритм, с помощью которого функция решает проблему. Мы реализуем логику функции. В приведенном примере мы вычисляем площадь квадрата, а именно n * n. При объявлении функций важно соблюдать последовательность основных элементов - сначала ключевое слово function, затем имя функции, список параметров, заключенный в круглые скобки (), и, наконец, тело функции, заключенное в фигурные скобки {}. Экспрессивно (function expression) В следующем примере мы р ассмотрим необходимые элементы в объявлении функции экспрессивно (выражение функции). Оно очень похоже на декларативное, которое мы уже рассматривали, и можно сказать, что это комбинация объявления переменной и де­ кларативного объявления функции (объявление функции): let getSquare = function getSquareFunc(n) { return n * n; } • Ключевое слово слова let, let. Начнем с использования ключевого которое мы используем, чтобы объявить пере­ менную . • Имя переменной. Имя переменной задается нами. В приме­ ре имя getSquare, и это ной функции - • говорит нам о том, что задача дан­ вычислить площадь квадрата. Объявление функции. Используется та же структура, ко­ торую мы уже изучили в объявлении функции - сначала
Глава 426 ключевое слово function, 1О. Функции затем имя функции, список пара­ метров, заключенный в круглые скобки (), и, наконец, тело функции, заключенное в фигурные скобки{}. Особенность этого случая в том, что имя функции не является обязатель­ ным элементом, но рекомендуется привыкнуть к его добав­ лению. В примере программа будет работать без проблем, даже если мы опустим имя getSquareFunc. Если мы опуска­ ем имя, то функция называется анонимной. Когда мы объявляем переменную в теле функции (с помощью ключевого слова let или const), мы называем ее локальной пере­ менной функции. Область, в которой эта переменная существует и может быть использована, начинается со строки, где мы е е объ­ явили, и продолжается до закрывающей фигурной скобки } тела функции. Эта область называется областью видимости перемен­ ной (variaЫe scope). Декларативно или экспрессивно Разница между объявлением функции с помощью деклар ации или выражения относительно пр оста. В се функции, объявлен­ ные пер вым спо собом, за гружаются в память программы до на­ чала ее выполнения, в то время как программа узнает о функци­ ях, объявленных с помощью выражения функции, только когда начинает выполнение и достигает строки, на которой объявлена функция. Н а практике это означает, что вы можете вызвать функцию, объявленную декларативно, даже в некоторых предшествую­ щих строках - до ее объявления, тогда как если вы попытаетесь сделать это с помощью выражения функции, прогр амма выдаст ошибку о том, что она не распознает эту функцию во время вы­ п олнения. Вызов функций Выз ов функции - это инициирование вьmолнения кода, находя­ щегося в теле функции. Для этого нужно набрать имя функции, за­ тем круглые скобки printHeader(); () и знак ; для завершения строки. Вот пример:
Вызов функций 427 Функция может быть вызвана из нескольких мест в нашей про ­ грамме. Один из способов - вызвать ее из основной области види­ мости программы (глобальная область видимости) : function printHeader( ) { console.log( '' ----------'' ) ; } printHeader(); Также функцию можно вызвать из тела другой функции, кото ­ рая не является основной областью видимости нашей программы: function printHeader( ) { conso 1 е . 1 og ( " ---------- " ) ,· } function printMessage( ) { / / вызов функции из тела printHeader(); другой фун к ции } Есть возможность вызвать функцию из ее собственного тела. Это называется рекурсией, и вы можете найти дополнительную информацию о ней в Википедии (https://ru.wikipedia.org/wiki/Peкyp­ cия) или самостоятельно поискать ее в Интернете. Пример: пустой чек Напишите функцию, которая выводит пустой чек. Эта функция должна вызывать три другие функции: одну для вывода заголовка, одну для тела чека и одну для нижней части. Текст Часть чека CASH RECEIPT Заголовок Тело чека Ни жняя часть Charged to Received Ьу (с) SoftUni
Глава 428 1О. Функции Пример ввода и вывода Ввод Вывод CASH RECEIPT (нет) Charged to Received Ьу (с) SoftUni Рекомендации и подсказки Первым делом мы создадим функцию для вьmода заголовка чека. Дадим ей осмысленное имя, которое коротко и ясно описыва­ ет ее назначение, например printReceiptHeader. В ее теле мы напи­ шем следующее: funct ion printReceiptHeader() { console.log("CASH RECEIPT"); console.log("------------------------------ 00 ); } Аналогично создадим еще две функции для вывода тела чека (body) printReceiptBody и для вьmода нижней части чека (footer) printReceiptFooter. Далее мы создадим еще одну функцию, которая будет последо­ вательно вызьmать все три функции, написанные нами до сих пор: function printReceipt( ) { printReceiptHeader(); printReceiptBody(); printReceiptFooter(); } Н аконец, мы вызов ем функцию printReceipt из глобальной об­ ласти видимости нашей программы: printReceipt(); Проверка в системе Judge Программа с четырьмя функциями, вызываемыми одна за дру­ гой, готова, и мы можем запустить и протестировать ее, а затем отправить в систему Judge Contests/Practice/lndex/943#0. для проверки : https://judge.softuni.bg/
Функции с параметрами 429 Функции с параметрами Очень часто на практике для решения задачи функции, которую мы используем для этого, требуется дополнительная информация, зависящая от ее задачи. Именно эту информацию представляют со­ бой параметры функции, от которых зависит ее поведение. Использование параметров в функциях Если нашей функции требуются входные данные, они передают­ ся в круглых скобках (), а последовательность фактических пара­ метров должна совпадать с последовательностью параметров, пе­ реданных при объявлении функции. Как мы уже отмечали выше, параметров может быть не только ноль, но и один или несколько. При их объявлении мы разделяем их запятой. Мы объявляем функцию printNumbers( ... ) и список параметров, необходимых ей для корректной работы, а затем пишем код, кото­ рый она будет выполнять: function printNumbers(start, end) { for (let i = start; i <= end; i += 1) { console.log(i); } } Затем мы вызываем функцию, передавая ей определенные зна­ чения: printNumbers(5, 10); При объявлении параметров необходимо следить за тем, что­ бы у каждого из них было имя. При вызове функции важно переда­ вать значения параметров в том порядке, в котором они объявле­ ны. В рассмотренном примере переменной значение первого переданного параметра ло 5. Переменной ного параметра - end start - будет присвоено в нашем случае чис­ будет присвоено значение второго передан­ в данном случае число Важно отметить, что в JavaScript 10. объявление функции с задан­ ным количеством параметров не обязывает нас вызывать функцию с тем же количеством параметров . Мы можем вызвать функцию, передав ей как большее, так и меньшее количество параметров, и это не приведет к ошибке.
Глава 430 1О. Функции Рассмотрим следующий пример: function printNumbers(start, end) { for (let i = start; i <= end; i += 1) { console . log(i); } } printNumbers(5, 10, 15, 20); В данном случае мы вызываем функцию редаем ей 4 параметра printNumbers ( ...) и пе­ 2. Лишние параметры 15 и 20 не попадут в функ­ вместо заявленных будут проигнорированы. То есть числа цию, потому что у нас нет объявленного параметра для их приема. Давайте рассмотрим еще один пример : function printNumbers (firstNumber, secondNumber) { console . log(firstNumber); console.log (secondNumber); // это выведет в консоль "undefined" } print Numbers(5); В этом случае мы вызьmаем функцию printNumbers( ...) и пере­ да ем один вместо заявленных двух параметров. Все параметры, для которых не передано значение, автоматически получат зна­ чение undefined. В нашем иметь значение undefined. случае переменная secondNumber будет Пример: знак целого числа Создайте функцию, которая вьmодит знак целого числа n. Пример ввода и вывода Ввод вывод 2 The number 2 is positive. -5 The number -5 is negative. 0 The number 0 is zero. Рекомендации и подсказки Сначала мы объявим функцию и дадим ей описательное имя, на­ пример printSign. У этой функции будет только один параметр :
Функции с параметрами 431 function printSign(num) { } Следующим шагом будет реализация логики, с помощью кото­ рой наша программа будет проверять, какой именно знак у числа. Из примеров видно, что есть три случая - число больше нуля, рав­ но нулю или меньше нуля, а это значит, что в теле функции мы сде­ лаем три проверки. Следующим шагом будет вызов созданной нами функции: function solve([n]) { function printSign(num) { // TODO } const num = parseint(n); printSign(num); } Проверка в системе Judge Пр оверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/943#1. Необязателънъ1е параметры Язык JavaScript поддерживает использование необязательных па­ раметров. Они позволяют не указывать параметры при вызове функ­ ции. Объявление таких параметров осуществляется путем указания значения по умолчанию в описании соответствующего параметра. Следующий пример иллюстрирует использование необязатель­ ных параметров: function printNumbers(start = 0, end = 10) { for (let i = start; i <= end; i += 1) { console.log(i); } } Показанная функция сколькими способами: printNumbers(); printNumbers(2); printNumbers(2, 3); printNumbers( ... ) может быть вызвана не-
Глава 432 В отсутствие переданного значения параметра 1О. она Функции примет то значение, которое мы объявили при объявлении функции. Пример: вывод треугольника Создайте функцию, которая въmодит на экран треугольник с n строками, как показано в примерах. Примеры ввода и вывода Ввод вывод Ввод 1 1 2 1 2 3 1 2 1 3 4 Вывод 1 11 1 1 1 1 1 ~ 2 2 3 2 3 4 2 3 2 Рекомендации и подсказки Выб ерите для функции осмысленное имя, описывающее ее на­ значение, например printline, и реализуйте ее: function printline(sta rt = 1, end) { let line = ""; for (let i = start; i <= end; i += 1) { line += i + '' ''; } console.log(line); } Из задач по рисованию в консоли мы помним, что хорошей прак­ тикой является разделение фигуры на несколько частей. Для удоб­ ства мы разделим треугольник на три части - верхнюю, среднюю линию и нижнюю. Следующим нашим шагом будет использование цикла для выво­ да верхней половины треугольника: for (let i = 1; i < n; i++) { printline( l , i ); }
Функции с параметрами 433 Затем мы выводим среднюю линию: printline(l, num); Наконец, мы выводим нижнюю половину треугольника, на этот раз уменьшая шаг цикла: for (let i = n-1; i > 0; i -- ) { printline(l, i); } Проверка в системе Judge Пр оверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/943#2. Пример: рисование заполненного квадрата Нарисуйте в консоли заполненньrй квадрат со стороной n, как по­ казано в примерах. Примеры ввода и вывода Ввод Вывод Ввод -------4 - \/\/\/ -\/\/\/- вывод Ввод Вывод -----3 -------- - \/\/ -\/\/- 2 --- ---- ------ Рекомендации и подсказки Мы создаем функцию, которая будет выводить первую и послед­ нюю строки, поскольку они одинаковы. Не забудем, что нужно дать ей имя и задать в качестве параметра длину стороны. Мы будем ис­ пользовать встроенный метод repeat( ... ): function printHeaderFooter(num) { console.log(«-».repeat( 2 * num)); } Следующим шагом будет создание функции, которая будет рисо­ вать средние ряды в консоли. Снова зададим описательное имя, на­ пример printMiddleRow:
Глава 434 1О. Функции function printMiddleRow(num) { let line = "-"; for (let i = 0; i < num - 1; i++ ) { line += "\\ /"; } line += "-"; console.log(line); } Наконец, мы вызовем созданные функции, чтобы нарисовать весь квадрат: func t ion solve( [n]) { const num = parse!nt(n); printHeaderFooter(num); // отрисовать остальную часть квадра т а } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/943#3. Возврат результата функции До сих пор мы рассматривали функции, которые вьmолняют действие, например, выводят в консоль текст, число или цифру. Помимо функций этого типа существуют функции, которые могут возвращать некоторый результат своего вьmолнения - результат умножения 7Jl3yx чисел. например, Именно эти функции мы и рас­ смотрим в следующих строках. Оператор return Чтобы мы смогли получить результат выполнения функции, нам на помощь приходит оператор return. Он должен использоваться в теле функции и указывает программе прекратить выполнение функции и вернуть значение вызывающей стор оне. Это значение определяется выражением, следующим за оператором return.
Возврат результата функции 43 5 В приведенном ниже примере мы имеем функцию, которая по­ лучает в качестве параметров имя и фамилию, объединяет их и воз­ вращает в качестве результата полное имя: function get FullName(firstName, lastName) { return firstName + '' '' + lastName; } Бывают случаи, когда return можно вызвать из нескольких мест функции, но только при наличии определенных условий. В примере ниже представлена функция, котор ая сравнивает два числа и возвращает результат -1, 0 или 1 соответственно, в зави­ симости от того, меньше, равен или больше первый аргумент, чем второй, переданный в функцию. Функция использует ключевое слово return в трех разных местах, чтобы вернуть три разных зна­ чения в соответствии с логикой сравнения чисел: function compareTo(numberl, number2) { if ( numberl > number2) { return 1; } else if (numberl number2) { return 0·, } else { return -1; } } Код после return недоступен Если оператор как i f , то после return не находится в условном оператор е, таком него в текущем блоке не должно быть других строк кода, поскольку в этом случае Visual Studio Code выдаст предупре­ ждение о том, что встретился код, к которому нельзя получить до ­ ступ: function getFullName(firstName, secondName, familyName) { return firstName + " " + secondName; [jshint] UnreachaЫe 'return ' after 'return'. (1'1027) ret rn firstName + " " + secondName +" "+ familyName; ). Оператор return также можно использовать без указания кон­ кретного возвращаемого значения. В этом случае код в функции бу-
Глава 43 6 1О. Функции дет просто завершен, а по умолчанию будет возвращено значение undefined. В программировании нельзя иметь два оператора return, распо­ ложенных друг за другом, потому что въmолнение первого не по­ зволит въшолнить второй. Иногда программисты шуrят фразой «напиши return; return; and walk away», чтобы объяснить, что логика программы нарушена. Использование возвращаемого функцией значения После того как функция выполнена и вернула значение, его мож­ но использовать несколькими способами. Первый - присвоить результат в качестве значения пере­ менной: let max = getMax(5 , 10) ; Второй - let t otal Третий - let age = использовать результат в выражении: = getPrice() * quantity * 1 . 20; пер едать результат функции другой функции: parseint (getMyAge()); Пример : вычисление площади треугольника Н апишите функцию, которая вычисляет площадь тр еугольника, заданную основанием и высотой, и возвращает ее значение. Пример ввода и вывода Ввод 3 4 Вывод 6 Рекомендации и подсказки Создаем функцию с подходящим именем: function getTriangl eArea(a, return (а * Ь) / 2; Ь) { } Следующим шагом будет вызов новой функции и запись возвра­ щаемого значения в соответствующую пер еменную:
Возврат результата функции 437 function solve ( [length, heigth]) { const а= parseF l oat(length); const Ь = parseFloat(heigth); const area = getTriangleArea(a, console . log(area); Ь); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/943#4. Пример: степень числа Напишите функцию, которая вычисляет и возвращает результат возведения числа в заданную степень. Примеры ввода и вывода Ввод вывод Ввод вывод 1 2 8 256 3 81 4 Рекомендации и подсказки Первым нашим шагом снова будет создание функции, кото­ рая будет принимать два параметра (число и степень) и возвра­ щать в качестве результата число, возведенное в соответствующую степень: function calculatePower(num, power) { let result = 0; / / TODO: Calculate result / / Use а loop or Math.pow() return result; } По сле того как мы вьmолним необходимые вычисления, нам останется только вызвать объявленную функцию. Проверка в системе Judge Проверьте свое решение: Index/943#5. https://judge.softuni.bg/Contests/Practice/
Глава 438 1О. Функции Функции, возвращающие несколько значений На практике встречаются случаи, когда функция должна вер­ нуть в качестве результата более одного элемента. В есть два способа добиться этого - JavaScript деструктуризация и возврат объекта. Деструктуризация Когда мы хотим, чтобы функция возвращала более одного значе­ ния, мы используем ключевое слово return, затем перечисляем все значения, которые мы хотим вернуть, заключая их в квадратные скобки-[, ]: funct ion getNames(firstName, secondName, familyName) { const name = firstName +" "+ familyName; const fullName = firstName +" "+ secondName +" " + familyName; return [name, fullName ] ; Затем, чтобы мы смогли получить возвращаемые значения, на помощь снова приходят квадратные скобки. Мы перечисляем пар аметры, чтобы получить эти значения, и присваивание будет выполняться в том порядке, в котором возвращаются значения: let [name, fullNa me] = getNames("John", "Silver", "Doe"); В приведенном выше примере переменная ние «John Doe», ным функцией name получит значе­ которое является первым значением, возвращен­ getNames, а fullName получит значение «John Silver Doe», которое является вторым возвращенным значением. Объекты Этот подход очень похож на пр едыдущий, с той лишь разницей, что мы не просто перечисляем значения, которые хотим вернуть, но и даем им имена. Объекты являются чр езвычайно важной и фундаментальной ча­ стью языка с JavaScript. Пока достаточно знать, что они объявляются помощью фигурных скобок { }, а междУ ними мы перечисляем имя значения (называемое ключом), затем символ с двумя точками :и само значение. Мы разделяем отдельные пары «имя-значение » симв олом,:
Варианты функций 439 return { name: firstName +" "+ familyName, fullName: firstName +" "+ secondName +" "+ familyNa me }; В этом примере мы возвращаем объект, содержащий два значе­ ния - name и fullName: function getNames (firstName, secondName, familyName) { return { name: firstName + '' '' + familyName, ful l Name: firstName +" "+ secondName +" "+ familyName }; } const personNames = getNames( "John", "Doe", "Silver"); personNames получит в се возвращенные зна­ чения. Поскольку name и fullName являются частью этих значений, Здесь переменная доступ к ним можно получить с помощью символа .: console.log(personNames . name); console.log(personNames.fullName); Варианты функций Во многих языках программирования одна и та же функция может быть объявлена в нескольких вариантах с одним и тем же именем и разными параметрами. Это известно под термином «пе­ регрузка методов ». К лучшему или худшему, но JavaScript не под­ держивает эту возможность. Когда вы объявляете две или более функций с одинаковым име­ нем, программа будет использовать последнюю из объявленных. Объявляя вторую функцию с тем же именем, вы фактически удаля­ ете старую функцию и записываете на ее место новую. Вложенные функции Рассмотрим следующий пример: function solve() { function sum(a, Ь) { return а+ Ь;
Глава 440 1О. Функции } const const а= Ь = 10; 20; console . log(sum(a, Ь)); } Что такое локальная функция? Мы видим, что в этом коде для нашей функции лена еще одна функция sol ve () объяв­ sum( ). Такая вложенная функция называет­ ся локальной. Локальные функции могут быть объявлены в любой другой функции. Зачем использовать локалънъ1е функции? Со временем и практикой мы обнаружим, что при написании кода нам часто нужны функции, которые мы используем только один раз, или же нужная нам функция становится слишком длин­ ной. Выше мы упоминали, что когда функция содержит слишком много строк кода, ее становится трудно поддерживать и читать. В та­ ких случаях на помощь приходят локальные функции - они дают возможность объявить другую функцию в функции, которая будет использоваться, например, только один раз. Это помогает нашему коду быть более упорядоченным и проще читаемым, что, в свою очередь, помогает быстрее исправить любую ошибку в коде и сни­ жает вероятность ошибок при внесении изменений в логику про­ граммы. Объявление локалънъIХ функций Давайте вернемся к рассмотренному выше примеру. function solve( ) { function sum(a, Ь) { return а+ Ь; } const const а= Ь = 10; 20; console.log(sum(a, } Ь));
Именование функций. Лучшие практики при работе с функциями В этом примере функция sum() 441 является локальной функцией, поскольку она вложена в функцию sum() являет­ ся локальной для solve(). Это означает, что функция sum() может быть использована только в функции solve(), поскольку она объ­ solve(), то есть явлена в ней. Локальные функции имеют доступ к переменным, которые объ­ явлены на том же или более высоком уровне, чем они. Это демон­ стрирует следующий пример: function solve() { const message = "I will Ье used in local function"; function printMessage( ) { console.log(message); } printMessage(); } Эта особенность вложенных функций делает их очень удобны­ ми помощниками при решении задач. Они экономят время и код, которые в противном случае мы бы потратили на п ередачу вло­ женньrм функциям параметров и переменных, которые использу­ ются в функциях, в которые они вложены. Именование функций. Лучшие практики при работе с функциями В этом разделе мы рассмотрим некоторые устоявшиеся практи­ ки работы с функциями, связанные с именованием, р асположени­ ем и структурой кода. Именование функций При именовании функций рекомендуется использовать осмыс­ ленные имена. Поскольку каждая функция отвечает за какую-то часть нашей задачи, при ее именовании мы должны учитьmать действие, которое она вьmолняет, то есть хорошей практикой явля­ ется то, что имя должно описьmать цель . Имя обязательно должно начинаться со строчной буквы и состо­ ять из глагола или пары: глагол + существительное. При формати-
Глава 442 1О. Функции ровании названия соблюдается нижний регистр, т. е. каждое слово, кроме первого, начинается с заглавной буквы. После имени функ­ ции всегда следуют круглые скобки ( и ). Каждая функция должна выполнять отдельную задачу, а имя функции должно описывать ее роль. Некоторые примеры правильного именования функций: • findSt udent • loadReport • sine Примеры неудачного именования функций: • methodl • doSomething • handleStuff • sampleMethod • dirtyHack • FindStudent • LoadReport Если мы не можем придумать подходящее имя, то, вер оятно, функция решает более одной задачи или не имеет четко опреде­ ленного назначения, и тогда нам нужно подумать, как разбить ее на несколько отдельных функций. Именование параметров функций При именовании пар аметров функций действуют почти те же правила, что и для самих функций. Разница лишь в том, что для имен параметров лучше использовать существительное или пару из прилагательного и существительного. Следует отме­ тить, что хорошей практикой является указание в имени параме­ тр а единицы измерения, которая используется при р аботе с ним. Некоторые примеры функций: • firstName • report • speedKmH правильного именования параметров
Именование функций. Лучшие практики при работе с функциями • userslist • fontSizeinPixels • font 443 Некоторые примеры неправильного именования пар аметров: • р • pl • р2 • populate • LastName • last name Хорошие практики при работе с функциями Повторим, что функция должна выполнять только одну кон­ кретную задачу. Если это невозможно, то нужно подумать о том, как разделить функцию на несколько отдельных. Как мы уже гово ­ рили, имя функции должно точно и ясно описывать ее назначение . Еще одна хорошая практика программирования - избегать функ­ ций длиннее экрана (примерно). Однако если код становится очень большим, рекомендуется разбить функцию на несколько более ко­ ротких, как в примере ниже: function printReceipt() { printHeader(); printBody( ) ; printFooter(); } Структура и форматирование кода При написании функций необходимо следить за соблюдени­ ем правильного форматирования кода (отступы внутри блоков кода). Пример правильно отформатированного кода JavaScript: function solve() { // // } код еще код ...
Глава 444 1О. Функции Пример неправильно отформатированного кода JavaScript: function solve() { // код //еще код .. . .. . } Если строка заголовка функции слишком длинная, рекоменду­ ется разбить ее на несколько строк, причем каждую строку после первой смещать на две табуляции вправо (для лучшей читабель­ ности): function solve(firstName, secondName, familyName) { // // код ... еще код ... } Еще одна хорошая практика при написании кода - оставлять пустую строку между функциями, после циклов и условных опе­ раторов. Также старайтесь избегать написания длинных строк и сложных выражений. Со временем вы поймете, что это улучшает читаемость кода и экономит время. Мы рекомендуем всегда использовать фигурные скобки для тела проверок и циклов. Скобки не только улучшают читае­ мость, но и снижают вероятность того, что будет допущена ошибка и наша программа поведет себя неправильно. Что мы узнали из этой главы? В этой главе мы познакомились с основными понятиями работы с функциями: • Мы узнали, что назначение функций - разделять большие программы с большим количеством строк кода на более мелкие и короткие задачи. • Мы узнали о структуре функций, о том, как их объявлять и как вызывать по имени. • Мы рассмотрели примеры функций с параметрами и узна­ ли, как использовать их в программе.
Упражнения • 445 Мы узнали, что такое возвращаемое значение функции, а также о том, какова роль оператора • return. Мы узнали, как лучше работать с функциями, как назъmатъ функции и их параметры, как форматировать код и многое другое. Упражнения Чтобы закрепить навыки работы с функциями, мы решим не­ сколько задач. В них требуется написать функцию с определен­ ной функциональностью, а затем вызвать ее, передав ей данные, как показано в примерах ввода и вывода. Задача: «Hello, имя! » Напишите функцию, которая принимает в качестве параметра имя и въmодит в консоль сообщение «Hello, {Имя} !». Пример ввода и вывода Ввод Вывод Peter Hello, Peter! Рекомендации и подсказки Определите функцию шите функцию printName(name) и реализуйте ее. Напи­ solve( ... ), которая получает на вход имя человека и вызывает функцию printName, передавая считанное имя. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/943#7. Задача: меньшее число Создайте функцию getMin(a, Ь ), которая возвращает меньшее из двух чисел. Напишите функцию solve( ... ), которая принимает на вход три числа и выводит наименьшее из них. Используйте уже созданную функцию getMin ( ... ).
Глава 446 1О. Функции Примеры ввода и вывода Ввод Вывод 1 3 1 Вывод -100 -101 -102 1 2 Ввод -102 Рекомендации и подсказки Определите функцию а затем вызовите ее из getMin(int а, int функции solve( ... ), Ь) и реализуйте ее, как показано ниже. Чтобы найти минимум трех чисел, сначала найдите минимум первых двух чисел, а затем минимум результата и третьего числа: function solve([numl, num2, numЗ]) { let min = getMin (getMin ( numl, num2), numЗ); } Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ IndeX/943#8. Задача:повторениестроки Н апишите функцию repeatString(str, count), которая прини­ мает в качестве параметров строковую переменную число n и возвращает строку, повторенную n str и целое раз. Результат выво­ дится в консоль. Примеры ввода и вывода Ввод str Вывод 1 strstr 1 2 Ввод roki 6 Вывод rokirokirokirokirokiroki Рекомендации и подсказки Завершите приведенную ниже функцию, добавив входную стро­ ку к ре зультату в цикле: func t ion repeatString(str, count) { let repeatedString = "";
Упражнения 447 for (let i = 0; i < count; i / / TODO += 1) { } ret urn repeatedString; } Проверка в системе Judge Пр оверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/943#9. Задача: N-й разряд Напишите функцию findNthDigi t ( number, index ), которая при­ N и выводит N-ую с 1). Затем выведите нимает в качестве параметров число и индекс цифру числа (считая справа налево, начиная результат в консоль. Примеры ввода и вывода Ввод Вывод 83746 2 Ввод 1 ' Вывод 93847837 6 4 1 Ввод 2435 4 8 1 Вывод 1 2 1 Рекомендации и подсказки Чтобы запустить алгоритм, мы будем использовать цикл while до тех пор , пока число не станет равным О. На каждой итерации цикла while мы будем проверять , совпада ет ли текущий индекс цифры с искомым индексом. Если совпадает, то в качестве резуль­ тата мы вернем цифру индекса (чис л о то мы удалим последнюю цифру числа % 10). Если не совпадает, (number = number / 10). Нам нужно отслеживать, какую цифру мы проверяем, по индексу (справа нал ево , начиная с 1). Когда мы найдем цифру, мы вернем индекс. Проверка в системе Judge Пр оверьте свое решение: Index/943#10. https://judge.softuni.bg/Contests/Practice/
Глава 448 1О. Функции Задача: перевод числа в систему счисления Напишите функцию integerToBase(number, toBase), которая принимает в качестве параметров целое число и основание систе­ мы счисления и возвращает входное число, преобразованное в ука­ занную систему счисления. Результат выводится в консоль. Вход­ ное число в сегда будет в десятичной системе счисления, а параметр основания новой системы счисления будет находиться в диапазоне ОТ 2 ДО 10. Примеры ввода и вывода Ввод Вывод 3 2 11 Ввод 4 4 Вывод Ввод Вывод 10 9 7 12 Рекомендации и подсказки Чтобы решить задачу, объявим строковую переменную, в кото­ рой будем хранить результат. Затем нам нужно выполнить следую­ щие вычисления, необходимые для преобразования числа : • • Вычисляем остаток числа, деленный на основание. Вставляем остаток числа в начало строки, представляющей результат. • • Делим число на основание. Повторяем алгоритм до тех пор, пока входное число не ста­ нет равным О. Заполните недостающую логику в приведенной ниже функции: function i ntegerToBase(number, toBase) { string result = "" ; while (number !== 0) { // implement the missing conversion l ogic } return result; } Проверка в системе Judge Проверьте свое решение: Index/943#11. https://judge.softuni.bg/Contests/Practice/
Упражнения 449 Задача: уведомления Напишите функцию solve( . .. ), которая в качестве первого метра принимает целое число n- пара­ количество сообщений и допол­ нительное количество параметров, которые являются самими ча­ стями сообщений. Для каждого сообщения может быть получено разное количе­ ство параметров. Первым параметром для каждого сообщения является message- Type, который может быть success, warning или error: • Если • Если messageType - warning, дет message. • Если success, то следующими раметрами будут operation и message messageType равен двумя па­ то следующим параметром бу­ messageType - error, следующие три параметра бу­ дут следующими: operation + message + errorCode (каждый из них является отдельным параметром). В консоль выводится каждое прочитанное сообщение, отформа­ тированное в соответствии с его messageType. Следуя строке заголовка каждого сообщения, выведите коли­ чество такое количество символов =, сколько символов в соот­ ветствующей строке заголовка , и поместите одну пустую строку после каждого сообщения (для более детального понимания см. примеры). Решите задачу, определив четыре функции: • showSuccessMessage( ... ), • showWarningMessage( ... ), • showErrorMessage( ... ) • processMessage( ... ), причем только последняя зывается из главной функции solve( . . . ): function function function function и функция вы- showSuccessMessage(operation, message) {} showWarningMessage(message ) {} showErrorMessage(operation, message, errorCode) {} processMessage(messageinfo) {}
Глава 450 1О. Функции Примеры ввода и вывода Ввод Вывод 4 error Error: Failed to execute credit card purchase. credit card ---------------------------------------------purchase Reason: Invalid customer address. Error code: Invalid customer 500 address · 500 warning Email not confirmed Warning: Email not confirmed. ----------------------------- success Successfully executed user registration. user ---------------------------------------registration ---------------------------------------User registered successfully . User registered successfully warning Customer has not Warning : Customer has not email assigned. ----------------------------------------email assigned ----------------------------------------1 Рекомендации и подсказки Определите и реализуйте четыре функции. Затем вызовите функцию processMessage( ... ) из основной функции function solve(messageinfo) { processMessage(messageinfo) ; } solve( ... ):
Упражнения 451 В функции processMessage( ... ) сначала вычтите количество со­ общений, затем обработайте их по одному в соответствии с их ти­ пом и вызовите соответствующую функцию вывода. Проверка в системе Judge Проверьте свое решение : https://judge.softuni.bg/Contests/Practice/ Index/943#12. Задача: преобразование чисел в слова Напишите функцию letterize(number), которая считывает це­ лое число и выводит его в виде английских слов в соответствии с приведенными ниже условиями: • Вьmедите сотни, десятки и единицы (а таюке минус, если необходимо) словами. • Если число больше ние • • -999, то должно быть выведено Если число отрицательное, то перед ним должен быть вы­ "minus ". Если число не состоит из трех цифр, его не следует выво­ дить на экран. Примеры ввода и вывода Ввод 3 999 -420 1020 Ввод 2 15 350 сообще­ "too small". веден • то должно быть выведено сообще­ "too la rge". Если число меньше ние 999, вывод nine-hundred and ninety nine minus four-hundred and twenty too large вывод fifteen three-hundred and fifty
Глава 452 Ввод 1О. Функции Вывод 1 ; three-hundred and eleven 11 f~ur-hundred and eighteen 418 five-hundred and nine 509 9945 ltoo small I_ Ввод Вывод 1 1 3 five-hundred one-hundred and twenty t hree nine 500 123 9 1 1 Рекомендации и подсказки Мы можем сначала вывести сотни в виде текста % 10, затем десятки - (число / 10) % 10 и, наконец, ло% до - (число / 100) единицы - (чис­ 10). Первый особый случай число точно округляется 100 этом случае мы вьmодим (например, - это когда 100, 200, 300 и т. д.) . В «one - hundred», «two - hundred», «three hundred» и т. д. Второй особый случай - когда число, обр азованное двумя по­ следними цифр ами входного числа, меньше 305, 609 10 (например, 101, и т. д.). В этом случа е мы вьmодим «one-hundred and one», «three-hundred and fi ve», «six-hundred and nine» и т. д. Третий особый случай - когда число, образованное двумя по­ следними цифрами входного числа, больше мер, 111, 814, 919 10 и меньше 20 (напри­ и т. д. ) . В этом случае мы выводим «one-hundred and eleven», «eight-hundred and fourteen »,« nine-hundred and nineteen» и т. д. Проверка в системе Judge Проверьте свое решение: https://judge.softuni.bg/Contests/Practice/ Index/943#13.
Упражнения 453 Задача: зашифровать строку Напишите функцию encrypt(char letter), которая шифрует букву следующим образом: • Берутся первая и последняя цифры АSСП-кода буквы и конка­ тенируются в результирующую сrроку. • В начале значения строки, представляющей результат, добавляется символ, удовлетворяющий следующему усло ­ вию: о • АSСП-код буквы + последняя цифра АSСП-кода буквы. Затем к концу строкового значения, представляющего ре­ зультат, добавляется символ, удовлетворяющий следующе­ му условию: о • АSСП-код буквы - первая цифра АSСП-кода буквы. Функция должна возвращать в качестве результата заши­ фрованную строку. Пример : • j -p16i о АSСП-код j о Соединяем первую и последнюю цифры о В начало стр оки, представляющей р езультат, вставьте - 106 - первая цифра - 1, последняя - 6. - 16. символ, который получается из суммы АSСП-кода следней цифры - 106 о + 6 ➔ 11 2 - + по­ р. В конце строки, представляющей собой результат, кон­ катенируйте символ, который получается в результате вычитания АSСП-кода 105 Используя -+ - первой цифры - 106 - 1 -+ i. описанный solve ( ...), которая выше метод, определите функцию получает строку символов, шифрует их и выво­ дит р езультат в одну строку. Мы предполага ем, что входные дан­ ные всегда будут достоверными. Функция solve( ... ) должна полу­ чить входные данные , предоставленные пользователем, число n, - целое за которым следует по одному символу для каждого по ­ следующего n элемента, зашифровать символы и добавить их в за-
Глава 454 1О. Функции шифрованную строку. В итоге в качестве результата должна быть выведена зашифрованная строка символов, как в следующем при­ мере. Пример: S, о, f, t, U, n, i ➔ V83Kpllnh12ezlбsZ85Mn10mn15h Примеры ввода и вывода Ввод Вывод Ввод 7 1 s 4 s 1 Вывод о f x15rt18kh97Xr12o t а V83Kpllnh12ezlбsZ85Mn10mn15h u р n i Рекомендации и подсказки Присвоим переменной resul t начальное значение 1111 , в которой будет храниться значение результата. Нам нужно выполнить цикл n раз, и на каждой итерации мы будем добавлять зашифрованный символ в переменную, в которой хранится значение результата. Чтобы найти первую и последнюю цифры АSСП-кода, мы вос­ пользуемся алгоритмом, который использовали для решения зада­ чи «Преобразование чисел в слова». Проверка в системе Judge Проверьте свое решение: Index/943#14. https://judge.softuni.bg/Contests/Practice/
Глава 11. Трюки и хаки В этой главе мы рассмотрим некоторые трюки, хаки и прие­ мы, которые облегчат работу с JavaScript в среде разработки Visual Studio Code. В частности, мы рассмотрим : • Как правильно оформлять код. • Как правильно именовать переменные. • Некоторые сочетания клавиш, или, как их еще называют «горячие клавиши» (keyboard shortcuts). • Некоторые фрагменты кода • Приемы отладки кода. (code snippets). Форматирование кода Правильное форматирование кода сделает его более читаемым и понятным, если кому-то еще понадобится с ним работать. Это важно, потому что на практике нам придется работать в команде с другими людьми, и очень важно написать код так, чтобы наши коллеги могли быстро в нем сориентироваться. Для правильного оформления кода существуют определенные правила, которые в совокупности называются соглашениями. Со­ глашения - это группа правил, общепринятых для программи­ стов, работающих с тем или иным языком, и широко используе­ мых. Эти соглашения помогают выработать нормы в конкретных языках - как лучше писать и что является лучшей практикой. Предполагается, что если программист следует им, то его код легко читается и понимается. JavaScript был создан Бренданом Эйхом в рамках разработ­ ки одного из первых браузеров, Netscape. Основные конструк-
Глава 456 11 . Трюки и хаки ции и синтаксис, лежащие в основе языка, намеренно похожи на Java, чтобы уменьшить усилия по их изучению. Более того, используются даже похожие соглашения для написания и фор­ матирования кода. Вы должны знать, что даже если вы не будете следовать навя­ занным соглашениям, код будет работать (при условии, что он на­ писан правильно) , но его будет нелегко понять. На базовом уровне это, конечно, не смертельно, но чем раньше вы привыкнете пи­ сать качественный код, тем лучш е. Правила, используемые при написании программ на JavaScipt, можно найти в о многих местах. Официальные правила или так на­ зываемые JavaScript-кoдoвыe соглашения, хорошо описаны в ста­ тье «Стиль кодирования» в документации Mozilla: https://developer. mozilla .org/en-US/docs/Мozilla/Developer_guide/Coding_Style. Важно отметить, что примеры, которые мы приводили до сих пор и будем приводить в дальнейшем в этой книге, в основном ру­ ководствуются именно ими. Для скобки форматирования кода {} рекомендуется, чтобы фигурные открывались в той же строке и закрывались чуть ниже утверждения, к которому они относятся, как в примере ниже: if (someCondition) { console.log(''Inside the if statement'' ); } Видно , что команда console. log( ... ) написана с отступом в че­ тыре пустых пробела (одна табуляция), что также рекомендуется в документации. Кроме того, если утверждение с фигурными скоб­ ками находится с отступом в одну табуляцию, то фигурные скоб­ ки {} должны находиться в начале утверждения, как в примере ниже: if (someCondition) { if (anotherCondition) { console . log(''Inside the if st atement''); } } Вот пример плохо отформатированного кода относительно со­ глашения написания кода JavaScript:
Форматирование кода 457 if(someCondition) { console.log("Inside the if statement");} Первое, что бросается в глаза , фигурные скобки { }. Пер­ вая (открывающая) скобка должна находиться рядом с услови­ i f , а вторая (закрывающая) скобка - под командой console. log( ... ), в отдельной пустой строке. Кроме того, команда внутри оператора i f должна занимать 4 пробела (одна табуляция). Про­ ем бел оставляется сразу после ключевого слова if и перед услови­ ем проверки. Это же правило относится к циклам ждениям с фигурными скобками for и любым другим утвер­ {}. Приведем еще несколько примеров. Правильно: for (let i = 0; i < 5; i++) { console.log(i); } Неправильно: for(let i=0;i<S;i++) { console.log(i); } Для вашего удобства в Visual Studio Code есть сочетания клавиш, о которых мы расскажем позже в этой главе, но пока нас интересу­ ют следующие комбинации для форматирования кода во всем до­ кументе: • Для • Для Мае • Для UЬuntu Windows [Shift + Alt + F] [Shift + Option + F] [Ctrl + Shift + I] Давайте воспользуемся ошибочным примером, который мы приводили выше: for(let i=0;i<S;i++) { console.log(i); }
Глава 458 Если мы нажмем [Shift + Alt + F], что 11 . Трюки и хаки является нашей комбина­ цией для форматирования всего документа, мы получим код, от­ форматированный в соответствии с общепринятыми соглашения­ ми JavaScript. Однако автоматическое форматирование не влияет на именование переменных, о котором мы должны позаботиться сами. Именование переменных Основное правило именования переменных в программиро­ вании гласит: «Имя переменной должно кратко объяснять ее на­ значение». Например, переменная, которая подсчитывает цифры в тексте, может называться lettersCount. Функции в программировании именуются аналогичным об­ разом: чтобы ответить на вопрос «какое действие выполняет эта функция». Соответственно, чаще всего в названии присутствует глагол+ существительное, например drawline(size). Переменные JavaScript принято всегда начинать со строчной бук­ вы. Их названия должны содержать строчные символы, а каждое по­ следующее слово в переменной следует начинать с заглавной бук­ вы (это соглашение об именовании также известно как camelCase convention). Следует быть осторожным с прописными и строчными буква­ ми, поскольку и Age - JavaScript чувствителен к регистру. Например, age это разные переменные. Имена переменных не могут совпадать с кточевыми словами JavaScript, например let - это недопустимое имя переменной. Слу­ - это просто слова, которые являются частью синтаксиса JavaScript, поэтому они заре­ жебные, или так называемые ключевые слова зервированы и не могут быть использованы в качестве имен пе­ ременных. Мы имеем возможность строить наши программы, ис­ пользуя эти слова. Примерами таких слов являются уже знакомые нам: for, while, do, i f, else, let и т. д. Полный список этих зарезервированных имен можно най­ https://developer.mozilla.org/en-US/docs/Web!JavaScript/ Reference/Lexical_grammar#Keywords. ти здесь:
Горячие клавиши в Visual Studio Code 459 _ в именах переменных разрешено, JavaScript и считается плохим стилем име­ Хотя использование символа оно не рекомендУется в нования. Вот несколько примеров удачных имен переменных: • firstName • age • startindex • lastNegativeNumberindex Вот несколько примеров неудачных имен переменных, хотя с точки зрения JavaScript имена корректны: (начинается с'_') • _firstName • last_name • AGE (пишется с большой буквы) • Start_Index (содержит'_ ') (начинается с заглавной буквы и содержит '_ ' ) • lastNegativeNumber_Index (содержит'_') Поначалу все эти правила могуг показаться бессмысленными и ненужными, но со временем и с опытом вы убедитесь в необхо­ димости норм для написания качественного кода, чтобы вам было проще и быстрее работать в команде. Вы поймете, что работать с ко ­ дом, написанным без соблюдения каких-либо правил качественно­ го кода, крайне угомител:ьно. Горячие клавиши в Visual Studio Code В предыдущем разделе мы упомянули некоторые сочетания кла­ виш, которые применяются для форматирования кода. Одно соче­ тание [Shift + Alt + F] предназначалось для форматирования всего кода в файле, а другие делали то же самое, но в другой операцион­ ной системе. Эти комбинации называются горячими клавишами, и сейчас мы расскажем о них подробнее.
Глава 460 Горячие клавиши - 11 . Трюки и хаки это комбинации, которые дают нам воз­ можность выполнять определенные действия проще и быстрее, и в каждой среде разработки программного обеспечения есть свои горячие клавиши, хотя большинство из них повторяются во всех средах. Сейчас мы рассмотрим некоторые сочетания клавиш в Studio Code. Visual Перечисленные сочетания клавиш точно работают и были протестированы в Windows. Идея состоит в том, чтобы по­ казать вам, что они существуют, ими легко пользоваться, и вы всег­ да сможете найти то, что вам нужно, для любой операционной си­ стемы, если вам это понадобится. Комбин а ция [CTRL + F] [CTRL + /] Дей с твие Эта комбинация открывает стему , которую мы поиска нашего можем поисковую си- использовать для кода . Комментирует часть кода и удаляет тарий из за комментированного Отменяет изменение. коммен- кода . 1 [CTRL + Z] [CTRL + У] Эта комбинация имеет эффект, ложный эффекту противопо- (так называемый [CTRL+Z] Redo). [Shift + Alt + F] Форматирует код в соответствии со стандартными соглашениями. [CTRL + Backspace] Удаляет [CTRL + Del] Удаляет слово справа от курсора. [CTRL + Сохраняет все файлы в проекте . К [CTRL + S] S] слово слева от курсора. Сохраняет текущий файл. Подробнее о горячих клавишах в Visual Studio Code вы можете уз­ нать здесь: https://code.visualstudio.corn/shortcuts/keyboard-shortcutswindows.pdf.
Фрагменты кода (code snippets) 461 о4 КеуЬоаrо Shortcuts - Visual Studio Code file ОеЬu9 Edit Se/ection Vie\v Go аа KeyЬoard Shortcuts о Tasks х Hclp 1D ••• х Sc ch keyЬind ngs а _d ~ st _ 1;:аТJо _ р_ Keyblnding Command AddCu Source When Pre$$ desred key comblnation and ENТER. ESCAPE to cancel. AddCu AddCu •, . ,d .·, A/t - • Add Se Change AII Occurrences Cut + f2 Change language Mode Cut - К м Default Или, если вы уже достаточно уверены в своих навыках работы с горячими клавишами, откройте Visual Studio Code, нажмите [CTRL + к + S] (обратите внимание, что это отличается от [CTRL + к s], где ct r 1 и к нажимаются одновременно, а s - потом), в результате чего в самой среде разработки откроется окно, содержащее полный спи~ сок всех возможных сочетаний клавиш в мире Visual Studio Code. Более того , вы даже сможете внести изменения в существующие со­ четания клавиш. Не медлите, применяйте полученные знания и используйте те сочетания клавиш, которые, по вашему мнению, помогут вам при написании программ! Фрагменты кода (code snippets) В Visual Studio Code есть так называемые фрагменты кода, в кото­ рых блок кода набирается по шаблону. Эта полезная опция не вклю­ чена по умолчанию. Вы должны включить ее самостоятельно из меню сле чего [File > Preferences -> Settings] (или просто [Ctrl + Comma]), по­ появится окно User Settings. Это ваши личные настройки, которые вы можете легко изменить. Просто добавьте следующую строку между открывающей и закрывающей фигурными скобками в правой части экрана: «editor.tabCompletion » : true
Глава 462 После этого, когда вы набираете 11 . Трюки «for» и нажимаете и хаки [ТаЬ] + [ТаЬ], в теле нашей программы автоматически генерируется код для пол­ ного цикла for. Это называется «разворачивание шаблона краткого кода». Шаблон «i f» + [ТаЬ] + [ТаЬ] работает аналогично. На рисунке ниже показано действие шаблона «for»: f o rl [J for [J foreach [J for i n j ava script t 1Select Language for Snippet 1 Handlebars HLSL HTML lni Java 1JavaScript 1 JavaScript React JSON JSON with Comments Less Создание собственного шаблона кода В этом разделе мы покажем, как создать свой собственный шаблон. Мы рассмотрим, как сделать фрагмент кода для объекта json. Для начала перейдем в раздел [File ➔ Preferences ➔ User Snippets], после чего откроется окно, в котором нужно выбрать язык программирования, для которого вы будете создавать ша­ блон, как показано на рисунке. Выберите с именем JavaScript из выпадающего меню , javascript. json. Расширение json - и откроется окно это специальный формат записи данных, который применяется при передаче и со­ хранении информации. Кроме того, формат json можно использо­ вать и в наших прогр аммах, о чем мы поговорим чуть позже. Файл выглядит следующим образом:
Фрагменты кода (code snippets) 463 { /* // Place your snippets for JavaScript here. Each snippet is defined under а snippet name and has а prefix, body and // description . The prefix is what is used to trigger the snippet and the body will Ье expanded and inserted . PossiЫe variaЫes are : // $1, $2 for tab stops, $0 for the final cursor posi tion, and $ {l : label}, ${2 : another} for placeholders . Placeholders with the // same ids are connected . // Example : "Print to console'' : { 11 prefix" : 11 log 1 ', "body" : [ "console . log('$1');", "$2" ], "description": ''Log output to console'' } */ } Пример, который мы видим, по умолчанию генерирует код для за­ rшси в консоль с использованием префикса log. Этот код - всего лишь пример, и на самом деле этот паттерн встроен в программу, но если бы его не бьшо, она выглядела бы так же, как в примере. В этом примере вы видите много незнакомых вещей, но это не страшно, мы разберемся с ними позже. Сейчас мы сосредоточим­ ся на части «Print to console «: и на коде между открывающими и закрывающими фигурными скобками{ }. То, что мы видим вну­ три фигурных скобок, представляет собой содержимое шаблона. Каждый шаблон должен содержать prefix, представляющий собой короткий текст, который при нажатии [ТаЬ] + [ТаЬ] будет создавать код шаблона в вашей программе. Второе, что должно быть у вашего шаблона, - body, самая сложная часть шаблона. Это собственно код, который будет сге­ нерирован, в этом коде мы можем использовать переменные, ко­ торые создаются с помощью $1, а на место единиц измерения мож­ но поместить другой текст. В примере используется переменная "console. log( '$1' ) ; ". Мы можем использовать остановки табуляции, которые просто помещают курсор в определенные места в коде, и с помощью табу-
Глава 464 11 . Трюки и хаки ляции можно перемещаться между ними. Они создаются автомати­ чески путем создания переменной. Мы также можем использовать заполнители, которые являются разновидностью ограничителей табуляции, но они также могут содержать некоторое значение, на­ пример: ${1:myVal}. Существуют и более сложные конфигурации, но эти отлично по­ дойдут для начала. Последняя часть шаблона - description, описание, которое слу­ жит для дополнительного объяснения того, что делает шаблон. Теперь давайте попробуем создать свой собственный шаблон. Удалим приведенный пример и введем следующий код : { "Generates JSON Object":{ "prefix": "json", "body": [ "let myJson = {", ''\t${1: myKey}: '${2:Value} ''', "}; ' ], ''description'': '' Generates JSON Object in our program'' } } Теперь, когда мы набираем j son + [ТаЬ] + [ТаЬ] в открьпом JavaScript-фaйлe в Visual Studio Code, появляется наш новый фрагмент: let myJson = { myKey: ' Va l ue ' }; ~ EXТENSIONS. МА!ЩТРI.АСЕ J snipp~t • 1 React Native Snippet о.: z. Q IОК *s ~•ct №t~. StyleSheet. ~actJS. Redux Sn;ppet , lml Wordpre-ss Snippet l ф ~,:: Wordpress Snippet fOf' Vtsual Studio Code *S 11:!Ш!1 JavaScript Snip~t Pack • s А snippet pack to ~ke you more productwe wo.. lml snip~t-cr•11tor "H'.t Q9C •.a.s c~,t~ snippets from s~lection lml * Atom Jav.aScript Snippet ~ • Q 14:к ~ Atom ЛlvaScript SnJppet fOf Visual Studio Code ~ lml
Техники отладки кода 465 Для тех, кто больше интересуется такой тематикой, многие круп­ ные фреймворки, такие как Angular, React и т. д., имеют свои соб­ ственные шаблоны, которые можно установить из окна Как следует из названия, фреймворк - Extensions. это концептуальная струк­ тура, которая помогает нам, предоставляя некоторые вещи изна­ чально, а таюке удерживает нас от серьезных ошибок, накладывая некоторые ограничения. Основная идея заключается в том, чтобы дать готовое решение в определенной области, которое может бьпь построено на основе всех компонент в этой области. Техники отладки кода Отладка играет важную роль в процессе разработки программ­ ного обеспечения, позволяя нам пошагово отслеживать выполне­ ние нашей программы. Используя эту технику, мы можем отсле­ живать значения локальных переменных по мере их изменения в ходе вьmолнения программы и отлаживать любые ошибки (баги). Процесс отладки включает в себя: • Выявление багов (ошибок). • • Нахождение кода, вызывающего проблемы. Исправление кода, вызывающего ошибки, чтобы програм­ ма работала правильно. • Тестирование, чтобы убедиться, что программа работает правильно после внесения поправок. Visual Studio Code предоставляет нам встроенный отладчик, с по­ мощью которого мы можем расставлять точки останова в нужных нам местах. При нахождении точки останова программа останав­ ливает выполнение и позволяет выполнить оставшиеся строки. От­ ладка позволяет нам вникнуть в детали программы и увидеть, где именно возникают ошибки и что их вызывает. Чтобы продемонстрировать работу отладчика, мы воспользуем­ ся следующей программой: for (let i = 0; i < 100; i++) { console.log(i); }
Глава 466 Поставим точку останова (Ьreakpoint) на методе 11 . Трюки и хаки console . log( . .. ). Для этого нам нужно подвести курсор к строке, которая выводится в консоль, и нажать рой в строке [F9]. Появится стопор (красная точка перед циф­ 3), на котором программа остановит выполнение: for (let i = 0 ; i < 100 ; i++) { console . log(i) 1 1 1е Чтобы [Debug] -+ 2 3 } запустить программу [Start Debugging] Debug Tasl<s в режиме или нажмите выберите [FS]: Help Start Debugging 1 отладки, FS Start Without Debugging Sh1ft+FS Stop Debugging Restart Debugging 1 Ct.l+FS Ctrl + Sh1ft+F 5 Запустив программу, мы видим, что она прекращает выполне­ ние на строке 4, где мы поставили точку останова (breakpoint). Код на текущей строке окрашен в желтый цвет, и мы можем выпол­ нять его пошагово. Для перехода к следующей строке мы использу­ ем клавишу [F10]. Обратите внимание, что код на текущей строке еще не выполнен. Он будет выполнен, когда мы перейдем к следу­ ющей строке: for (let i = 0 ; i 1 1• console . log(i ) 2 3 < 100 ; i++ ) { 1 ). В окне отладки, которое открывается по команде [View -+ Debug] или с помощью сочетания клавиш [Ctrl + Shift + о] , мы можем наблюдать з а изменениями в локальных переменных: DEBUG А VARIABLES А Block ► this : Object 1i : 0 ► Local ► Glob~I
Полезные приемы 467 Полезные приемы В этом разделе мы вкратце расскажем о некоторых трюках и при­ емах программиров ания на JavaScript, часть из которых уже упоми­ налась в этой книге и которые бу~ очень полезны, если вы сдаете экзамен по программированию для начинающих. Округление чисел Когда нам нужно округлить число, мы можем воспользоваться одним из следующих методов: • Math . round( ... ) - принимает один пар аметр - число, которое мы хотим округлить. Округление выполняется по основному правилу округления - если десятичная часть меньше 5, то округление пр оисходит в меньшую сторону, и наоборот, если больше 5- в большую: let number = 5.439; console.log(Math.round(number)); / / Вывод: "5 " let secondNumber = 5.539; console.log(Math.round(secondNumber)); / / Вывод: "6 " • Math . floor( .. .) - в том случае, если мы хотим, чтобы окру­ гление всегда происходило до меньшего целого числа. На­ пример, если у нас есть число метод, то получим число 5.99 и мы используем данный 5: let numberToFloor = 5.99; console. l og(Math.floor(numberToFloor)); / / Вывод: 5 • Math . cei l ( ...) - в случае, если мы хотим, чтобы окру­ гление всегда происходило до следующего целого числа. 5.13 Math. ceil(S .13), то получим число 6: Например, если у нас есть число let numberToCeil = 5.13; console. l og(Math.floor(numberToCeil)); // Вывод: 6 и мы используем
Глава 468 • Math.trunc( ...) - 11 . Трюки и хаки в случае, если мы хотим удалить дРОб­ 2.63 ную часть. Например, если у нас есть число пользуем и мы ис­ Math. trunc(2.63), то получим 2: let numberToTrunc = 2.63; console . log(Math.floor(numberToTrunc)); / / Вывод: 2 JS используйте === вместо == и !== вместо != В JavaScript операторы == и ! = автоматически преобразуют срав­ ниваемое значение или переменную, в то время как операторы === и ! == такого преобр азования не делают, и если два значения не име­ ют одинакового типа, результат будет ложным (false). Они(== и ! =) В выполняют сравнение значения и типа, что более точно и даже бы­ стрее. Давайте рассмотрим следующий пример, чтобы прояснить, что ПОдРазумевается под типом данных: [10] --- 10 [10] -- 10 "10 " -- 10 "10" --- 10 [] -- 0 [] === 0 -- false 11 11 11 11 === false // // // // // // // // false true true false true false true but true -- .. .. is fa l se false а Мы видим, что число 10 может быть записано в наших програм­ мах по-разному. Написанное таким образом, [ 10] представляет со­ бой массив из одного числа. Кор оче говоря, массивы - это несколь­ ко значений, хранящихся в одной переменной. Например : let array = [10, 20, 30, 40]; // переменная типа мас с и в ПодРобнее о массивах мы узнаем позже, а пока давайте просто рассмотрим, равен ли массив ( 10] числу 10. Дадим вам подсказку ­ это не нормально. Поэтому, если мы не хотим неприятных ошибок (багов) в наших программах, лучше всего использовать операторы === и ! ==. С дРуrими операторами сравнения и здесь действует та же логика. ситуация аналогичная,
Полезные приемы 469 Как написать условный оператор? Условный оператор • • • • if Ключевое слово состоит из следующих элементов: if Булево выражение (условие) Тело условного оператора Необязательно: условие (условие) // } else // if else { последовательность операторов (условие) { последовательность операторов } Для удобства набора мы можем использовать фрагмент кода ДЛЯ i f: i f + [ТаЬ] + [ТаЬ]. Как написать цикл for? Для цикла • for нам нужно несколько элементов: Блок инициализации, в котором объявляется переменная- счетчик (let i) и устанавливается ее начальное значение. • • Условие итерации (i • Тело цикла. <= 10). Обновление счетчика (i ++). for (let i = 0; i <= 10; i++;) { / / тело Для удобства написания мы можем использовать шаблон (фрагмент кода) for цикл: for + [ТаЬ] + [ТаЬ]. Использование так называемых положительных (Truthy) и отрицательных (Falsy) значений Все значения Truthy, используемые в условном операторе i f, да­ дут положительный результат, а значит, наша программа продол­ жит выполнение в теле условного оператора (для целей приведен­ ного здесь примера тело условного оператора отформатировано неверно). Для некоторых из них положительный результат кажется логич­ ным, а для других - не очень.
Глава 470 //Truthy if (true ) {} if ({}) {} if ( []) {} if (42) {} if ("foo") {} if (new Date()) {} if (-42) {} if (3 .14) {} / if (-3 .14) {} if (Infinity) {} if (-Infinity) {} 11 . Трюки и хаки //true //true //true //true //true //true //true / true //true //true //true И наоборот, все значения Falsy дадут отрицательный результат, и программа не войдет в тело условного оператора: //Falsy if (false) {} if (null) {} if (undefi ned) {} if ( 0 ) { } if ( NaN) {} if ( ") {} if ("") {} //false //fa lse //fa lse //false //false //false //fa lse Сейчас нет необходимости знать эти значения наизусть, просто запомните, что существуют так называемые истинные и ложные значения. Со временем вы привыкнете к тому, как правильно их использовать и как они помогают нам сокращать код. Что мы узнали из этой главы? В этой главе мы узнали о том, как правильно форматировать и называть элементы кода, о некоторых сочетаниях клавиш для ра­ боты в Visual Studio Code, способы отладки кода. о фрагментах кода, а таюке рассмотрели
Заключение Если вы прочитали всю книгу, решили все задачи в упражнени­ ях и пришли к этому заключению, то вас стоит поздравить! Вы уже сделали первый шаг в освоении профессии программиста, но вам предстоит пройти еще долгий путь, прежде чем вы станете дей­ ствительно хорошим специалистом и сделаете написание про­ грамм своей профессией. Запомните четыре основных навыка, которыми должен обла­ дать каждый программист, чтобы стать успешным: • Навык № 1- написание программного кода программиста) - (20 % навыков в основном рассматривается в этой кни­ ге, но вы таюке должны изучить основные структуры дан­ ных, классы, объекты, функции, строки и другие элементы написания кода. • Навык № 2- алгоритмическое мышление программиста) - (30 % навыков частично освещен в этой книге и разви­ вается в основном за счет решения большого количества алгоритмических задач. • Навык № 3- фундаментальные знания о профессии навыков программиста) - (25 % приобретается в течение не­ скольких лет путем сочетания учебы и практики (чтение книг, просмотр видеоуроков, прохождение курсов и особен­ но написание разнообразных проектов в различных техно­ логических областях). • 4 - языки программирования и программные технологии (25 % навыков программиста) осваивается Навык № в течение длительного периода времени, с большим коли­ чеством практики, основательным чтением и написанием проектов. Эти знания и навыки быстро устаревают и нужда­ ются в постоянном обновлении. Хорошие программисты осваивают новые технологии каждый день.
Заключение 472 Эта книга - лишь первый шаг! Эта книга по основам программирования - лишь первый шаг в развитии навыков программиста. Если вы справились со всеми задачами, значит, вы получили ценные знания о принципах про­ граммирования на JavaScript на базовом уровне. Вам еще пред­ стоит углубленно изучить программирование и развить алгорит­ мическое мышление, а затем добавить технологические знания Node.js (Node.js, npm, Express.js и другие), фронтенд-веб-технологиях (HTML, CSS, Angular, React, AJAX, НТМLS) о JavaScript и экосистеме и ряде других концепций, технологий и инструментов разработки программного обеспечения. Если вы не смогли решить все или большинство задач, вер­ нитесь к ним и решите их! Помните: для того чтобы стать про­ граммистом, нужно много работать и прилагать значительные усилия. Эта профессия не для ленивых. Не занимаясь програм­ мированием серьезно на протяжении многих лет, вы не сможете этому научиться! Как мы уже объясняли, первый и самый основной навык про­ граммиста - научиться писать код с легкостью и удовольствием. В этом и заключается задача данной книги: научить вас писать код. В дополнение к книге мы рекомендуем вам записаться на практи­ ческий курс «Основы программирования» в SoftUni, который пред­ лагается бесплатно в очном или онлайн-формате. Куда двигаться дальше? С помощью этой книги вы заложили прочный фундамент, кото­ рый позволит вам продолжать развиваться как программисту. Если вы задаетесь вопросом, как продолжить свое развитие, рассмотри­ те следующие несколько вариантов: • Получить профессию инженера-программиста при по­ мощи SoftUni и сделать программирование своей про­ фессией. • Продолжить развиваться как программист своим собствен­ ным путем, например, с помощью самообучения или он­ лайн-учебников.
473 Куда двигаться дальше? • Оставаться на уровне кодера, не занимаясь серьезным программированием. Профессия «инженер-программист» в университете SoftUni Первая, и поэтому рекомендуемая, возможность освоить профес­ сию «инженер-программист» - это начать обучение по комплекс­ ной программе подготовки инженеров-программистов в универ­ ситете SoftUni: https:1/softuni.bg/curriculum. Учебная программа SoftUni была тщательно разработана доктором Светлинам Нако ­ вым и его командой, чтобы последовательно и с постепенным ус­ ложнением дать вам все навыки, нео бходимые для того, чтобы начать карьеру разработчика программного обеспечения в IТ-ком­ пании. Продолжительность обучения в Обучение в SoftUni длится 2-3 SoftUni года (в зависимости от специаль­ ности и выбранных специализаций), и за это время вполне реально выйти на хороший начальный уровень (junior developer), но толь­ ко при условии, что вы серьезно занимаетесь и пишете код каж­ дь1й день. При хорошей успеваемости типичный студент начинает работать уже в середине обучения (примерно через 1,5 года). Бла­ SoftUni предла­ SoftUni, имеющим годаря развитой партнерской сети Центр карьеры гает работу по специальности всем студентам отличные или хорошие оценки. Поступление на работу по специ­ альности при наличии высоких оценок в SoftUni, желания рабо­ тать и разумных ожиданий по отношению к работодателю практи­ чески гарантировано. Программист становится программистом как минимум после года упорного написания кода Имейте в виду, что для того, чтобы стать программистом, нуж­ но приложить много усилий, написать десятки тысяч строк кода и решить сотни, а то и тысячи практических задач, и на это ухо ­ дят годы! Если кто-то предлагает вам « более легкую программу» и обещает, что вы станете программистом и начнете работать
Заключение 474 по специальности через 3-4 месяца, то вас либо обманут, либо да­ дут настолько низкий уровень, что компании не возьмут вас даже на стажировку. Конечно, есть исключения, например, если вы не начинаете с нуля, или у вас отлично развито инженерное мыш­ ление, или вы претендуете на очень низкую должность (напри­ мер, техническая поццержка), но в целом программистом меньше чем за год упорного обучения и написания кода не станешь! Вступительный экзамен в Для поступления в SoftUni SoftUni необходимо сдать вступительный эк­ замен по «Основам программирования» , основанный на матери­ але данной книги. Если вы легко решаете приведенные в книге упражнения, значит, вы готовы к экзамену. Также обратите вни­ мание на несколько глав, посвященных подготовке к практиче­ скому экзамену по программированию. Они дадут вам представ­ ление о сложности экзамена и типах задач, которые необходимо научиться решать. Если задачи из книги и примеры экзаменов кажутся вам слож­ ными, значит, вам необходима дополнительная подготовка. За­ пишитесь на бесплатный курс « Основы программирования» или внимательно прочтите книгу с самого начала, не пропуская задач из каждой учебной темы! Вы должны научиться решать их с легкостью , не помогая себе методическими указаниями и при­ мерами решений. Учебная программа для инженеров-программистов После экзамена вас ждет серьезная учебная программа по под­ готовке инженеров-программистов в университете SoftUni. Она представляет собой серию модулей из нескольких курсов по про­ граммированию и программным технологиям, полностью ори­ ентированных на изучение основ разработки программного обеспечения и приобретение практических навыков работы про­ граммиста с современными программными технологиями. Сту­ дентам предоставляется выбор из нескольких профессий и специ­ ализаций с акцентом на С#, и технологиях. Java, JavaScript, РНР и других языках
Куда двигаться дальше? 475 Каждая специальность изучается в нескольких модулях продол­ жительностью четыре месяца, каждый модуль содержит са. Занятия делятся на теоретическую подготовку ческие упражнения, проекты и мероприятия (30 %) (70 %), 2- 3 кур­ и практи­ каждый курс заканчивается практическим экзаменом или практическим курсо­ вым проектом. Сколько часов в день занимает обучение ? Обучение инженера-программиста в SoftUni - ное занятие, и ему необходимо уделять не менее очень серьез­ 4-5 часов еже­ дневно, а вообще рекомендуется уделять ему все свое время. Совмещать работу с учебой не всегда удается, но если вы за­ нимаетесь чем-то легким и имеете много свободного времени, у вас может получиться. SoftUni - хороший вариант для стар­ шеклассников, студентов вузов и тех, кто работает на другой ра­ боте, но лучше все свое время посвятить учебе и освоению про­ фессии. Этого не сделаешь , уделяя пр ограммированию 2-4 часа в неделю! Формы обучения в SoftUni - очная и онлайн. При обеих формах обучения для того, чтобы освоить программу по учебному плану (который требуют софтверные компании для начала работы), необ­ ходимо много учиться. Нужно только найти на это время! Причина № 1, по которой о бучающимся тяжело дается путь к профессии, - недостаточное количество времени на обучение: как минимум нужно уделять ему 20-30 часов в неделю. SoftUni для тех, кто работает и учится Всем, кто получил отличный результат на вступительном экза­ мене в SoftUni, действительно увлечен программированием и меч­ тает сделать его своей профессией, мы рекомендуем освободиться от других обязательств и посвятить все свое время освоению про­ фессии «инженер-программист». • Для работающих людей это означает увольнение с рабо­ ты (и получение кредита или сокращение расходов, что­ бы провести с меньшим доходом период в 1-2 года, они не начнут работать по новой специальности). пока
Заключение 476 • Для тех, кто учится в традиционном университете, это озна­ чает значительное смещение акцента в сторону програм­ мирования и практических курсов в SoftUni, что заставит сократить время, уделяемое обучению в традиционном университете. • Для безработных это отличный шанс направить все свое время, силы и энергию на приобретение новой, перспек­ тивной, хорошо оплачиваемой и востребованной профес­ сии, которая обеспечит им хорошее качество жизни и дол­ госрочное процветание. • Для учеников средних и старших классов это выбор того, что важнее для их развития: ского программирования в или изучение практиче­ SoftUni, которое даст им про­ фессию и работу, или полное внимание к традиционной системе образования, или разумное совмещение обоих начинаний. Всем тем, кто не может получить отличный результат на всту­ пительном экзамене в SoftUni, рекомендуется сосредоточиться на более nцательном изучении, на понимании и особенно на отра­ ботке материала, изложенного в этой книге. Если вы не справитесь с задачами из этой книги, то не сможете в будущем справиться с за­ дачами при изучении программирования и разработки программ­ ного обеспечения. Не пропускайте занятия по основам программирования! Ни в коем случае не принимайте смелых решений и не бросайте работу или традиционный университет, строя грандиозные планы на будущую профессию инженера-программиста, если у вас нет от­ личной оценки на вступительном экзамене в SoftUni! Он определя­ ет, подходит ли вам программирование, насколько оно вам нравит­ ся и есть ли у вас мотивация изучать его всерьез и заниматься этим долгие годы каждый день с радостью и удовольствием. Изучение программной инженерии самостоятельно Другой вариант развития событий после прочтения этой кни­ ги - продолжить изучение программирования вне SoftUni. Вы можете записаться на видеокурсы или пройти их, чтобы более глубоко изучить программирование на JavaScript или других язы-
Онлайн-сообщества для начинающих программистов 477 ках и платформах разработки. Можно читать книги по програм­ мированию и пр ограммным технологиям, изучать онлайновые учебники и другие онлайн-ресурсы - в Интернете бесконечное множество бесплатного материала. Однако помните, что самое главное на пути к становлению программиста - это практиче­ ские проекты! Программистом нельзя стать, не написав много-много кода. По­ тратьте достаточно времени. Программистом нельзя стать за месяц или два. В Интернете вы найдете большое количество бесплатных ре­ сурсов: книг, учебников, видеоуроков, онлайновых и очных курсов по программированию и разработке программного обеспечения. Однако, чтобы получить работу начального уровня, придется по­ тратить не менее года или двух. Когда вы продвинетесь вперед, наЙДите возможность либо прой­ ти стажировку в какой-либо компании (что будет практически не­ возможно без хотя бы годового опыта написания кода), либо при­ думать свой собственный практический проект, над которым вы будете работать несколько месяцев, а то и год, чтобы учиться мето­ дом проб и ошибок. Не забьmайте, что существует множество способов стать програм­ мистом, но все они имеют нечто общее: интенсивное написание кода и годы практики! Онлайн-сообщества для начинающих программистов Независимо от того, какой путь вы выберете, если вы соби­ раетесь но серьезно посещать заниматься программированием, специализированные желатель­ интернет-форумы, группы новостей и сообщества, где можно получить помощь от коллег и последнюю информацию о новинках в области программного обе­ спечения. Если вы собираетесь серьезно изучать программирование, окру­ жите себя людьми, которые им серьезно занимаются. Вступайте в сообщества разработчиков, посещайте конференции по програм­ мированию, ходите на мероприятия для программистов, найди-
Заключение 478 те друзей, с которыми вы сможете говорить о программировании и обсуждать проблемы и ошибки, наЙДИте окружение, которое смо­ жет вам помочь. В небольших населенных пунктах у вас есть Ин­ тернет и доступ ко всему онлайн-сообществу. Ниже приведены некоторые рекомендуемые ресурсы, которые буfJУТ полезны для вашего развития как программиста: • https://softuni.bg - официальный сайт SoftUni. Здесь вы най­ дете бесплатные (и не только) курсы, семинары, видеоуро­ ки и тренинги по программированию, программным тех­ нологиям и цифровым компетенциям. • https://softu.ni.bg/forum - официальный форум университе­ та SoftUni. Дискуссионный форум SoftUni чрезвычайно по­ зитивен и полон коллег, готовых помочь . Если вы зададите содержательный вопрос, связанный с программированием и технологиями, изучаемыми в SoftUni, то почти наверняка получите содержательный ответ в течение нескольких ми­ нут. Попробуйте, вы ничего не теряете. • http://www.introprogramming.info - официальный книг «Введение в программирование» на С# и сайт Java доктора Светлина Накова и команды. В этих книгах подробно рас­ сматриваются основы программирования, базовые струк­ туры данных и алгоритмы, ООП и другие базовые навыки, и они являются отличным продолжением для чтения после этой книги. Однако помимо чтения вам необходимо интен­ сивно писать код, не забывайте об этом! • http://stackoverflow.com - Stack Overflow - один из круп­ нейших в мире дискуссионных форумов для программи­ стов, где можно получить помощь по всем возможным вопросам программирования. Если вы свободно владеете английским языком, найдите Stack Overflow и задайте там свои вопросы. • https://www.meetup.com/find/tech - ищите технологические встречи в своем городе и участвуйте в тех сообществах, ко­ торые вам нравятся. Большинство технологических встреч бесплатны, и новичкам на них рады.
Всем удачи! • 479 Если вас интересуют мероприятия в области IT, техноло­ гические конференции, обучение и стажировки, обратите внимание на такие крупные сайты, посвященные IТ-собы­ тиям, как http://iteventz.bg и http://dev.bg. Всем удачи! От лица в сего авторского коллектива мы желаем вам дальней­ ших успехов в профессии и в жизни! Мы будем очень рады, если по­ могли вам увлечься программированием и вдохновили смело идти к профессии «инженер-программист», которая принесет вам хоро­ шую работу, где вы будете трудиться с удовольствием, обеспечит качественную жизнь и достаток, а также потрясающие перспекти­ вы для развития и возможности создавать впечатляющие проекты с вдохновением и увлеченностью.
Справочное издание Анык.тамалык, басылым Серия «Полный курс для начинающих программистов» Светлин Наков JavaScript ОСНОВЫ ПРОГРАММИРОВАНИЯ Ответственный редактор: Л. А. Адаменко Менеджер проекта: А. А. Дюдина Оформление обложки: С. А. Арутюнян Подписано в печать 13.02.2025. Формат 70х100'/ 1 6 . Бумага офсетная . Печать офсетная. Гарнитура Noto Serif SemiCondenced. Усл. печ. л. 39. Тираж экз. Заказ № Общероссийский классификатор продУкции ОК-034-201 4 (КПЕС 58.11.1 - книги, брошюры печатные. Изготовлено в 2008); 2025 г. Произведено в Российской Федерации. Из готовитель: ООО «Издательство АСТ». 129085, Российская Федерация, строение 1, г. Москва, Звёздный бульвар, дом комната 705, пом. 21, 1, этаж 7. Адрес места осуществления деятельности по изготовлению продукции : 123112, Российская Федерация, г. Москва, Пресненская набережная, д. 6, стр. 14, 15 этаж. Наш электронный адрес: ask@ast.ru Наш сайт: www.ast.ru Интернет-магазин: www.book24.ru Деловой ком плекс «Империя», ендiруш i : «Издательство АСТ» ЖШК: 129085, Ресей Федерациясы, Мэскеу, Звёздный бульвары, 21-уй, 1-к;~рылыс, 705-белме, 1уй-жай, 7-к,абат. енiм ендiру к,ызметiн жузеге асыру мекенжайы : 123112, Ресей Федерациясы, Мэскеу, Пресненская жаr., 6-уй, 2-к,vр., 14, 15-к,абат. www.ast.ru E-mail: ask@ast.ru Интернет-ма газин: www.book24.kz Интернет-дУкен: www.book24.kz «Империя » iскерлiк кешенi, Бiздi~; электрондык; мекенжайымыз: Импортер в Республику Казахстан и Представитель по приему претензий в Республике Казахстан - ТОО РДЦАлматы, г. Алматы. t<;азак;стан Республикасына импорпаушы жэне к;азак;стан Республикасы нда наразылык,тарды к,абылдау бойынша екiл - «РДЦ-Алматы» ЖШС, 1. 8(727) 2 51 59 90,91, факс: 8 (727) 251 59 92 iшкi 107; E-mail: RDC-Almaty@eksmo.kz, www.book24.kz Тауар бeлric i : «АСТ». ендiрiлrен жылы: 2025. Алматы к,., Домбровский кеш., З«а», Б литерi офис Тел. : 6н iмнi~; жарамдылык; мерзi мi шектелмеген. Ресей Федерациясында ендiрiлген. 2,
Перед вами нечто гораздо большее, чем просто пособие по про­ граммированию на высокоуровневом мультипарадигменном языке JavaScript с использованием такого продвинутого редактора кода, как Visual Studio Code. Это тщательно продуманный, систематизиро­ ванный и структурированный сборник задач для начинающих про­ граммистов, кажда я и з которых сопровождается готовым решением на языке JavaScript. Благодаря тому, что данное издание - далеко не первое в серии проектов по обучению основам программирова­ ния , претворенных в жизнь доктор ом Светлинам Наковым - ши­ роко известным создателем учебного контента курса «Осн овы про­ граммирования » в университете SoftUni, - книга вобрала в себя опыт авторов предыдущих учебников, адаптированных к другим языкам программирования, и поэтому является своеобразной квинтэссенцией их плодотворной работы. И здан ие предназначено в первую очередь для новичков в сфере информационных техноло­ гий, которые стремятся постигнуть необходимый набор алгоритмов для создания программ на JavaScript, изучив основные конструкции этого языка для самостоятельного написания программного кода . Каждая рассматриваемая тема сопровождается простыми и понят­ ными примерами, а также подробно разобранными задачами , реше ­ ния которых можно тут же проверить в режиме реального времени с помощью интерактивной судейской системы. С++ основы ПРОГРАММИРОВАНИЯ ~ книги для любого нас т роен и я www.ast.ru здесь I www.book24.ru CJ vk. com/izdatelstvoast О ИЗдАТЕЛЬСКАЯ ГРУППА АСТ ok.ru/izdatelstvoast ISBN 978-5-17-162193-3