<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Кудрявый микрофон</title><generator>teletype.in</generator><description><![CDATA[Меня зовут Валерий Линьков.
Я эксперт в сфере IT-образования. Больше 8 лет учу студентов по всему миру.]]></description><image><url>https://img1.teletype.in/files/4c/16/4c16927d-466f-47ec-892e-33bcbe8888c7.png</url><title>Кудрявый микрофон</title><link>https://teletype.in/@valerylinkov</link></image><link>https://teletype.in/@valerylinkov?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/valerylinkov?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/valerylinkov?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Sat, 04 Apr 2026 12:00:41 GMT</pubDate><lastBuildDate>Sat, 04 Apr 2026 12:00:41 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/GULm4mVGJTF</guid><link>https://teletype.in/@valerylinkov/GULm4mVGJTF?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/GULm4mVGJTF?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Как получить продукты JetBrains бесплатно</title><pubDate>Wed, 30 Oct 2024 17:46:39 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/2d/50/2d5048c4-032d-4996-bc11-b14cc3a79ba2.png"></media:content><category>Гайды 📖</category><description><![CDATA[<img src="https://img1.teletype.in/files/01/40/0140f050-0953-4aa0-a613-a4e56b5162af.png"></img>Вам нужно перейти на сайт студенческих аккаунтов GitHub https://education.github.com/.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#o2tf">Шаг 1. Перейти на сайт.</a></li>
      <li class="m_level_1"><a href="#9Qrb">Шаг 2. Прислать фото студенческого билета.</a></li>
      <li class="m_level_1"><a href="#kMUk">Шаг 3. На сайт JetBrains</a></li>
    </ul>
  </nav>
  <h2 id="o2tf">Шаг 1. Перейти на сайт.</h2>
  <p id="tJ7s">Вам нужно перейти на сайт студенческих аккаунтов GitHub <a href="https://education.github.com/" target="_blank">https://education.github.com/</a>.</p>
  <figure id="o3cy" class="m_original">
    <img src="https://img1.teletype.in/files/01/40/0140f050-0953-4aa0-a613-a4e56b5162af.png" width="929" />
  </figure>
  <p id="EpaD">Регистрируемся там (если у вас нет аккаунта GitHub, то сразу и на гите). </p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Be2G">Главное, чтобы в профиле на гитхабе было написано такое же имя</p>
  </section>
  <h1 id="9Qrb">Шаг 2. Прислать фото студенческого билета.</h1>
  <p id="sbDn">Фото должно быть аналогично тому, что ниже</p>
  <figure id="R7O9" class="m_original">
    <img src="https://img2.teletype.in/files/df/b8/dfb8fd52-b061-4c30-b762-33a64e94c900.png" width="916" />
  </figure>
  <h1 id="kMUk">Шаг 3. На сайт JetBrains</h1>
  <p id="umbU">Перейдите на сайт <a href="https://www.jetbrains.com/" target="_blank">https://www.jetbrains.com/</a></p>
  <figure id="ZK5n" class="m_original">
    <img src="https://img1.teletype.in/files/0c/0f/0c0f9649-cff8-4589-81ba-25d9eff15699.png" width="928" />
  </figure>
  <p id="yVWJ">Далее</p>
  <figure id="3Q8g" class="m_original">
    <img src="https://img1.teletype.in/files/89/62/896251a3-2184-48be-90e0-220a44e1ff13.png" width="928" />
  </figure>
  <p id="nrse">Заполняем анкету через гитхаб:</p>
  <figure id="LqH5" class="m_original">
    <img src="https://img2.teletype.in/files/1f/3f/1f3f464a-7cb2-4b69-86e4-ccee787af469.png" width="931" />
  </figure>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="DPXw">В поле где почта указываем любую без приписки .ru</p>
  </section>
  <p id="hip7"><strong><u>Шаг 4. Радуемся </u></strong></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/LH9pm4VG4hg</guid><link>https://teletype.in/@valerylinkov/LH9pm4VG4hg?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/LH9pm4VG4hg?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Создаём крутую тему для терминала в винде</title><pubDate>Wed, 30 Oct 2024 17:43:54 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/f1/ac/f1acb0dd-5749-42f1-bb2f-9c046bd9251f.png"></media:content><category>Гайды 📖</category><description><![CDATA[<img src="https://img1.teletype.in/files/cf/26/cf26a6b6-3085-470b-8a55-cd50bb9349b0.jpeg"></img>Сегодня при слове &quot;терминал&quot; есть сочетание слов типа Ubuntu, Linux ну и или MacOS. Операционная система Windows неправомерно подвержена гонению. Я намерен это исправить и создать офигенный шаблон для написания ПО в ОС Windows. Все темы бесплатны и в свободном доступе.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#3RUq">Цели</a></li>
      <li class="m_level_1"><a href="#i2J2">Программы</a></li>
      <li class="m_level_1"><a href="#9QQH">Настройка терминала</a></li>
      <li class="m_level_1"><a href="#Idxf">Установка Nerd Fonts</a></li>
      <li class="m_level_1"><a href="#S3GA">Настройка цветов</a></li>
      <li class="m_level_1"><a href="#d0Q4">Starship</a></li>
    </ul>
  </nav>
  <h2 id="3RUq">Цели</h2>
  <p id="MKN8">Сегодня при слове &quot;терминал&quot; есть сочетание слов типа Ubuntu, Linux ну и или MacOS. Операционная система Windows неправомерно подвержена гонению. Я намерен это исправить и создать офигенный шаблон для написания ПО в ОС Windows. Все темы бесплатны и в свободном доступе.</p>
  <p id="JLJL">Иными словами, мы делаем из этого:</p>
  <figure id="cDmT" class="m_original">
    <img src="https://img3.teletype.in/files/e9/68/e9688437-0878-44f9-8982-2f4abf508514.png" width="930" />
  </figure>
  <p id="MOv8">Это:</p>
  <h2 id="i2J2">Программы</h2>
  <p id="hDyt">Для работы нам понадобится несколько программ. Для базовой работы я возьму такие приложения как:</p>
  <ul id="39Ro">
    <li id="7Y0m"><a href="https://www.sublimetext.com/3" target="_blank"><strong>Sublime Text 3</strong></a>. Задача Sublime Text&#x27;а создать удобную среду для работы с кодом. Сейчас я больше всего пишу на Python и покажу как выглядит код в Sublime из коробки. Я использую автоматическую тему, которая подстроится под системную.</li>
  </ul>
  <figure id="LpCr" class="m_original">
    <img src="https://img1.teletype.in/files/88/bb/88bbb476-7721-48b6-b8a9-6f795cba1736.png" width="880" />
  </figure>
  <ul id="ZrYM">
    <li id="SyO0"><a href="https://typora.io/" target="_blank">Typora</a>. Так как я пишу много текста про код — его нужно оформить. Я оформляю текст в маркдауне (это такой шаблон написания текста с кодом). Все PDFки, которые вы тут видите (в том числе и эту) — работа данного ПО. Тема — Night. Дополнительные темы можно посмотреть <a href="https://theme.typora.io/" target="_blank">тут</a>.</li>
  </ul>
  <figure id="PpHN" class="m_original">
    <img src="https://img3.teletype.in/files/60/9b/609bf408-d9d9-4f67-b990-b8a537bb6ace.png" width="869" />
  </figure>
  <ul id="lR72">
    <li id="JBN4"><a href="https://notepad-plus-plus.org/" target="_blank"><strong>NotePad++</strong></a>. Это ещё один текстовый редактор. С ним я чиню конфигурационные файлы, так как очень легко менять кодировки и размеры символов. Тема как у системы + фиолетовая.</li>
  </ul>
  <figure id="yoFl" class="m_original">
    <img src="https://img3.teletype.in/files/2b/b5/2bb5c8ce-405f-479e-9f8c-163703d791aa.png" width="883" />
  </figure>
  <ul id="pluQ">
    <li id="sD7q"><a href="https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=ru-ru&gl=ru" target="_blank"><strong>Windows Terminal</strong></a>. Это улучшенная версия системного ПО Windows (командной строки). Добавлены много фич. О них мы ещё поговорим.</li>
  </ul>
  <figure id="5ESz" class="m_original">
    <img src="https://img3.teletype.in/files/aa/b9/aab93bbe-7a47-4a52-b507-f97a16155931.png" width="895" />
  </figure>
  <p id="iJX2">На данный момент есть несколько сложностей со скачиванием всех утилит. Чтобы упростить задачу, всё что нужно дня скачивания из программ я поместил в <a href="https://disk.yandex.ru/d/tYUBUHKnqKDcAg" target="_blank">этот архив</a>.</p>
  <h2 id="9QQH">Настройка терминала</h2>
  <p id="VVQY">Какие настройки я выставил в самом терминале. Для их настройки я перешёл во вкладку &quot;Параметры&quot;:</p>
  <figure id="U86h" class="m_original">
    <img src="https://img4.teletype.in/files/f6/a0/f6a0031e-50a6-44f3-b932-89e667617de8.png" width="921" />
  </figure>
  <p id="I492">По умолчанию, настройки выставятся в очень стандартный и весьма красивый вид.</p>
  <figure id="0DAm" class="m_original">
    <img src="https://img2.teletype.in/files/18/30/18307ea8-1a9a-4528-9003-d75a3accdaeb.png" width="921" />
  </figure>
  <p id="YAaw">Многие спрашивали меня как установить Ubuntu в терминал Windows. На самом деле, это проще чем кажется.</p>
  <ul id="T1Eu">
    <li id="lO2F">Переходим в панель управления.</li>
  </ul>
  <figure id="ZX9y" class="m_original">
    <img src="https://img2.teletype.in/files/14/6f/146fdd31-bca4-4114-a5f9-5dda46518dc5.png" width="882" />
  </figure>
  <ul id="BtZO">
    <li id="DvIC">Затем, выбираем пункт &quot;Удаление программ&quot; (не волнуйтесь, мы не будем ничего удалять).</li>
  </ul>
  <figure id="zpZN" class="m_original">
    <img src="https://img1.teletype.in/files/cc/6d/cc6db12c-42f1-4932-b3c3-d96c1eafaeb7.png" width="886" />
  </figure>
  <ul id="wJAc">
    <li id="qUEz">Выбираем в открывшемся окошке пункт &quot;Включение или отключение компонентов Windows&quot;</li>
  </ul>
  <figure id="zvy9" class="m_original">
    <img src="https://img3.teletype.in/files/ea/41/ea41c438-d4e1-471a-9af7-bda53db72602.png" width="871" />
  </figure>
  <ul id="TMeB">
    <li id="L3g7">Далее, нас интересует пункт &quot;Подсистема Windows для Linux&quot;. Этот пункт нужно включить.</li>
  </ul>
  <figure id="evs9" class="m_original">
    <img src="https://img4.teletype.in/files/79/92/79928a7c-c503-46c6-a90b-31a3dd0a7575.png" width="881" />
  </figure>
  <ul id="Ocvr">
    <li id="E326">Дальше, всё просто — <a href="https://apps.microsoft.com/store/search/linux" target="_blank">заходим в MS Store</a> и скачиваем нужную систему.</li>
  </ul>
  <h2 id="Idxf">Установка Nerd Fonts</h2>
  <p id="5DXG">Установим крутые темы в виде текста и символов. Переходим на <a href="https://www.nerdfonts.com/" target="_blank">сайт Nerd Fonts</a>. И нажимаем кнопочку Download. Там выбирайте любую тему, которая вам понравилась. Лично мне очень нравится тема JetBrainsMono. Её я и скачал. Ещё я использовал Hack Nerd Font.</p>
  <figure id="mdU7" class="m_original">
    <img src="https://img4.teletype.in/files/76/b3/76b31911-1d67-4d5e-a108-30294f50b784.png" width="925" />
  </figure>
  <p id="iUVh">Далее, наша задача разархивировать папку куда угодно и установить все шрифты. Самый простой способ это сделать: открыть папку, выделить все файлы (Ctrl+A), правая кнопка мыши, установить для всех пользователей.</p>
  <figure id="AQNp" class="m_original">
    <img src="https://img1.teletype.in/files/c0/d2/c0d2c97a-af27-47fd-bd9f-3a11bb1fbc37.png" width="933" />
  </figure>
  <p id="Swvz">Далее, после установки, перейдите в настройки терминала и выберите понравившейся шрифт по умолчанию.</p>
  <figure id="M8ri" class="m_original">
    <img src="https://img3.teletype.in/files/65/8a/658ac61e-0e5f-479f-bf1c-5ea421e6945c.png" width="921" />
  </figure>
  <h2 id="S3GA">Настройка цветов</h2>
  <p id="M9tt">Настройка цветов может быть любой, но я подготовил отдельный файл, в котором указаны все настройка цветовой схемы. Для её настройки, перейдите в раздел настройки терминала &quot;Цветовые схемы&quot; и используете готовую.</p>
  <p id="Apmz">Чтобы сделать тему уникальной, можно открыть JSON файл (внизу слева) в терминале и настроить цветовую палитру детально. Тут нам тоже помогает Sublime Text</p>
  <figure id="QYdT" class="m_original">
    <img src="https://img1.teletype.in/files/4d/f8/4df8bf53-e073-4d11-9f68-6d152842f405.png" width="921" />
  </figure>
  <p id="ZL1N">Чтобы всё работало хорошо, скопируйте и вставьте всё, что в фигурных скобках в пункте <code>defaults</code>, не трогайте пункт <code>list</code> и вставьте пункт <code>schemes</code>.</p>
  <pre id="GZ5z" data-lang="jsx">{
    &quot;$help&quot;: &quot;https://aka.ms/terminal-documentation&quot;,
    &quot;$schema&quot;: &quot;https://aka.ms/terminal-profiles-schema&quot;,
    &quot;actions&quot;: [],
    &quot;defaultProfile&quot;: &quot;{574e775e-4f2a-5b96-ac1e-a2962a402336}&quot;,
    &quot;firstWindowPreference&quot;: &quot;defaultProfile&quot;,
    &quot;profiles&quot;: 
    {
        &quot;defaults&quot;: 
        {
            &quot;colorScheme&quot;: &quot;xcad&quot;,
            &quot;cursorShape&quot;: &quot;filledBox&quot;,
            &quot;font&quot;: 
            {
                &quot;face&quot;: &quot;Hack Nerd Font&quot;,
                &quot;size&quot;: 10
            },
            &quot;historySize&quot;: 12000,
            &quot;intenseTextStyle&quot;: &quot;bright&quot;,
            &quot;opacity&quot;: 95,
            &quot;padding&quot;: &quot;8&quot;,
            &quot;scrollbarState&quot;: &quot;visible&quot;,
            &quot;useAcrylic&quot;: false
        },
        &quot;list&quot;: 
        [
            {
                &quot;commandline&quot;: &quot;C:\\Program Files\\PowerShell\\7\\pwsh.exe --NoLogo&quot;,
                &quot;elevate&quot;: false,
                &quot;guid&quot;: &quot;{574e775e-4f2a-5b96-ac1e-a2962a402336}&quot;,
                &quot;hidden&quot;: false,
                &quot;icon&quot;: &quot;%userprofile%\\WindowsTerminalIcons\\ps.png&quot;,
                &quot;name&quot;: &quot;PowerShell&quot;,
                &quot;source&quot;: &quot;Windows.Terminal.PowershellCore&quot;
            },
            {
                &quot;guid&quot;: &quot;{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}&quot;,
                &quot;hidden&quot;: false,
                &quot;icon&quot;: &quot;%userprofile%\\WindowsTerminalIcons\\ubuntu.png&quot;,
                &quot;name&quot;: &quot;Ubuntu Linux&quot;,
                &quot;source&quot;: &quot;Windows.Terminal.Wsl&quot;,
                &quot;startingDirectory&quot;: &quot;\\\\wsl$\\Ubuntu-20.04\\home\\xcad&quot;
            },
            {
                &quot;guid&quot;: &quot;{46ca431a-3a87-5fb3-83cd-11ececc031d2}&quot;,
                &quot;hidden&quot;: false,
                &quot;icon&quot;: &quot;%userprofile%\\WindowsTerminalIcons\\kali.png&quot;,
                &quot;name&quot;: &quot;Kali Linux&quot;,
                &quot;source&quot;: &quot;Windows.Terminal.Wsl&quot;,
                &quot;startingDirectory&quot;: &quot;\\\\wsl.localhost\\kali-linux\\home\\xcad&quot;
            },
            {
                &quot;guid&quot;: &quot;{0caa0dad-35be-5f56-a8ff-afceeeaa6101}&quot;,
                &quot;icon&quot;: &quot;%userprofile%\\WindowsTerminalIcons\\cmd.png&quot;,
                &quot;name&quot;: &quot;Commandline&quot;
            },
            {
                &quot;guid&quot;: &quot;{b453ae62-4e3d-5e58-b989-0a998ec441b8}&quot;,
                &quot;hidden&quot;: true,
                &quot;icon&quot;: &quot;%userprofile%\\WindowsTerminalIcons\\azure.png&quot;,
                &quot;name&quot;: &quot;Azure Cloud Shell&quot;,
                &quot;source&quot;: &quot;Windows.Terminal.Azure&quot;
            }
        ]
    },
    &quot;schemes&quot;: 
    [
        {
            &quot;background&quot;: &quot;#1A1A1A&quot;,
            &quot;black&quot;: &quot;#121212&quot;,
            &quot;blue&quot;: &quot;#2B4FFF&quot;,
            &quot;brightBlack&quot;: &quot;#666666&quot;,
            &quot;brightBlue&quot;: &quot;#5C78FF&quot;,
            &quot;brightCyan&quot;: &quot;#5AC8FF&quot;,
            &quot;brightGreen&quot;: &quot;#905AFF&quot;,
            &quot;brightPurple&quot;: &quot;#5EA2FF&quot;,
            &quot;brightRed&quot;: &quot;#BA5AFF&quot;,
            &quot;brightWhite&quot;: &quot;#FFFFFF&quot;,
            &quot;brightYellow&quot;: &quot;#685AFF&quot;,
            &quot;cursorColor&quot;: &quot;#FFFFFF&quot;,
            &quot;cyan&quot;: &quot;#28B9FF&quot;,
            &quot;foreground&quot;: &quot;#F1F1F1&quot;,
            &quot;green&quot;: &quot;#7129FF&quot;,
            &quot;name&quot;: &quot;xcad&quot;,
            &quot;purple&quot;: &quot;#2883FF&quot;,
            &quot;red&quot;: &quot;#A52AFF&quot;,
            &quot;selectionBackground&quot;: &quot;#FFFFFF&quot;,
            &quot;white&quot;: &quot;#F1F1F1&quot;,
            &quot;yellow&quot;: &quot;#3D2AFF&quot;
       lebar&quot;: true,
    &quot;tabSwitcherMode&quot;: &quot;inOrder&quot;,
    &quot;useAcrylicInTabRow&quot;: true
}</pre>
  <p id="6agR">Результат:</p>
  <figure id="evmJ" class="m_original">
    <img src="https://img4.teletype.in/files/3a/90/3a90c1a6-e5c1-45ef-b087-00bb1ed8ac65.png" width="910" />
  </figure>
  <h2 id="d0Q4">Starship</h2>
  <p id="4rpQ">Starship</p>
  <p id="8i30">Установим крутую адаптацию. Как сами про себя пишут &quot;Звёздные кораблики&quot;, их продукт, это минимальная, молниеносная и бесконечно настраиваемая подсказка для любой оболочки!</p>
  <p id="QNEY">Установка весьма проста:</p>
  <ul id="TFjG">
    <li id="SOWj">Перейти на <a href="https://starship.rs/" target="_blank">сайт компании</a>.</li>
    <li id="fltO">Установить через уже улучшенный терминал приложение (списки возможных установок написаны на сайте). Я использовал команду <code>winget install starship</code>.</li>
  </ul>
  <figure id="veua" class="m_original">
    <img src="https://img4.teletype.in/files/b0/dc/b0dc4c43-7462-4546-80e5-c63b7b244f1c.png" width="886" />
  </figure>
  <ul id="qxDp">
    <li id="bioh">Следующая задача — установить нужные настройки в файлы профилей ваших сред (в которых вы пишите). Для начала, я взял самую сложную часть — работу с командной строкой. Для этого, вам нужно установить <a href="https://chrisant996.github.io/clink/clink.html" target="_blank">Clink</a>.</li>
    <li id="P9sj">Перейдя на сайт книлка, вы попадёте на сложную страницу. На неё нужно перейти сразу на вкладку репозитория на гитхабе.</li>
  </ul>
  <figure id="v718" class="m_original">
    <img src="https://img3.teletype.in/files/27/1e/271e1a11-f7c5-4599-a520-f2122048cc0f.png" width="617" />
  </figure>
  <ul id="KIRr">
    <li id="Mtvv">Перейдя на данную страницу, нужно скачать файлы. Найти из можно на <a href="https://github.com/chrisant996/clink/releases" target="_blank">странице релиза</a>.</li>
  </ul>
  <figure id="GNFc" class="m_original">
    <img src="https://img3.teletype.in/files/e5/26/e526b4c9-a9bc-4b93-b105-dceae6cb67e9.png" width="881" />
  </figure>
  <ul id="a1t9">
    <li id="b4F8">Далее, я выбрал просто доступный ассет.</li>
  </ul>
  <figure id="cCf7" class="m_original">
    <img src="https://img3.teletype.in/files/69/73/69735af9-463a-4eea-b6c1-b67d820ad082.png" width="893" />
  </figure>
  <ul id="4Kax">
    <li id="a9IL">Далее, установите программу. По умолчанию, папка установки <code>C:/Program Files (x86)/clink</code>. Перейдите в данную папку.</li>
    <li id="Kp9B">В это время, в саблайме создайте файл <code>starship.lua</code> и заполните его строкой<br /><code>load(io.popen(&#x27;starship init cmd&#x27;):read(&quot;*a&quot;))()</code></li>
  </ul>
  <p id="T4Ub">Результат:</p>
  <figure id="5OYo" class="m_original">
    <img src="https://img1.teletype.in/files/4d/97/4d97b6ce-c2a8-43a2-9e7e-fcaea705af38.png" width="910" />
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/Vbo2TkvnwxJ</guid><link>https://teletype.in/@valerylinkov/Vbo2TkvnwxJ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/Vbo2TkvnwxJ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Супер простая инструкция, как оставаться с заблокированными ресурсами</title><pubDate>Wed, 30 Oct 2024 17:25:17 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/43/32/43329698-c05c-4178-a7c9-11143d58a5e3.png"></media:content><category>Гайды 📖</category><description><![CDATA[<img src="https://img1.teletype.in/files/84/85/8485c183-37fe-4435-b5ab-93d6773b6a7d.jpeg"></img>Тут всё просто. Нужно скачать Tor браузер по ссылке. Сеть тор просто так не заблокировать. В ней всегда будет анонимность и доступ к ресурсам. Но есть существенный минус — работать можно только через тулзу. Уберплюс — всё бесплатно.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#bbQI">Вариант 0. Tor браузер.</a></li>
      <li class="m_level_1"><a href="#imMz">Вариант 1. АнтиЗапрет.</a></li>
      <li class="m_level_1"><a href="#RzNu">Вариант 2. VPN.</a></li>
      <li class="m_level_2"><a href="#ITge">Вариант 2.1. Готовые сервер под L2TP.</a></li>
      <li class="m_level_2"><a href="#nLQB">Вариант 2.2. Всё сам.</a></li>
      <li class="m_level_3"><a href="#XoyV">Шаг 1. Арендуем VDS сервер.</a></li>
      <li class="m_level_3"><a href="#5kzb">Шаг 2. Подключаемся по SSH</a></li>
      <li class="m_level_3"><a href="#224a">Шаг 3. Устанавливаем OpenVPN</a></li>
      <li class="m_level_3"><a href="#CyYw">Шаг 4. Качаем конфиг по FTP</a></li>
      <li class="m_level_3"><a href="#qxhb">Шаг 5. Празднуем</a></li>
      <li class="m_level_1"><a href="#bIiz">Итоги</a></li>
    </ul>
  </nav>
  <h2 id="bbQI">Вариант 0. Tor браузер.</h2>
  <figure id="6Hav" class="m_original">
    <img src="https://img1.teletype.in/files/8f/d3/8fd3df08-e557-4260-98e7-7cf6d974e6fb.png" width="595" />
  </figure>
  <p id="NDPw">Тут всё просто. Нужно скачать Tor браузер <u>по ссылке</u>. Сеть тор просто так не заблокировать. В ней всегда будет анонимность и доступ к ресурсам. Но есть существенный минус — работать можно только через тулзу. Уберплюс — всё бесплатно.</p>
  <h1 id="imMz">Вариант 1. АнтиЗапрет.</h1>
  <figure id="gL2M" class="m_original">
    <img src="https://img3.teletype.in/files/26/e9/26e9bac0-b648-46d3-9dfc-08af1a96b528.png" width="601" />
  </figure>
  <p id="Hs4H">Готовое решение из коробки и бесплатных VPN. Ещё раз скажу, чтобы точно было понятно. <strong>Оно не безопасно</strong>. Вся инструкция описана на их <a href="https://antizapret.prostovpn.org/" target="_blank">официальном сайте</a>.</p>
  <h1 id="RzNu">Вариант 2. VPN.</h1>
  <figure id="8euz" class="m_original">
    <img src="https://img3.teletype.in/files/ad/1e/ad1e5f8e-3811-4a2c-82a3-c39d04c7eb75.png" width="593" />
  </figure>
  <p id="4CLT">В посту ранее, я писал, что сам по себе VPN — бесполезен. Вариант нужно разбит на несколько задач:</p>
  <ul id="3o7i">
    <li id="m3a1">Найти внешний сервер VDS или VPS.</li>
    <li id="47yt">Настроить форвардинг трафика через данный сервер (создали прокси). </li>
    <li id="Irp8">Фигачим на данное соединение шифрование.</li>
  </ul>
  <p id="bZW8">Приступим.</p>
  <p id="FlDu">Сразу оговорюсь, данный способ, я бы разбил на два разных. Первый попроще, второй посложнее. Обо весьма безопасны. Вопрос в целях. Если цель — скрыть своё пребывание от кучи сторонних глаз (вы творите что-то не оч хорошее), то лучше одумайтесь или используйте вариант</p>
  <p id="pWbb">2.2.  Если же задача вылезти в инсту и не делать себе мозг проблемами — вариант 2.1 точно для вас.</p>
  <h2 id="ITge">Вариант 2.1. Готовые сервер под L2TP.</h2>
  <p id="PC7c">Лично я использую сервера компании Inferno Solutions. <a href="https://cp.inferno.name/cart.php?gid=56" target="_blank">Решение такое</a>:</p>
  <ul id="BGY3">
    <li id="XZJB">5 видов VPN соединений: PPTP, L2TP/IPsec, WireGuard и, конечно же, OpenVPN!</li>
    <li id="JbVL">10+ учетных записей для OpenVPN (5 TCP + 5 UDP), шифрование AES-256 2048 bit</li>
    <li id="OFrD">2+ учетных записи для PPTP и L2TP/IPsec</li>
    <li id="p3za">2+ учетных записи для Socks 5 прокси (идеально для Telegram)</li>
    <li id="cPX5">Поддержка Windows, Linux, Mac OS, iOS, Android, роутеров и других систем!</li>
    <li id="uyIm">Скорость подключения 1 Gbit/s</li>
    <li id="b9Of">22 стран на выбор (я сижу в Эстонии)</li>
  </ul>
  <p id="f10d">Сами Инферно делают оговорку: <strong>Только для индивидуального и легального использования!</strong></p>
  <figure id="IOEy" class="m_original">
    <img src="https://img3.teletype.in/files/22/e9/22e9a954-055e-47c5-ab75-b622edf15f16.png" width="517" />
  </figure>
  <p id="Tj2n">Что это значит и как всё происходит? Вам настраивают типовой сервер на VPS. VPS — это ситуация, когда вам выдают виртуальный доступ к выделенной удалённой среде. В случае с Инферно, средой выступает CentOS 7 с характеристиками в 512 MB оперативы, 1 ядро проца, 5 Гб SSD-диска.</p>
  <p id="oVvM">Вам предустанавливают систему и настраивают её. Если вы сделаете что-то нехорошее и власти запросят официальным письмом доступ к вашим данным — доступ им будет предоставлен. Но есть нюанс. Компания находится в Лондоне и запрос нужно будет делать в их юрисдикцию, а значит и нарушение, которое вы будете совершать (я надеюсь не будете), должно быть международное.</p>
  <p id="s72y">Лично меня решение от Inferno более чем устроило, так как есть <a href="https://cp.inferno.name/knowledgebase/19/Instruktsii-po-nastroyke" target="_blank">подробные инструкции </a>для моей семьи и друзей как что ткнуть чтобы работало. Второй крутой момент лично для меня — разные профили в настройках (от OpenVPN, до L2TP).</p>
  <h2 id="nLQB">Вариант 2.2. Всё сам.</h2>
  <p id="S2IK">Вариант для АмаМамаКриминал. Делаем сами всё. Тут несколько шагов.</p>
  <ol id="RE30">
    <li id="LF0D">Аренда виртуального сервера.</li>
    <li id="OWeU">Подключение к серверу по SSH.</li>
    <li id="vF23">Установка и настройка OpenVPN.</li>
    <li id="dcRT">Скачивание конфига через FTP-клиент.</li>
    <li id="fAoE">Подключение к VPN.</li>
  </ol>
  <h3 id="XoyV">Шаг 1. Арендуем VDS сервер.</h3>
  <p id="LIYB">Лично я рекомендую арендовать ваш собственный сервер. Таким образом вы избавитесь от внешних проблем с безопасностью. От физических атак на весь сервер (там ваш и не ваш виртуальные сервера) — упадут все.</p>
  <p id="QmQR">Компаний-поставщиков услуг VDS просто дикое количество. Выбирайте по странам близлежащие страны вне запретов, чтобы уменьшить пинг (Латвия, Эстония, Литва, Нидерланды, Филиппины).</p>
  <p id="sD5p">Установите на ваш сервер Ubuntu 20.04. Чаще всего, она предустановлена. После оплаты и активации вам придут доступы к серверу, которые понадобятся для дальнейшей работы: <strong>логин</strong>, <strong>пароль </strong>и <strong>IP-адрес</strong>.</p>
  <h3 id="5kzb">Шаг 2. Подключаемся по SSH</h3>
  <p id="qiNa">SSH — это протокол, позволяющий производить удаленное управление операционной системой. С помощью SSH-клиента (специальной программы) можно подключаться к VDS/VPS и производить необходимые настройки.</p>
  <p id="asUu">Чтобы не мучать ни вас, ни себя критериями выбора программ, скажу просто — Putty классная тулза. Она бесплатная и скачать её можно с <a href="https://www.putty.org/" target="_blank">официального сайта</a>.</p>
  <p id="Ab88">Открываем Putty, в поле «Host Name» вводим IP-адрес сервера, в поле «Port» оставляем «22» (SSH). Нажимаем кнопку «Open». Откроется консоль, в которой мы будем работать с сервером.</p>
  <figure id="zll6" class="m_original">
    <img src="https://img4.teletype.in/files/77/e8/77e864db-a677-4d19-8795-f386a8c0b2a4.png" width="591" />
  </figure>
  <p id="lHU1">Вводим логин (можно сразу под «root») и нажимаем Enter. Вводим пароль от сервера и нажимаем Enter. Подключение прошло успешно. Обратите внимание, пароль не отображается в интерфейсе Putty — не пугайтесь, это нормально.</p>
  <figure id="VX6X" class="m_original">
    <img src="https://img1.teletype.in/files/4b/0f/4b0f2a34-b1c2-48f1-b622-9ee4382df3aa.png" width="601" />
  </figure>
  <h3 id="224a">Шаг 3. Устанавливаем OpenVPN</h3>
  <p id="pSkw">Чтобы установить OpenVPN на сервер, вводим следующую команду и нажимаем Enter:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="o8qx">wget <a href="https://git.io/vpn" target="_blank">https://git.io/vpn</a> -O openvpn-install.sh &amp;&amp; bash openvpn-install.sh</p>
  </section>
  <p id="TCGQ">Запустится процесс установки. Далее выполним настройку и создадим конфигурационный файл:</p>
  <ol id="6qOj">
    <li id="Yylu"><strong>Which protocol should OpenVPN use? </strong>Выбираем протокол: вводим цифру «1» (UDP) и нажимаем Enter. Можно и TCP, но подключаться будем дольше через трёхфакторное рукопожатие.</li>
    <li id="ilEj"><strong>What port should OpenVPN listen to? </strong>Ничего не вводим и просто нажимаем Enter.</li>
    <li id="eob7"><strong>Select a DNS server for the clients. </strong>Выбираем DNS-сервер: например, вводим цифру «2» (Google) и нажимаем Enter.</li>
    <li id="BwEG"><strong>Enter a name for the first client. </strong>Придумываем имя клиента на английском языке (оно может быть любым) и нажимаем Enter.</li>
  </ol>
  <p id="oemP">Далее нажимаем любую кнопку для начала установки и ждем завершения.</p>
  <figure id="8vol" class="m_original">
    <img src="https://img2.teletype.in/files/14/1d/141d7316-59ef-47f1-bc9f-86f63eec7f3b.png" width="601" />
  </figure>
  <h3 id="CyYw">Шаг 4. Качаем конфиг по FTP</h3>
  <p id="Y16Q">FTP — протокол передачи файлов по сети, а FTP-клиент — специальная программа для упрощения доступа к FTP-серверу. С помощью этой программы мы подключимся к VDS и скачаем созданный конфигурационный файл.</p>
  <p id="27WW">Опять таки, не разглагольствуя о великом, мой выбор — FileZilla (<a href="https://filezilla.ru/" target="_blank">качать тут</a>).</p>
  <p id="e2Uf">Открываем FileZilla. В поле «Хост» вводим:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="pQRw">sftp://ip_нашего_сервера</p>
  </section>
  <p id="K4iW">Имя пользователя и пароль — берем из доступов (их вам должны были прислать при закупке VDS). Нажимаем кнопку «Быстрое соединение». После подключения в интерфейсе справа отобразятся папки на сервере, а слева — на вашем компьютере. Находим конфигурационный файл на сервере и сохраняем его у себя на компьютере (с помощью мыши перетаскиваем в левую часть экрана в интерфейсе FileZilla).</p>
  <figure id="IjZM" class="m_original">
    <img src="https://img2.teletype.in/files/56/98/5698cdb3-197a-4846-9b6c-86385200017f.png" width="601" />
  </figure>
  <p id="F6bW">Чтобы открыть конфигурационный файл, нужно скачать программу OpenVPN <a href="https://openvpn.net/community-downloads/" target="_blank">с официального  сайта.</a></p>
  <h3 id="qxhb">Шаг 5. Празднуем</h3>
  <p id="Nec7">После установки OpenVPN нажимаем на конфигурационный файл два раза и нажимаем «Да». Обратите внимание, файл сохранился в папке на нашем компьютере, которая была выбрана в программе FileZilla при скачивании.</p>
  <h1 id="bIiz">Итоги</h1>
  <p id="wyHA">Надеюсь, установка прошла успешно! Пишите что думаете и как вы обходите блокировки. Всех люблю!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/PaDWolpUPHY</guid><link>https://teletype.in/@valerylinkov/PaDWolpUPHY?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/PaDWolpUPHY?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Хабрахабр. Легенда о комьюнити </title><pubDate>Wed, 30 Oct 2024 16:56:44 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/71/2b/712b7e70-ab07-4ad7-8a9e-be9d41535030.png"></media:content><category>Бомбёж 🔥</category><description><![CDATA[<img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/45a/fa9/311/45afa93112250808b88a50b97219cd54.png"></img>Разрабы. Сетевики. Диайвайщики. Прочие айтишники. Когда-то давно четыре народа жили в мире. Но всё изменилось, когда Народ прочих айтишников развязал войну. Только Хабрахабр, властелин всех четырёх платформ, мог остановить захватчиков. Но, когда мир нуждался в Хабрахабре больше всего, он исчез. Прошло сто лет, и я нашёл новый Хабр, в стоке прочих комьюнити именуемых «Флудилки». И хотя его искусство покорения статей было велико, ему предстояло ещё многому научиться. Но я верил, что Хабр спасёт мир!]]></description><content:encoded><![CDATA[
  <figure id="GuUq" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/45a/fa9/311/45afa93112250808b88a50b97219cd54.png" width="604" />
  </figure>
  <blockquote id="Wmrx">Разрабы. Сетевики. Диайвайщики. Прочие айтишники. Когда-то давно четыре народа жили в мире. Но всё изменилось, когда Народ прочих айтишников развязал войну. Только Хабрахабр, властелин всех четырёх платформ, мог остановить захватчиков. Но, когда мир нуждался в Хабрахабре больше всего, он исчез. Прошло сто лет, и я нашёл новый Хабр, в стоке прочих комьюнити именуемых «Флудилки». И хотя его искусство покорения статей было велико, ему предстояло ещё многому научиться. Но я верил, что Хабр спасёт мир!</blockquote>
  <h2 id="B7ot">Книга 1. Статьи.</h2>
  <p id="UUhM">Чтобы точно не потерять кто понаписал это послание, сразу представлюсь:</p>
  <figure id="4C5O" class="m_original">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/ff6/d08/985/ff6d08985c5da83ce00b568b169fbce6.jpg" width="640" />
  </figure>
  <h5 id="flOj">Валерий Линьков</h5>
  <p id="YCHC">Писал сам, без угроз и кредитов</p>
  <p id="kNWL">Мой путь в Хабр начался с далёкого 2016 года. Я был супер-активным читателем, так как был школолошником, который фанател об IT и боготворил всех людей внутри. Конечно! Они же пьют сидр, вумничают и получают много деняк! Сердце школьника покорено на ровне со стримлерами.</p>
  <p id="0eeV">Как же долго я пытался попасть на Хабр. Писал новости, статьи, пытался извергнуть из себя мысль как мог и каждый раз НЛО меня динамило. Я понимал, что недотягиваю до звания пре-джуна и нифига не понимаю в IT. Боже, как я переживал по этому поводу. Как самый дёрганный чувак по поводу своих знаний, читал всё что было написано на русском, ломаном английском и мечтал быть среди тех крутых ребят из аськи. Я ждал каждый раз общения со старшими товарищами из индустрии и рвал все жилы, чтобы добиться <strong>признания</strong> от Хабр.</p>
  <p id="cF7N">И вот, международный женский день 2018 года. <strong>Меня приняло НЛО! </strong>Моему счастью не было придела. Теперь, я уже не школьник, а работник офиса, цискарь, студент технического ВУЗа и препод инфы в школе. Конечно, я ещё не <strong>айти</strong>, но уже <em>айтёныш</em>.</p>
  <figure id="GS2k" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/8ca/ed9/466/8caed946674bc49ae716330f1203a567.png" width="1191" />
  </figure>
  <p id="Dfjx">Меня читали! Знаете какая оценка у статьи? Не догадываетесь? +4. Ну я же не <strong>айти</strong>, я <em>айтёныш </em>(ну недоучка в айти). А знаете сколько комментов? Немножко... 54... Что же мне писали:</p>
  <figure id="E6uK" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/a50/8b0/e30/a508b0e300654881cc164670da305a09.png" width="1920" />
  </figure>
  <p id="RWcF">Есть к чему стремиться! Мотивация поднята! Работаем! Пишем следующую статью, где учёл недостатки.</p>
  <figure id="5thX" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b28/650/77a/b2865077a16d0315313620d55ddc41d1.png" width="1183" />
  </figure>
  <p id="LpUj">+1... Комменты (а их всего 15):</p>
  <figure id="j1hu" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/add/36c/219/add36c2197c7d282d74dfd18af63fc37.png" width="1920" />
  </figure>
  <p id="OIEm">Ну да, ну да. Пошёл я нафиг. Буду работать ещё! Потом 6 статей и все до +9. Мало! Надо лучше! Карма болтается на 10. Я айтёныш, а хочу быть айти!</p>
  <p id="lAZj">Дебют! Моя статья написанная с помощью Алексея Лукацкого (кто не знает, это бизнес-консультант циски в те годы, а сейчас на похожей должности в Positive Technologies). Вот он АЙТИ! Скоро будет круто:</p>
  <figure id="kKOp" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/69f/663/f65/69f663f654fd94025b5ca042eac3bc94.png" width="1171" />
  </figure>
  <p id="qI11">И тут уже +16! Ура! Я счастлив! Теперь не так мало. Комментов 24 и из них ничего особо интересного, так пара замечаний, что теперь «маркетинговы булшит».</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="qHxK">То есть, когда я пишу про технологию и разбираю её, я получаю ответ &quot;При чём тут Cisco&quot;, а когда пишу про Cisco &quot;Ну это маркетинговый булшит&quot;. Чё? А как тогда писать?! Ну ладно. Тролли наверное...</p>
  </section>
  <p id="Jmt6">В любом случае, это успех! Я рад и хочу выпустить новую статью. Ручки трясутся, ведь не хочется уровень опускать. А я ж <em>айтёныш</em>. Та статья была популярна только благодаря Лукацкому. Вот он <strong>айти</strong>, а я... ну вы поняли...</p>
  <p id="WoiP">Год паузы (чуть меньше) и снова 8 марта я пишу статью о сериале, который покорил моё сморщенное айтёнышное сердечко: &quot;Мистер Робот&quot;. Ииииииии. Я в шоке:</p>
  <figure id="n88j" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/dc9/8e8/736/dc98e8736ab1f99838076c8820a7ff17.png" width="1188" />
  </figure>
  <p id="6SxC">Оценки +29, комментов 162! Офигеть! И нет негатива. Все благодарят за разбор крутого сериала. Вау!</p>
  <p id="Kbt7">Тут меня начинают покорять смутные сомнения &quot;А может я уже айти?! Или людям просто понравился сериал?&quot;. Надо проверить! Следующая статья через месяц:</p>
  <figure id="Ikei" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/3a8/a70/736/3a8a70736e6dea9f808ed31c499a9fe1.png" width="1205" />
  </figure>
  <p id="3dak">-3. Я чмоня. Похороните меня за плинтусом. Далее, я думаю &quot;Может я журналист про сериалы?&quot;. Далее выпускаю несколько статей и карма уже +20 где-то. Ура! А может что-то интересное сделать? Попробую. Пишу про историю с попыткой Хуавей сделать что-то на примере Кремневой долины в IT. Беру интервью с Егором Бугаенко. Нуууу и просто 0. Хмм... Ну хоть не минус.</p>
  <p id="G4lL">Далее, рассказывать про мои статьи не очень интересно. Мой рекорд по статья +43. И это статья про игры.</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="ZQmC">Мы же техно-сообщество. Мы же пишем про айти. Про что-то интересное в нём, а не &quot;Как сделать бутерброд&quot; или &quot;Что посмотреть вечером&quot;. Почему же так с моей кармой и статьями. Может это не моё? Может я чего-то не понимаю? Может я как ЛжеДмитрий ЛжеАйти?</p>
  </section>
  <p id="qFkS">Что я понял из своего опыта:</p>
  <ul id="dTjI">
    <li id="GQST">Хабру интересно читать про личный опыт работы с конкретной штукой (желательно нишевой);</li>
    <li id="zGI4">Хабру интересно посмотреть что-то прикольное для себя;</li>
    <li id="ejum">На Хабре любят холеварить.</li>
  </ul>
  <h2 id="SHJu">Книга 2. Технотекст</h2>
  <p id="h8Ss">У Хабра есть такой прикольный конкурс как «Технотекст». Писал статьи в Технотекст я с 2021 года. Что‑то нравилось, что‑то нет. Но я понимал почему я не побеждаю. И вот долгожданная обнова платформы и у нас есть 3 уровня сложности:</p>
  <figure id="kBHr" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/893/816/c0e/893816c0e1f02cbcc74fffdc40b167bf.png" width="1089" />
  </figure>
  <p id="igtP">Итак, я на середнячка точно уж тяну. Я ж теперь работаю сеньором в сетях и лидом в проектах. Я справлюсь! Беру супер-неудобную тему и пишу про то как сделать Зельду на питоне. Момент истины и оценки +42 (мы не обогнали игры), но хоть людям интересно. Да же? Или нет?</p>
  <figure id="tQCQ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/281/8db/c3a/2818dbc3aafc314d6d755d47b93d9923.png" width="1200" />
  </figure>
  <p id="jc1o">А посмотрите, сколько прочтений на статье про сети или IP-адреса и сколько тут. Время? Да ну ладно! Оно же не так сильно влияет. Можно всё посчитать. Мы же умеем! Даже если до конца года меня прочитает х2 человек и спрос падать не будет (что уже невозможно), то за 5 лет я наберу только 100к прочтений. Как побить 400к с +1?</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="qXQh">Как вообще оценки связаны с прочтениями? Типа оценки от &quot;экспертов&quot;, а прочтения от &quot;недо-экспертов&quot;? Как это?!</p>
  </section>
  <p id="aePU">Комитет Хабра (тут мне прям хочется назвать их этим словом). Несколько раз переносит выкладывание списка победителей и ночью приходит сообщение. Конечно, меня там нет. Я не расстроился, но хотел узнать, кто победил в номинации «Геймдев на уровне мидл»:</p>
  <figure id="DZrT" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/13b/c5c/331/13bc5c33110da026c1e84133dd4308b3.png" width="1182" />
  </figure>
  <p id="s4QG">Сам автор пишет, что его уровень статьи &quot;простой&quot;, а не &quot;средний&quot;. А знаете какие у него оценки? +258. Чего?!...</p>
  <p id="mzw5">Сейчас важное уточнение. Мне самому понравилась статья. Автор классно рассказал про то, как и что реально работает в геймдеве. Я ни коем образом не хочу обидеть автора. Он заслужил своего признания. Лично меня интересует как идёт подсчёт голосов. Кто эксперты? Как и что они оценивали? Ведь, в пунктах указано, что важна техничность статьи. Ну ладно, может я чего не понимаю? Иду спрашивать:</p>
  <figure id="bCdo" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/043/691/aa6/043691aa6cdf990d78428c21bc375d5e.png" width="1123" />
  </figure>
  <p id="8L6N">Ответ был странным:</p>
  <figure id="bxDp" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/207/5b3/0cb/2075b30cbf2e9b41d6395a68074031f7.png" width="1125" />
  </figure>
  <p id="pfMT">Следующий день:</p>
  <figure id="1m01" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/abb/cb5/bb6/abbcb5bb61c360936ca2bfd9ddbad329.png" width="1020" />
  </figure>
  <p id="BYh5">Выложенная статья про &quot;Золотую клаву&quot;:</p>
  <figure id="AxeC" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/fa0/7ff/299/fa07ff299fba89073c01cb342ab4a295.png" width="1110" />
  </figure>
  <p id="wBLh">Комментов от организаторов не последовало. Почему‑то. Но я стал победителем Технотекста 2023. Рад ли я? Ну честно, вообще ХЗ. С одной стороны, теперь я точно уж айти, а с другой — а почему так? Что я сделал лучше или хуже? Или я просто «наныл на победу»? Я так не хочу.</p>
  <p id="Kf2L">Мне прислали мерч. Футболку, свитшот, значок и грамоту. Мне приятно. Я хожу в мерче, но как вы думаете сколько людей спросили про него и обратили не него внимание? Пара человек отметили, что мерч сделан красиво (понравилось как нарисована картинка, но люди от айти сильно далеки).</p>
  <p id="tM5B">Прошло уже достаточно времени с события, чтобы я мог с холодной головой задать простой вопрос:</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="982r">А как так получилось, что техническая сложность работы вообще не учитывалась? Что же тогда важно?</p>
  </section>
  <h2 id="4XZ7">Книга 3. Карма</h2>
  <p id="sq6S">Ну ладно, все эти конкурсы, победы, проигрыши, баллы и лайки с прочтениями — всё это приходит и уходит, но карма остаётся. У меня максимум был +45. Для Хабра это не много и не мало.</p>
  <p id="KSzk">И вот, наступает момент, когда я подготовил для сообщества компании, где работаю (это самый крупная Ed-Tech платформа) целую историю как я хотел переехать на Go, но забил и стал дальше писать на шарпе и питоне. Я очень переживал, что меня закидают тухлыми помидорами фразами &quot;Ты ничё не понимаешь! Вот то ли дело...&quot;.</p>
  <p id="wZmu">И каково было моё удивление, когда люди со мной просто обсудили простой вопрос &quot;что на чём писать удобнее и лучше&quot;. И там были и мидлы, и сеньоры, и лиды (и я в числе тех же). И все уважительно друг с другом говорили и рассуждали. Преза была на 20 минут, а мы сидели час с лишним.</p>
  <p id="ZRdK">Тут я начинаю задумываться, а почему же так нельзя тут. И вот, наш деврел выкладывает текстовую версию моего рассказа. Ииииииииии:</p>
  <figure id="vaeB" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/aa6/7f8/fe4/aa67f8fe4565dd196a603dfebb66ea64.png" width="1920" />
  </figure>
  <p id="htw1">Конечно, после карма немного упала, но я задумался и что? Ведь есть <strong>это</strong>:</p>
  <figure id="fj6i" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/a43/7f3/80f/a437f380f23e18737bce05f5651444da.png" width="1155" />
  </figure>
  <p id="HCVu">Как-то я встречал чувака с -300 кармой. Я не знаю что он сделал, но походу убил кого-то текстом. А какой ограничение? Никакого! Он просто не может публиковать новые статьи. Ну а если надо — да без проблем смени почту и снова получи инвайд от НЛО или попроси у кого-то с высокой кармой. И всё...</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="fJRR">А зачем тогда вообще карма? Ты можешь получить мерч? Тебя не захейтят? Тебе скажут спасибо за бесплатный вклад? Эммм... Нет. А зачем тогда?</p>
  </section>
  <h2 id="zkKi">Финал</h2>
  <p id="RZXk">Жаль, что не получилась история, где Хабр победил лорда Тролля и сообщество становится только токсичнее. Я искренне не понимаю зачем мне оно надо. Зачем мне писать статьи сюда? Я хотел вести личный блог, чтобы следить за своим прогрессом. Он у меня есть: Кудрявый микрофон в ТГ-шке (кому надо, тот найдёт). А тут прогресс кому нравится какой сериал...</p>
  <p id="Fdyf">Я хотел принять участие в новом технотексте, но опять таки... <strong>Зачем?!</strong> Оно ничего не даёт. Ни признания, ни экспертности, ни интересного времени-препровождения. Как написал какой-то комментатор под статьёй с победителями:</p>
  <figure id="EHJ1" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/db6/ff3/117/db6ff3117017705dc24d08617ac2ba2c.png" width="1090" />
  </figure>
  <p id="JqJn">Меня узнавали как автора Хакера, как международного спикера, а не как чувачка-дурачка с докладом, о том что я не дурачок. Мне искренне стало от это грустно. Не яростно, не холиварно. Теперь, я буду писать книги или статьи, но за вознаграждения, как это в том же Хакере, а что-то для себя, я буду писать у себя в ТГ-шке (там, где <strong>мне</strong> это комфортно). Это я делаю выбирая себя.</p>
  <p id="Z86J">Если вы задаётесь вопросом &quot;А нафига я это читаю?&quot;, отвечу просто: &quot;Подумайте надо ли вам писать на Хабре и трястись над кармой от таких приколов, как на картинке ниже, ещё и за бесплатно...&quot;.</p>
  <figure id="BA9X" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/49d/918/096/49d918096f92d52569775cf46435ef3c.png" width="1920" />
  </figure>
  <p id="CwI5">Увидимся в мире! Всем его и желаю!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/tVu_wVBcNd1</guid><link>https://teletype.in/@valerylinkov/tVu_wVBcNd1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/tVu_wVBcNd1?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>PyZelda своими руками или как геймдевить без Unreal, Unity и кредитов</title><pubDate>Wed, 30 Oct 2024 15:35:13 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/25/ef/25ef09fe-0c77-4494-84e8-07329a8c1890.png"></media:content><category>Игры 🎮</category><description><![CDATA[<img src="https://habrastorage.org/r/w1560/webt/hk/pc/jt/hkpcjtucu8_q8r5waklrrytfd78.jpeg"></img>Хабры и Хаброчки, я хотел бы перед самой статьёй обсудить вопрос целесообразности писать свой движок, вместо готовых решений. Есть куча статей, которые опишут разные движки от более популярных до менее. Я бы хотел затронуть немного другой вопрос: &quot;Как человеку, который изучал программирование много лет заняться геймдевом?&quot;. Обычно, есть два пути в геймдев:]]></description><content:encoded><![CDATA[
  <figure id="p6l7" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/hk/pc/jt/hkpcjtucu8_q8r5waklrrytfd78.jpeg" width="1560" />
  </figure>
  <h3 id="PTuv">Введение</h3>
  <p id="R80M">Хабры и Хаброчки, я хотел бы перед самой статьёй обсудить вопрос целесообразности писать свой движок, вместо готовых решений. Есть куча статей, которые опишут разные движки от более популярных до менее. Я бы хотел затронуть немного другой вопрос: &quot;Как человеку, который изучал программирование много лет заняться геймдевом?&quot;. Обычно, есть два пути в геймдев:</p>
  <ol id="KeBw">
    <li id="2Bds">Умышленный путь. Это когда человек, который играет в игры рано или поздно решит их создать. Тогда, он выбирает где ему учиться этому и выучивает игровые движки и C-образные языки к ним (чаще всего, C#).</li>
    <li id="4naG">Путь прогеров. Программист увлекается математикой и пишет код. Так или иначе, везде где есть код — есть компьютер. Цифровые развлечения (в том числе и игры) не проходят мимо тех людей, который постоянно пишут код. Так, <a href="https://www.stxnext.com/blog/python-for-game-development/" target="_blank">часть прогеров решает написать свою игру</a> и начать свой путь в геймдев. Об этом пути мы и поговорим.</li>
  </ol>
  <p id="p57B">Конечно можно сказать, что если ты хочешь работать — иди учись и получай нужные навыки. Осваивай Unity или Unreal и работай в крутой <a href="https://dtf.ru/gameindustry/1033019-igrovye-studii-i-mesta-ih-obitaniya-v-rossii" target="_blank">геймдев-компании</a>. В этом есть доля правды. Однако, превращать любое своё хобби в работу — дело не благоразумное. Выгорание скажет об этом достаточно понятно. Тогда вам могут предложить сделать либо мод на игру (например, <a href="https://skillbox.ru/media/gamedev/7-igr-na-source-sozdannykh-za-predelami-valve/" target="_blank">на движке Source</a>) или поиграть в <a href="https://dtf.ru/games/51311-interaktivnye-grezy-kak-ustroen-redaktor-dreams-i-chto-tam-mozhno-sozdat" target="_blank">Грёзы</a>, которая тоже очень популярна. Такой вариант вполне подойдёт, но появляется новая проблема: &quot;Выбор варианта работы&quot;.</p>
  <h3 id="E472">Выбор варианта работы</h3>
  <p id="Y8SG">Всего есть три варианта работы над игрой:</p>
  <ol id="zTzs">
    <li id="iISe">Создать игру на известном движке-конструкторе</li>
    <li id="bt1w">Сделать мод на существующий движок</li>
    <li id="0dqO">Создать свой движок и написать игру</li>
  </ol>
  <p id="hnRQ">Каждый из этих вариантов хорош по-своему, но и имеет ряд недоработок. Например, выбрав путь создания игры на популярном движке вы столкнётесь с проблемами самого движка, а главное — с проблемами монетизации проекта. Если выбрать модопуть — вы сразу столкнётесь с тем, что не каждый движок открыт для написания игр, а также, не каждый движок позволяет продавать мод хоть за какую-то цену. Путь написания своего движка вызывает в геймдеве дикий припадок, мол &quot;Да зачем опять идти очень сложно, когда сроки горят, а сам ты ещё не доработал концепцию?&quot;. Данный путь весьма не популярен для общества из-за сложности реализации и проблем с набором хоть какой-то команды, ведь если вы пишете движок, кому-то с ним работать.</p>
  <p id="m2vM">Так зачем выбирать &quot;сложный&quot; путь? Во-первых, не для всех он сложнее. Лично мне сложнее перейти на C# с использованием Unity, чем написать новый проект на Python. Во-вторых, люди не всегда понимают сам движок. Сейчас я преподаю в <a href="https://obe.ru/" target="_blank">институте &quot;Бизнеса и Дизайна&quot;</a>. Это один из первых профильных учреждений, занимающихся геймдевом. И вот у студентов я спросил зачем им движок. Каково было моё удивление, что далеко не все понимаю, вообще зачем он нужен. Спойлер, не из-за пресетов.</p>
  <h3 id="IMQx">Зачем вам движок?!</h3>
  <p id="Z8F8">По сути, движок решает всего лишь три, но очень важных вопроса:</p>
  <ol id="Xq6C">
    <li id="tCP9"><strong>Физика</strong>. Если вы окончили физмат, вы понимаете насколько сложно определить и прописать траекторию падения стеклянного шара весом в 2 килограмма на доску из дуба, которая лежит под углом 32 градуса. Также, нужно не забыть прописать с какой высоты должен упасть шар, чтобы разбиться. Движок прописывает эту физику за вас, а вы лишь обращаетесь к тем или иным объектам.</li>
    <li id="urzu"><strong>Тайлсеты</strong>. Тайл — это маленькие картинки для прорисовки графики (чаще всего, карт). Процесс создания тайлов <a href="https://habr.com/ru/articles/470099/" target="_blank">весьма энергозатратный</a>, а наложение этих тайлов достаточно простое дело. Просто выбрать где лежит камень, а где земля или вода. В движках типа Unreal или Unity вы можете просто выбрать слой карты и нарисовать клеточками из тайтлов карту.</li>
    <li id="VkTW"><strong>Анимация</strong>. Самый спорный пункт. В движках все элементы на карте — это объекты. Каждый объект имеет форму по координатам x, y, z и их можно менять прямо в самом движке путём перемещения, сжатия или растягивания объекта. Но важное уточнение, прорисовывать анимацию по x, y, z — не самая лучшая идея. Куда надёжнее, красивее и вообще правильнее прописывать каждый шаг объекта путём перемещения по пресету персонажа по графике.</li>
  </ol>
  <p id="OwE5">Иными словами, сам игровой движок — это автоматизирующая система, которая позволяет упростить разработку. Однако, при использовании движка теряется часть гибкости в настройках. Моя задача — описать как можно более подробный процесс написания игры по самому сложному пути, хотя Python и упрощает часть вещей. Что ж, хватит слов и давайте к делу!</p>
  <h3 id="XLvB">Подготовка</h3>
  <p id="kQUZ">Для начала, давайте создадим папку проекта. Я назвал проект PyZelda и в папке проекта есть ещё 4 директории: audio, code, graphic и map.</p>
  <figure id="PTeN" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/ex/80/nz/ex80nzsijzxwn-d2kwwbn1_icyc.png" width="1093" />
  </figure>
  <p id="Xh5B">Далее, в папке code создадим три файла:</p>
  <ul id="uRmN">
    <li id="rtcq"><a href="http://main.py/" target="_blank">main.py</a> — основной файл игры</li>
    <li id="WXio"><a href="http://settings.py/" target="_blank">settings.py</a> — настройки игры (тут мы укажем настройки полей и основных данных по окну и прорисовке)</li>
    <li id="7cUJ"><a href="http://debug.py/" target="_blank">debug.py</a> — файл дебагинга</li>
  </ul>
  <p id="Slsd">Перед работой, не забудьте скачать библиотеку PyGame (<code>pip install pygame</code>)</p>
  <figure id="GYcS" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/hm/dt/zi/hmdtzidghxionst8damlsi_flzw.png" width="1350" />
  </figure>
  <p id="HuJi">Файл main:</p>
  <pre id="R7Hj" data-lang="python">import pygame, sys #импортируем библиотеки PyGame и Sys
from settings import * #импорт из файла settings

class Game: #основной класс игры
	def __init__(self): #создаём конструктор класса
		pygame.init() #конструктор использует конструкции из библиотеки PyGame
		self.screen = pygame.display.set_mode((WIDTH,HEIGTH)) #забирает из нашего проекта экран в виде размеров в ширину и высоту
		pygame.display.set_caption(&quot;PyZelda&quot;) #Устанавливаем название нашего окна
		self.clock = pygame.time.Clock() #а также, забирает из проекта время

	def run(self): #функция запуска игры
		while True: #до выхода из игры она активна
			for event in pygame.event.get(): #просмотр событий в игре
				if event.type == pygame.QUIT: #сейчас мы можем только выйти и при выходе:
					pygame.quit() #вызываем метод закрытия игры
					sys.exit() #и закрываем окно системы
			self.screen.fill(&#x27;green&#x27;) #помимо событий, указываем цвет экрана
			pygame.display.update() #обновляем экран
			self.clock.tick(FPS) #запрашиваем FPS

if __name__ == &#x27;__main__&#x27;: #запуск игры только из main-файла
	game = Game() #Если файл main, то сама игра вызывает класс...
	game.run() #...и запускает функцию run из класса</pre>
  <p id="BMgz">В файле main мы запускаем саму игру. Создаём конструктор на базе PyGame и работаем с входными файлами и данными.</p>
  <p id="bY8G">Файл <a href="http://setting.py/" target="_blank">setting.py</a>:</p>
  <pre id="FbRr" data-lang="python">WIDTH = 1280 #Ширина экрана
HEIGTH = 720 #Высота экрана
FPS = 60 #Число FPS
TILESIZE = 64 #Размер тайла (квадрата текстуры)

WORLD_MAP = [ #Карта мира игры. Она состоит из 20х20 квадратов
[&#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;,&#x27;, &#x27;x&#x27;],
[&#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;, &#x27;x&#x27;],
]</pre>
  <p id="ZeKD">Далее, файл <a href="http://debug.py/" target="_blank">debug.py</a>:</p>
  <pre id="WYC8" data-lang="python">import pygame #Снова обращаемся к PyGame
pygame.init() #Используем базовый конструктор
font = pygame.font.Font(None, 30) #Указываем шрифт

def debug(info, y = 10, x = 10):  #Сама функция дебага
	display_surface = pygame.display.get_surface() #Получаем ссылку на текущую установленную поверхность отображения в игре
	debug_surf = font.render(str(info), True, &quot;Red&quot;) #Рендерим текст (я сделал его красным)
	debug_rect = debug_surf.get_rect(topleft = (x, y)) #Указывамем место отображения инфы на экране (левый верхний угол)
	pygame.draw.rect(display_surface, &quot;White&quot;, debug_rect) #Делаем микро-консоль в виде прямоугольника (и да он белый, будет белая консоль с красным текстом)
	display_surface.blit(debug_surf, debug_rect) #Собираем нашу микро-консоль с параметрами текста</pre>
  <p id="IJ68">В данном файле мы создадим дебаг игры. Это поле, которое мы выводим вверху слева экрана и в нём показываем нужный нам текст. Для запуска дебага, нужно импортировать debug в main-файл и вывести что-то после отрисовки окна. Примерно так (файл <a href="http://main.py/" target="_blank">main.py</a>):</p>
  <pre id="E3aM" data-lang="python">import pygame, sys #импортируем библиотеки PyGame и Sys
from settings import * #импорт из файла settings
from debug import debug #импортируем дебаг &lt;------------------

class Game: #основной класс игры
	def __init__(self): #создаём конструктор класса
		pygame.init() #конструктор использует конструкции из библиотеки PyGame
		self.screen = pygame.display.set_mode((WIDTH,HEIGTH)) #забирает из нашего проекта экран в виде размеров в ширину и высоту
		pygame.display.set_caption(&quot;PyZelda&quot;) #Устанавливаем название нашего окна
		self.clock = pygame.time.Clock() #а также, забирает из проекта время

	def run(self): #функция запуска игры
		while True: #до выхода из игры она активна
			for event in pygame.event.get(): #просмотр событий в игре
				if event.type == pygame.QUIT: #сейчас мы можем только выйти и при выходе:
					pygame.quit() #вызываем метод закрытия игры
					sys.exit() #и закрываем окно системы
			self.screen.fill(&#x27;green&#x27;) #помимо событий, указываем цвет экрана
			debug(&#x27;Чё как? Я дебаг!&#x27;) #Дебажим &lt;------------------
			pygame.display.update() #обновляем экран
			self.clock.tick(FPS) #запрашиваем FPS

if __name__ == &#x27;__main__&#x27;: #запуск игры только из main-файла
	game = Game() #Если файл main, то сама игра вызывает класс...
	game.run() #...и запускает функцию run из класса</pre>
  <p id="oPbO">Получим феерическую игру цветов:</p>
  <figure id="siGZ" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/_b/t0/i5/_bt0i5v_zg2q9mwccux-ch_xfd4.png" width="1084" />
  </figure>
  <p id="swK2"><a href="https://disk.yandex.ru/d/8jdGZBe3w3plAg" target="_blank">Стартовый набор файлов для скачивания</a>.</p>
  <h3 id="WU3P">Пишем уровень</h3>
  <p id="B4RA">Итак, для начала давайте разберёмся в понятии &quot;класс&quot; в концепции ООП (объектно-ориентированного программирования). Сейчас мы создадим класс <code>Level</code>. В этом классе есть всё необходимое для работы с объектами внутри. По сути, класс <code>Level</code> и есть наша игра, так как именно этот класс собирает все <strong>спрайты</strong> (игрок, враги, карта мира и т.д.). Помимо самих спрайтов, нас интересует набор элементов связанных с подсчётом тех или иных пунктов. Как я говорил ранее, движок нужен для прописывания физики, а физика — это математический способ описать поведение объекта. Таким образом, мы взаимодействуем с <strong>числами</strong> и <strong>параметрами</strong>. Это тоже находится в классе <code>Level</code>. Например, если игрока ударит враг, то игрок потеряет 5% здоровья — это и есть наши параметры.</p>
  <p id="dayO">Но есть одна проблема. Объектов очень много. Чтобы не рыскать в коде в поисках конкретного камня №67, код будем разбивать группами объектов. Сейчас мы создадим две группы: <code>visible_sprites</code> и <code>obstacle_sprites</code>. Как вы уже поняли, группа <code>visible_sprites</code> отвечает за все объекты, которые пользователь видит (например, карту мира и персонажа), а <code>obstacle_sprites</code> — это объекты, которые нужны для технического использования. Все объекты можно сослать на конкретные группы или на набор групп. Так, объект &quot;кот&quot; может быть в группе объектов движущихся, но не взаимодействующих с игроком. Если же добавить кота в обе группы, он будет отображён и активен.</p>
  <p id="eklM">Приступим к коду. Создадим новый файл <code>level.py</code>. Пропишем в нём следующий код:</p>
  <pre id="DoFm" data-lang="python">import pygame

class Level: #Создали класс
	def __init__(self): #Базовые параметры
		self.visible_sprites = pygame.sprite.Group() #Создали группу видимых элементов
		self.obstacle_sprites = pygame.sprite.Group() #Создали группу технических элементов

	def run(self): #Создали метод в классе
		pass</pre>
  <p id="dRys">Мы просто создали класс и в нём 2 группы, а затем в классе создали метод вызова данного класса. Далее, нужно вернуться в main-файл и импортировать класс <code>Level</code> (<code>from level import Level</code>), объявить класс <code>Level</code> (<code>self.level = Level()</code>), а таже запустить его в самом run-методе в main (<code>self.level.run()</code>). Я решил пока убрать дебаг из проекта, так как сейчас дебажить нечего и финальный код в main-файле выглядит так:</p>
  <pre id="BLuv" data-lang="python">import pygame, sys #импортируем библиотеки PyGame и Sys
from settings import * #импорт из файла settings
from level import Level #+++ импорт из файла level класс Level +++

class Game: #основной класс игры
	def __init__(self): #создаём конструктор класса
		pygame.init() #конструктор использует конструкции из библиотеки PyGame
		self.screen = pygame.display.set_mode((WIDTH,HEIGTH)) #забирает из нашего проекта экран в виде размеров в ширину и высоту
		pygame.display.set_caption(&quot;PyZelda&quot;) #Устанавливаем название нашего окна
		self.clock = pygame.time.Clock() #а также, забирает из проекта время
		self.level = Level() #+++ объёвили Level +++

	def run(self): #функция запуска игры
		while True: #до выхода из игры она активна
			for event in pygame.event.get(): #просмотр событий в игре
				if event.type == pygame.QUIT: #сейчас мы можем только выйти и при выходе:
					pygame.quit() #вызываем метод закрытия игры
					sys.exit() #и закрываем окно системы
			self.screen.fill(&#x27;green&#x27;) #помимо событий, указываем цвет экрана
			self.level.run() #+++ запустили функцию run в файле level в классе Level +++
			pygame.display.update() #обновляем экран
			self.clock.tick(FPS) #запрашиваем FPS

if __name__ == &#x27;__main__&#x27;: #запуск игры только из main-файла
	game = Game() #Если файл main, то сама игра вызывает класс...
	game.run() #...и запускает функцию run из класса
</pre>
  <p id="1wLm">Давайте далее, пропишем что-то в классе Level. Таким образом, мы создадим подложку из зелёного фона, а сверху наложим новые объекты. Для этого, мы воспользуемся простым методом, как в и в дебаге: <code>display_surface = pygame.display.get_surface()</code>. В коде с Level оно выглядит так:</p>
  <pre id="eTzS" data-lang="python">import pygame

class Level: #создали класс
	def __init__(self): #базовые параметры
		self.display_surface = pygame.display.get_surface() #создали новый слой объектов
		self.visible_sprites = pygame.sprite.Group() #создали группу видимых элементов
		self.obstacle_sprites = pygame.sprite.Group() #создали группу технических элементов

	def run(self): #создали метод в классе
		pass</pre>
  <p id="F7Ea">Сейчас ничего не поменяется, так как мы объявили что будем что-то рисовать, но ничего не нарисовали. Давайте приступим к процессу отрисовки. Для этого создадим новый файл <code>tile.py</code>.</p>
  <pre id="57Wq" data-lang="python">import pygame
from settings import *

class Tile(pygame.sprite.Sprite):
	def __init__(self, pos, groups):
		super().__init__(groups) #наследуем все группы
		self.image = pygame.image.load(&#x27;../graphic/box.png&#x27;).convert_alpha() #указываем адрес картинки
		self.rect = self.image.get_rect(topleft = pos) #указываем позицию отрисовки (левый верхний угол)</pre>
  <p id="3yS6">Интересного в этом коде мало. Мы просто импортируем сам pygame (снова и снова), из файла <code>settings.py</code> мы берём всю информацию по разметке поля (потому, мы его и оставляем тут). Далее, мы создаём новый класс <code>Tile</code>. В нём создаём параметры себя, позицию и группу наследования. Далее, командой <code>super()</code> мы включаем <a href="https://docs-python.ru/tutorial/vstroennye-funktsii-interpretatora-python/funktsija-super/" target="_blank">наследование</a>. Далее, указываем картинки самих предметов и <a href="https://younglinux.info/pygame/rect" target="_blank"><code>rect</code></a> данных картинок. Из интересного, <code>convert_alpha()</code>. Эта функция пайгейма создает новую копию поверхности с желаемым форматом пикселей. Суровая необходимость, чтобы пайгейм понял что мы делаем.</p>
  <p id="MU30">Ровно такой же код создадим в файле <code>player.py</code>:</p>
  <pre id="iJ6U" data-lang="python">import pygame
from settings import *

class Player(pygame.sprite.Sprite):
	def __init__(self, pos, groups):
		super().__init__(groups)
		self.image = pygame.image.load(&#x27;../graphic/link.png&#x27;).convert_alpha()
		self.rect = self.image.get_rect(topleft = pos)</pre>
  <p id="a9Zz">Отличие данного кода лишь в двух местах:</p>
  <ul id="MEJH">
    <li id="eO6z">Я создал класс <code>Player</code> вместо Tile</li>
    <li id="JehW">Заменили картинку с коробок на героя Хайрула :)</li>
  </ul>
  <p id="bZHV">Все пресеты картинок я взял из проекта <a href="https://pixel-boy.itch.io/ninja-adventure-asset-pack" target="_blank">NinjaAdventure</a>. Там есть способ скачать бесплатные сеты графики. Обрезал картики в фотошопе и получил мини-изображения.</p>
  <p id="YTRe">Теперь, давайте отобразим нашу мировую карту. Делать мы это будем в файле <code>level.py</code>, так как именно в нём мы храним всю нужную инфу про конкретный уровень. Сразу импортируем <code>settings.py</code> и обратимся к карте. Финал работы будет выглядеть так:</p>
  <pre id="Akdy" data-lang="python">import pygame
from settings import *

class Level: #создали класс
	def __init__(self): #базовые параметры
		self.display_surface = pygame.display.get_surface() #создали новый слой объектов
		self.visible_sprites = pygame.sprite.Group() #создали группу видимых элементов
		self.obstacle_sprites = pygame.sprite.Group() #создали группу технических элементов
		self.create_map()

	def create_map(self):
		for row in WORLD_MAP:
			print(row)

	def run(self): #создали метод в классе
		pass</pre>
  <p id="GVKt">После запуска main-файла, сама игра никак не поменялась, но мы в терминале отпечатали нашу карту.</p>
  <figure id="AtSM" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/w2/us/rl/w2usrlpqmue5az6n-t4q5dfqkmq.png" width="1494" />
  </figure>
  <p id="KrUN">Про карту. Для упрощения работы, я создал клетку (напомню, что она размером 64 на 64 пикселя) и указываю символами что куда ставить. Поставил карту я так: &#x27;x&#x27; — это коробки, &#x27;,&#x27; — пустое место, а &#x27;p&#x27; — это наш герой.</p>
  <p id="o0dG">Это, конечно, круто, но вот я хотел бы нарисовать карту в игре, а не в терминале. Для этого, модернизируем код. Работаем только с файлом <code>level.py</code>:</p>
  <pre id="Li10" data-lang="python">import pygame
from settings import *
from tile import Tile
from player import Player

class Level: #создали класс
	def __init__(self): #базовые параметры
		self.display_surface = pygame.display.get_surface() #создали новый слой объектов
		self.visible_sprites = pygame.sprite.Group() #создали группу видимых элементов
		self.obstacle_sprites = pygame.sprite.Group() #создали группу технических элементов
		self.create_map()

	def create_map(self):
		for row_index, row in enumerate(WORLD_MAP):
			for col_index, col in enumerate(row):
				x = col_index * TILESIZE
				y = row_index * TILESIZE
				if col == &#x27;x&#x27;:
					Tile((x, y), [self.visible_sprites])
				if col == &#x27;p&#x27;:
					Player((x, y), [self.visible_sprites])

	def run(self): #создали метод в классе
		self.visible_sprites.draw(self.display_surface)</pre>
  <p id="LWmu">Всё что я делаю — это прохожу массив данных и умножаю элемент на 64, так как размер моего тайла равен 64 пикселям. Далее, если элемент равен <code>&#x27;x&#x27;</code> заменяю его на коробку, а если <code>&#x27;p&#x27;</code>, то на героя. Далее, я прописал в методе запуска метод отрисовки поля. Также, на карте я заменил одну <code>&#x27;,&#x27;</code> на <code>&#x27;p&#x27;</code>. И результат:</p>
  <figure id="5KU0" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/yw/gu/s6/ywgus6g0r_afexbaexxmfjgvp3c.png" width="1560" />
  </figure>
  <p id="Di3R">В main-файле заменив цвет фона на чёрный, а размер тайла на 32 пикселя, я получил это:</p>
  <figure id="0mGp" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/aa/9f/wn/aa9fwnnikbo0j4titebgguazpuu.png" width="1560" />
  </figure>
  <p id="nCow"><a href="https://disk.yandex.ru/d/ZYjndkgFeRALkA" target="_blank">Файлы данного этапа для скачивания</a>. Сразу оговорюсь, что отображение не совсем корректное из-за самих картинок. Я не подбивал их к размеру 64 на 64 пикселя. Далее я исправил это и вернул размер тайла в 64 на 64 пикселя.</p>
  <h3 id="Nalu">Создаём игрока</h3>
  <p id="14nw">Сам игрок должен мочь передвигаться и сталкиваться с существующими объектами. Для начала, запишем его движения. Переходим в <code>player.py</code> и прописываем функцию перемещения. Код в <code>player.py</code>:</p>
  <pre id="XbTo" data-lang="python">import pygame
from settings import *

class Player(pygame.sprite.Sprite):
	def __init__(self, pos, groups):
		super().__init__(groups)
		self.image = pygame.image.load(&#x27;../graphic/link.png&#x27;).convert_alpha()
		self.rect = self.image.get_rect(topleft = pos)

		self.direction = pygame.math.Vector2() #обращаемся к направлению через вектор

	def input(self): #варьируем кнопки
		keys = pygame.key.get_pressed()

		if keys[pygame.K_UP]:
			self.direction.y = -1
		elif keys[pygame.K_DOWN]:
			self.direction.y = 1
		else:
			self.direction.y = 0

		if keys[pygame.K_LEFT]:
			self.direction.x = -1
		elif keys[pygame.K_RIGHT]:
			self.direction.x = 1
		else:
			self.direction.x = 0

	def update(self):
		self.input()</pre>
  <p id="Gb97">Тут с кодом достаточно просто. В функции <code>self.direction = pygame.math.Vector2()</code> мы задаём вектор точке. Точка — это наш герой, а его вектор болтается в диапазоне от -1 до 1. Функция <code>keys = pygame.key.get_pressed()</code> позволяет продолжать нажатие и тогда, герой должен разгоняться. Если нажатия нет — вектор равен 0 и герой тормозит. Это очень условное, но приписывание инерции.</p>
  <p id="Atjk">Ещё в файле <code>level.py</code> в функции <code>run</code> я записал обновление всех спрайтов. Это строчка кода вида:</p>
  <pre id="8uif" data-lang="python">self.visible_sprites.update()</pre>
  <p id="4gUc">Ещё, я переписал в том же файле вызов героя. Мне это нужно для глобализации позиции героя. Из строки</p>
  <pre id="qo2R" data-lang="python">Player((x, y), [self.visible_sprites])</pre>
  <p id="Ag28">Я сделал</p>
  <pre id="lwo1" data-lang="python">self.player = Player((x, y), [self.visible_sprites])</pre>
  <p id="Umwg">Продолжим прорисовку движений в файле <code>player.py</code>. Создадим ещё один параметр — скорость. Для этого в глобальные параметры (<code>__init__</code>) добавим строчку <code>self.speed = 5</code></p>
  <p id="RIoD">Также напишем функцию <code>move</code>:</p>
  <pre id="67uY" data-lang="python">def move(self, speed):
		self.rect.center += self.direction * speed</pre>
  <p id="6DSR">И в update-функции пропишем движения персонажа: <code>self.move(self.speed)</code>.</p>
  <p id="iv6B">Результат:</p>
  <figure id="ni2v" class="m_original">
    <img src="https://habrastorage.org/webt/9r/f5/kr/9rf5krne9ukw8zz-8mrbc2k1eho.gif" width="600" />
  </figure>
  <p id="mSRK">Если приглядеться, то по диагонали, Линк бежит чуть быстрее. Дело в том, что он бежит по диагонали со скоростью корень из двух, что примерно равно 1.4. Мы прописали скорость вверх, вниз, влево и вправо равной 1, а вот по диагонали из правил математики, можно понять, что длина гипотенузы равна сумме квадратов длин оснований квадрата под корнем, то есть <strong>корень из (1^2 + 1^2)</strong>. Исправим данный баг нормализацией от PyGame (да-да, как в Unity). Исправленная функция движения:</p>
  <pre id="PtzN" data-lang="python">def move(self, speed):
	if self.direction.magnitude() != 0:
	    self.direction = self.direction.normalize()
	self.rect.center += self.direction * speed</pre>
  <p id="kDIB">Теперь вторая проблема. Линк — танк. Он сбивает всё на своём пути. Нам нужны объекты и прописать столкновения с ними. Не забывайте, что все объекты у нас — квадраты тайлами.</p>
  <p id="F1ZM">Сейчас у нас есть проблема — файл <code>player.py</code> не знает о наличии тайлов, которые отображаются через файл уровня. Поэтому, дадим нашему файлу новый аргумент. Добавим его в <code>init</code> и назовём <code>obstacle_sprites</code>. Также, не забудьте в файле самого уровня сослаться на <code>obstacle_sprites</code> в отрисовке точки игрока. Для этого в файле <code>level.py</code> замените строку:</p>
  <pre id="2YWt" data-lang="python">self.player = Player((x, y), [self.visible_sprites])</pre>
  <p id="Clco">На строку:</p>
  <pre id="JUCx" data-lang="python">self.player = Player((x, y), [self.visible_sprites], self.obstacle_sprites)</pre>
  <p id="tIhi">В самом файле игрока, создадим метод столкновений под название <code>collision</code>. Сама функция:</p>
  <pre id="ODwp" data-lang="python">def collision(self, direction):
	if direction == &#x27;horizontal&#x27;:
		for sprite in self.obstacle_sprites:
			if sprite.rect.colliderect(self.rect):
				if self.direction.x &gt; 0: #двигаем вправо
					self.rect.right = sprite.rect.left
				if self.direction.x &lt; 0: #двигаем влево
					self.rect.left = sprite.rect.right

	if direction == &#x27;vertical&#x27;:
		for sprite in self.obstacle_sprites:
			if sprite.rect.colliderect(self.rect):
				if self.direction.y &gt; 0: #двигаем вниз
					self.rect.bottom = sprite.rect.top
				if self.direction.y &lt; 0: #двигаем вверх
					self.rect.top = sprite.rect.bottom</pre>
  <p id="puPk">В ней всё разделено на две координаты. По горизонтальной оси — x, по вертикальной — y. Если столкновение произошло по горизонтали, то делаем смещения (вправо или влево). Тоже самое по вертикали, но там вниз и вверх. Последний шаг — разделить метод в движении на два варианта: вертикальный и горизонтальный. То есть, из строки:</p>
  <pre id="nLEO" data-lang="python">self.rect.center += self.direction * speed</pre>
  <p id="n4GT">Делаем структуру:</p>
  <pre id="KsoR" data-lang="python">self.rect.x += self.direction.x * speed
self.collision(&#x27;horizontal&#x27;)
self.rect.y += self.direction.y * speed
self.collision(&#x27;vertical&#x27;)</pre>
  <p id="dozo">Получаем героя Хайрула без наклонностей в приведение:</p>
  <figure id="1D1E" class="m_original">
    <img src="https://habrastorage.org/webt/cu/zc/0x/cuzc0x6xo2sy39hccbimhczo4pm.gif" width="600" />
  </figure>
  <p id="XqFF">Из предыдущей гифки видна следующая задача — создать камеру. Этим и займёмся. <a href="https://disk.yandex.ru/d/mpG1VH3zri3ioA" target="_blank">Ссылка на этот этап</a>.</p>
  <h3 id="Mzdc">Создание камеры</h3>
  <p id="M5K2">Создать камеру я предлагаю с учётом вектора направления движения персонажа. Мы будем двигать камеру вместе с персонажем. Переходим к файлу уровня и создаём новый класс.</p>
  <pre id="Ec9v" data-lang="python">class YSortCameraGroup(pygame.sprite.Group):
	def __init__(self):
		super().__init__()</pre>
  <p id="pT77">По сути, всё что я сделал сейчас — создал новый класс пустой и с наследованием всего и вся. Далее, применяем его вместо <code>pygame.sprite.Group()</code> в <code>visible_sprites</code>, дабы не тавтологироваться, а ссылаться на класс с более тонкими настройками. Теперь к тонкостям:</p>
  <pre id="JZez" data-lang="python">class YSortCameraGroup(pygame.sprite.Group):
	def __init__(self):
		super().__init__()
		self.display_surface = pygame.display.get_surface()

	def custom_draw(self):
		for sprite in self.sprites():
			self.display_surface.blit(sprite.image, sprite.rect) #прорисуем новую поверхность и отрисуем её</pre>
  <p id="e8fl">Тут я добавил тех же отображений новых поверхностей в главного демона с наследованием и создал метод ручной отрисовки (<code>custom_draw</code>). Там самый интересный пункт в <code>display_surface.blit</code>. Сам Surface создаёт новый слой объектов, а blit отрисовывет их. Далее мы передаём сами картинки и фигуры. Скоро и это перепишем, так как нам нужны векторы. Этим и займёмся. Сам вектор знаком вам по ходьбе Линка. Далее, снова улучшим класс:</p>
  <pre id="ujzx" data-lang="python">class YSortCameraGroup(pygame.sprite.Group):
	def __init__(self):
		super().__init__()
		self.display_surface = pygame.display.get_surface()
		self.offset = pygame.math.Vector2()

	def custom_draw(self):
		for sprite in self.sprites():
			offset_pos = sprite.rect.topleft + self.offset #определяем позицию путём сравнения верхнего левого угла с вектором направления
			self.display_surface.blit(sprite.image, offset_pos) #прорисуем новую поверхность и отрисуем её</pre>
  <p id="RukG">Тут из нового только одна конструкция в самом методе. Она направлена на определение верхнего левого угла, отрисовку и последующую сумму с вектором направления. Далее, в run-методе, не забудьте поменять отрисовку с базовой на нашу кастомную. Примерно так:</p>
  <pre id="9v38" data-lang="python">self.visible_sprites.custom_draw()</pre>
  <p id="VIcU">Если вы сделали всё верно, вставив в вектор 2 значения (x и y), вы увидите перемещение карты. Я поставил -150 и -150 и получил это:</p>
  <figure id="F8U1" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/ax/va/h8/axvah8xksnzlgt3mdg7c8x5c32q.png" width="1560" />
  </figure>
  <p id="waMk">Собственно, осталось перемещаться зацепившись за героя. Его мы оставим по центру экрана (да здравствует эпохе Dendy). Наш код по доработке:</p>
  <pre id="b3cV" data-lang="python">class YSortCameraGroup(pygame.sprite.Group):
	def __init__(self):
		super().__init__()
		self.display_surface = pygame.display.get_surface()
		self.half_width = self.display_surface.get_size()[0] // 2 #середина отрисованного экрана по ширине
		self.half_heigth = self.display_surface.get_size()[1] // 2 #середина отрисованного экрана по высоте
		self.offset = pygame.math.Vector2()

	def custom_draw(self, player):
		self.offset.x = player.rect.centerx - self.half_width #координата x Линка
		self.offset.y = player.rect.centery - self.half_heigth #координата y Линка
		for sprite in self.sprites():
			offset_pos = sprite.rect.topleft - self.offset #определяем позицию путём сравнения верхнего левого угла с вектором направления
			self.display_surface.blit(sprite.image, offset_pos) #прорисуем новую поверхность и отрисуем её</pre>
  <p id="SmgW">В базовых демонов мы добавили размеры экрана и центр экрана (нацело делим пополам). В нашу кастомную рисовалку передадим координаты игрока и по x, y офсетам высчитаем их. Чтобы избавиться от &quot;пьяной камеры&quot;, я вычитаю вектор направления, а не прибавляю его. Не забудьте run-методе передать <code>self.player</code>. Результат:</p>
  <figure id="i0OE" class="m_original">
    <img src="https://habrastorage.org/webt/1o/vl/fv/1ovlfv9bsetj4happytfcnep80o.gif" width="600" />
  </figure>
  <p id="odDT">Теперь нужно разобраться с хитбоксами. Сейчас, у нас графика из Денди, где каждый объект стоит по конкретным клеткам (тайлам). Нужно это исправить. Для начала, перейдем к настройкам тайла и допишем один демон-элемент:</p>
  <pre id="aIm8" data-lang="python">self.hitbox = self.rect.inflate(0, -10)</pre>
  <p id="wSCj">Таким образом, мы уменьшили хитбокс на 10 пикселей. Так как отрисовка идёт из центра — мы уменьшаем хитбокс сверху и снизу на 5 пикселей. В демонах игрока пропишем тот же код, но уменьшим хитбокс на 26 пикселей. Далее, наша задача двигаться и проверять коллизии через хитбоксы. Для этого объекты с <code>rect.x</code> заменим на <code>hitbox.x</code>. Тогда move-функция выглядит так:</p>
  <pre id="uTz7" data-lang="python">def move(self, speed):
	if self.direction.magnitude() != 0:
		self.direction = self.direction.normalize()
	self.hitbox.x += self.direction.x * speed
	self.collision(&#x27;horizontal&#x27;)
	self.hitbox.y += self.direction.y * speed
	self.collision(&#x27;vertical&#x27;)
	self.rect.center = self.hitbox.center</pre>
  <p id="cNxV">Также, починим коллизии:</p>
  <pre id="mhb5" data-lang="python">def collision(self, direction):
	if direction == &#x27;horizontal&#x27;:
		for sprite in self.obstacle_sprites:
			if sprite.hitbox.colliderect(self.hitbox):
				if self.direction.x &gt; 0: #двигаем вправо
					self.hitbox.right = sprite.hitbox.left
				if self.direction.x &lt; 0: #двигаем влево
					self.hitbox.left = sprite.hitbox.right

	if direction == &#x27;vertical&#x27;:
		for sprite in self.obstacle_sprites:
			if sprite.hitbox.colliderect(self.hitbox):
				if self.direction.y &gt; 0: #двигаем вниз
					self.hitbox.bottom = sprite.hitbox.top
				if self.direction.y &lt; 0: #двигаем вверх
					self.hitbox.top = sprite.hitbox.bottom</pre>
  <p id="IQQj">Результат:</p>
  <figure id="sPmS" class="m_original">
    <img src="https://habrastorage.org/webt/a8/og/um/a8ogumbvu9eyuwtraeiu6gegrjq.gif" width="600" />
  </figure>
  <p id="aMP2">Линку отрывает шапку. Это происходит из-за того, что изображения рандомно находятся на поверхности. Какие-то выше, какие-то ниже. Нужно это исправить. Исправим это через класс YSort (не просто же так мы мы назвали класс YSortCameraGroup). Поправим только одну строку:</p>
  <pre id="Y5AD" data-lang="python">for sprite in self.sprites():</pre>
  <p id="ajSH">На строку:</p>
  <pre id="ry9h" data-lang="python">for sprite in sorted(self.sprites(), key = lambda sprite: sprite.rect.centery):</pre>
  <p id="CHUU">По сути, мы просто сделали сортировку по y-координате. Про лямбду можно отдельно <a href="https://habr.com/ru/companies/piter/articles/674234/" target="_blank">почитать</a>, но если сказать грубо — лямбда-функция — функция, которая работает в с анонимными функциями.</p>
  <p id="fQIa">Итог:</p>
  <figure id="bgTV" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/ns/ll/7j/nsll7jsj49uhu6edhvwepn_lau0.png" width="1187" />
  </figure>
  <p id="NBEz"><a href="https://disk.yandex.ru/d/yQ82HKzPyOlTMw" target="_blank">Ссылка на этап проекта</a>.</p>
  <h3 id="12uA">Графика</h3>
  <p id="Vxh5">Тут мне пришлось освоить для себя новую прогу. Она была очень дружелюбной и со второго раза, я смог нарисовать поле игры. Программа называется <a href="https://www.mapeditor.org/" target="_blank">Tiled</a>. В ней можно с лёгкости настраивать карты. Сразу оговорюсь, что это мой первый опыт работы с картами. Это сыграло со мной злую шутку. Дважды.</p>
  <p id="MBrj">Чуть ранее я писал про проблемы с ассетами. Дело в том, что я выбрал размер тайла 64 пикселя. Это стандартное разрешение для игр в ряд, но я не учёл один момент — все ассеты, которые были у Ninja Adventure были в разрешении 16 на 16 пикселей. Это нормально для пиксельной графики. В общем, была задача поправить это расхождение. Поправка была простой — я увеличил размер нужных мне тайлов в 4 раза в фотошопе. В итоге, получилось из этого:</p>
  <figure id="DLya" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/n7/dx/g0/n7dxg0sqovm7qjtxmwfcmllmslw.png" width="1560" />
  </figure>
  <p id="90Yv">Сделать это:</p>
  <figure id="QqFY" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/yn/ed/x_/ynedx_aereay58ujsm6-qi2f2pm.png" width="1560" />
  </figure>
  <p id="RAUM">Для отрисовки самой карты, я взял 3 файла (TilesetFloor.png, TilesetFloorDetails.png и TilesetWater.png):</p>
  <figure id="NnE5" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/uv/j_/ry/uvj_rylxktzbe0rfsbuzrgyvzq0.png" width="1381" />
  </figure>
  <blockquote id="WpwF"><strong>Что-то типа ворнинга</strong>. Тут будьте осторожны. Мне пришлось перерисовать карту и сделать из разных картинок с тайлами одну. Не повторяйте моих ошибок и сначала прочитайте что происходит ниже в разделе &quot;Монстры&quot;.</blockquote>
  <p id="nBwr">Помимо прочего, я создал зелёный квадрат 64 на 64 и красный такой же с прозрачностью в 20%, чтобы поставить точку спауна Линка и невидимые стены для него. Приступим к отрисовки карты.</p>
  <p id="J5sH">Открываем Tiled и я выставил следующие настройки. Ортогональная карта лежит в координатах x и y, что нам и подходит. Слой будет выводиться в формате CSV и отрисовываться справа снизу. Размеры карты будут 80 на 60 тайлов, а это значит 80 на 64 = 5120 и 60 на 64 = 3840 пикселей.</p>
  <figure id="hd02" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/5z/kr/dh/5zkrdhqj5afln9a-ct1y-agpems.png" width="594" />
  </figure>
  <p id="lC2D">Создав карту, получим своё рабочее поле и приступим к рисованию:</p>
  <figure id="a2QH" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/rx/ii/s2/rxiis2ufyukuxp3biikv5t80qzi.png" width="1560" />
  </figure>
  <p id="VPg2">Час работы и результат:</p>
  <figure id="HMuN" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/pa/cx/qd/pacxqd-6ulljrztjabn2lqzwcde.png" width="1560" />
  </figure>
  <p id="J3dI">Сейчас работа очень грубая. Нужно добавить деталей. Займёмся этим. Вот что получилось спустя минут 20:</p>
  <figure id="bg7S" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/qz/l1/ws/qzl1ws40mjt3x8cnwfrv_y5jxyq.png" width="1560" />
  </figure>
  <p id="zeB8">Далее, я добавил тайлы-блоки, чтобы за них Линк не выбрался (куда ж без невидимых стен). Главное — все поля должны быть замкнуты, чтобы Линк внезапно не залетал. У меня получилось как-то так:</p>
  <figure id="aHu4" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/2c/60/gg/2c60ggttvct771gj8hn1r_fs0js.png" width="1560" />
  </figure>
  <p id="3YF6">Потом я выключил данный слой, чтобы он не отвлекал. Далее, проставим места спауна врагов (бебов) и ГГ (Линка):</p>
  <figure id="vqNx" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/w_/kp/vm/w_kpvmg-n4zcalfx9zmkzdhjgru.png" width="1560" />
  </figure>
  <p id="88xT">Добавим пару объектов:</p>
  <figure id="lShJ" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/hv/sd/gg/hvsdgggeq6l11hoibdj9fgkn5d0.png" width="1560" />
  </figure>
  <p id="wMsC">Конечно, карта может быть детальнее проработана, ну да это не моя задача. Моя задача — проверить как там игродев на змейке.</p>
  <p id="7rkG">Всю графику я перенёс в папку graphic, а также выгрузил карту в <code>.csv</code>-формате в папку map.</p>
  <p id="v53C">Приступим к коду. Для начала, я скинул в папку Test нашего Линка и коробку и поправил пути в проекте в файлах <code>player.py</code> и <code>title.py</code>. После запуска ничего не поменялось. Далее, я решил положить подложкой на чёрный экран нашу карту. Я просто экспортировал картинку без спауна и дополнительных объектов и установил её выше чёрного экрана, но ниже Линка с коробками. Для этого в файле <code>level.py</code> я для начала объявил о наличии таких файлов двумя строками кода в демонах класса <code>YSortCameraGroup</code>:</p>
  <pre id="2gYH" data-lang="python">self.floor_surf = pygame.image.load(&#x27;../graphic/map+det.png&#x27;).convert() #добавили задник карты
self.floor_rect = self.floor_surf.get_rect(topleft = (0, 0)) #отрисовка карты с левого верхнего угла</pre>
  <p id="StW6">Далее в методе <code>custom_draw</code> вычисляем отрисовку с офсетами для камерами (всё ровно также, как и ранее):</p>
  <pre id="el3u" data-lang="python">floor_offset_pos = self.floor_rect.topleft - self.offset
self.display_surface.blit(self.floor_surf, floor_offset_pos)</pre>
  <p id="Kbnn">Результат:</p>
  <figure id="lU04" class="m_original">
    <img src="https://habrastorage.org/webt/p-/nv/wp/p-nvwpzivcfjtrzrmac6uexh46k.gif" width="600" />
  </figure>
  <p id="UWnR">Происходит наслоение старой карты и новой. Исправим этою Удалим всё в методе <code>create_map</code> в <code>level.py</code>. Немного переписав метод, я привёл его к следующему виду:</p>
  <pre id="cgEb" data-lang="python">def create_map(self):
	self.player = Player((1000, 1000), [self.visible_sprites], self.obstacle_sprites)</pre>
  <p id="lPYn">Всё что я оставил — это отрисовку места Линка на карте. Просто указал координату.</p>
  <figure id="nmKc" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/m9/un/o8/m9uno82jupl3b2zj2jcmckewahu.png" width="912" />
  </figure>
  <p id="z7Md">Теперь наша задача провзаимодействовать с файлом <code>tile.py</code> эму нужны настройки более детальные для прорисовки объектов и картинок конкретного размера. Приступим.</p>
  <p id="rg21">Для начала, помимо прочих элементов, демонам нужно передавать новые два аргумента <code>sprite_type</code> и <code>surface = pygame.Surface((TILESIZE, TILESIZE))</code>. Думаю, по названия понятно, что они будут передавать сам тип спрайта и его размер из файла <code>settings.py</code>. Ещё немного переработаем файл и получим упрощение конструкции с ссылкой на себя:</p>
  <pre id="9ihH" data-lang="python">import pygame
from settings import *

class Tile(pygame.sprite.Sprite):
	def __init__(self, pos, groups, sprite_type, surface = pygame.Surface((TILESIZE, TILESIZE))):
		super().__init__(groups) #наследуем все группы
		self.sprite_type = sprite_type
		self.image = surface
		self.rect = self.image.get_rect(topleft = pos) #указываем позицию отрисовки (левый верхний угол)
		self.hitbox = self.rect.inflate(0, -10) #делаем по 5 пискселей сверху и снизу от самого объекта, до хитбокса</pre>
  <p id="nHXR">Вернёмся в <code>creat_map</code>. Создадим новый словарь на основе csv-файлов:</p>
  <pre id="Czbx" data-lang="python">layout = {
		&#x27;boundary&#x27;: import_csv_layout(&#x27;../map/map_Block.csv&#x27;)
}</pre>
  <p id="5mAe">Метод <code>import_csv_layout</code> нам не знаком. Напишем его в новой файле <code>support.py</code>.</p>
  <pre id="X1GL" data-lang="python">from csv import reader

def import_csv_layout(path):
	with open(path) as level_map:
		layout = reader(level_map, delimiter = &#x27;,&#x27;)
		for row in layout:
			print(row)

import_csv_layout(&#x27;../map/map_Block.csv&#x27;)</pre>
  <p id="C1aZ">В данном коде идёт чтение csv-файла. А при чтении &quot;1&quot; — означает, что объект там есть, а &quot;-1&quot; — его там нет.</p>
  <p id="wLDk">Результат вывода <code>support.py</code>:</p>
  <figure id="r1Ad" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/3n/in/aa/3ninaaaabhjj56tkz55he6z7m5a.png" width="1494" />
  </figure>
  <p id="Zlhu">Чуть подправим, чтобы у нас на выходе была матрица (массив из выведенных строк) и функция готова:</p>
  <pre id="SWjD" data-lang="python">from csv import reader

def import_csv_layout(path):
	terrain_map = []
	with open(path) as level_map:
		layout = reader(level_map, delimiter = &#x27;,&#x27;)
		for row in layout:
			terrain_map.append(list(row))
		return terrain_map</pre>
  <p id="35a5">Теперь, вернёмся к <code>creat_map</code> и допишем функцию очень похожую на то, что было ранее (не забудьте импортировать support):</p>
  <pre id="jdSk" data-lang="python">def create_map(self):
	layout = {
			&#x27;boundary&#x27;: import_csv_layout(&#x27;../map/map_Block.csv&#x27;)
	}
	for style, layout in layout.items():
		for row_index, row in enumerate(layout):
			for col_index, col in enumerate(row):
				if col != &#x27;-1&#x27;:
					x = col_index * TILESIZE
					y = row_index * TILESIZE
					if style == &#x27;boundary&#x27;:
						Tile((x, y), [self.visible_sprites, self.obstacle_sprites], &#x27;invisible&#x27;)
	self.player = Player((1000, 1000), [self.visible_sprites], self.obstacle_sprites)</pre>
  <p id="oMuP">Итог:</p>
  <figure id="r6J3" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/fq/cm/ew/fqcmewdiiqdrzhdd99epy1-kgwi.png" width="1560" />
  </figure>
  <p id="ELQM">Чёрные края — это невидимые стены. Осталось их только сделать невидимыми. Удалим <code>self.visible_sprites</code>.</p>
  <p id="ZJDf">Создадим ещё один вариант стиля — <code>objects</code>. Тут нам потребуется сразу несколько картинок. Чтобы не перебирать их вручную в <code>support.py</code> создадим новый метод поиска картинок при помощи знакомым многим функции walk:</p>
  <pre id="Abz1" data-lang="python">def import_folder(path):
	for _, __, img_files in walk(path):
		for image in img_files:
			full_path = path + &#x27;/&#x27; + image
			print(full_path)</pre>
  <p id="f6s5">Получим вывод:</p>
  <figure id="LIXS" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/nr/5i/zt/nr5iztoplq3uepre60axndgtsrq.png" width="1494" />
  </figure>
  <p id="MlVY">Немного перепишем метод под pygame:</p>
  <pre id="IexW" data-lang="python">def import_folder(path):
	surface_list = []
	for _, __, img_files in walk(path):
		for image in img_files:
			full_path = path + &#x27;/&#x27; + image
			image_surf = pygame.image.load(full_path).convert_alpha()
			surface_list.append(image_surf)
	return surface_list</pre>
  <p id="y5QI">Сам метод отрисовки объектов:</p>
  <pre id="kFgO" data-lang="python">if style == &#x27;objects&#x27;:
	surf = graphics[&#x27;objects&#x27;][int(col)]
	Tile((x, y), [self.visible_sprites, self.obstacle_sprites], &#x27;object&#x27;, surf)</pre>
  <p id="l5aP">Тут мы просто перебором по всем файлам выставляем объекты. Есть только одна проблема. Если объекты были друг за другом — они рандомно ставятся. Нужно это исправить. Исправим это в <code>tile.py</code>:</p>
  <pre id="GqXF" data-lang="python">if sprite_type == &#x27;object&#x27;:
	self.rect = self.image.get_rect(topleft = (pos[0], pos[1] - TILESIZE))
else:
	self.rect = self.image.get_rect(topleft = pos) #указываем позицию отрисовки (левый верхний угол)</pre>
  <p id="2eP8">В этом моменте мы отключили перекрытие объектом других объектов. Итого, Линк гуляет в лесу!</p>
  <p id="2S8d"><a href="https://disk.yandex.ru/d/eKerCcYDe7tTqA" target="_blank">Результат работы по ссылке</a>. Помимо прочего, я оставил проект в Tiled, чтобы вы сами могли &quot;поиграться&quot; с ним. Далее, мы поговорим об анимации.</p>
  <h3 id="qRms">Анимация Линка</h3>
  <p id="GYqh">Для начала, нужно добавить действие и кнопку. На атаку будет стоять кнопка &quot;Пробел&quot;. Пропишем это в <code>player.py</code>:</p>
  <pre id="6kLn" data-lang="python">if keys[pygame.K_SPACE] and not self.attacking:
	self.attacking = True</pre>
  <p id="RCWV">Тут непонятно что такое <code>self.attacking</code>. В демоны файла я добавил три параметра: статус атаки (<code>self.attacking = False</code>), кулдаун после атаки (<code>self.attack_cooldown = 400</code>) и время атаки (<code>self.attack_time = None</code>).</p>
  <p id="gkic">Добавим время между атаками. Для этого, после успешной атаки, создадим конструкцию: <code>self.attack_time = pygame.time.get_ticks()</code> сразу после объявление атаки флагом <code>True</code>. Далее, перейдём к настройке нового метода <code>cooldowns</code>. Сам метод:</p>
  <pre id="ECoh" data-lang="python">def cooldowns(self):
	current_time = pygame.time.get_ticks()

	if self.attacking:
		if current_time - self.attack_time &gt;= self.attack_cooldown:
			self.attacking = False</pre>
  <p id="8xf1">На самом деле конструкция очень проста. Если разница во времени после нажатия меньше кулдауна атаки (в моём случае 400 мс), запрещать атаку. Не забудьте закинуть функцию cooldowns в update-функцию.</p>
  <p id="9Ygf">Далее, пропишем метод <code>import_player_assets</code>:</p>
  <pre id="t05Y" data-lang="python">def import_player_assets(self):
	character_path = &#x27;../graphic/Link/&#x27;
	self.animations = {&#x27;up&#x27;: [], &#x27;down&#x27;: [], &#x27;left&#x27;: [], &#x27;right&#x27;: [],
	&#x27;right_idle&#x27;: [], &#x27;left_idle&#x27;: [], &#x27;up_idle&#x27;: [], &#x27;down_idle&#x27;: [],
	&#x27;right_attack&#x27;: [], &#x27;left_attack&#x27;: [], &#x27;up_attack&#x27;: [], &#x27;down_attack&#x27;: []}</pre>
  <p id="NFRz">В нём прописаны все возможности передвижения. Они лежат в папке &quot;Link&quot;:</p>
  <figure id="rtpg" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/dv/bz/7r/dvbz7r9mulkwm_hifbrckujnmre.png" width="1381" />
  </figure>
  <p id="N9Ud">Не забудьте закинуть в базовых демонов Player-класса наши ассеты: <code>self.import_player_assets()</code>. Далее, &quot;пробежимся&quot; по нашим папкам благодаря методу <code>import_folder</code> в <code>support.py</code>:</p>
  <pre id="nFXO" data-lang="python">for animation in self.animations.keys():
	full_path = character_path + animation
	self.animations[animation] = import_folder(full_path)</pre>
  <p id="0UKH">Теперь мы модем открыть все файлы, но есть дополнительная проблема — нужно прописать статусы и анимации при нажатии на кнопку. Статус по умолчанию укажем в демоне и по умолчанию Линк будет смотреть вниз (<code>self.status = &#x27;down&#x27;</code>). Но этого мало. Нужно получать статус автоматически, а это значит новый метод:</p>
  <pre id="1tjJ" data-lang="python">def get_status(self):
	if self.direction.x == 0 and self.direction.y == 0:
		self.status = self.status + &#x27;_idle&#x27;</pre>
  <p id="FJ1f">Тут мы прописываем название файла &quot;стояния&quot; героя. Стояние — <code>_idle</code>, а статус будет меняться от нажатия кнопок. Закидываем <code>get_status()</code> в update-метод.</p>
  <p id="b0U1">Далее, пропишем статусы для наших методов хождения:</p>
  <pre id="OY27" data-lang="python">if keys[pygame.K_UP]:
	self.direction.y = -1
	self.status = &#x27;up&#x27;
elif keys[pygame.K_DOWN]:
	self.direction.y = 1
	self.status = &#x27;down&#x27;
else:
	self.direction.y = 0

if keys[pygame.K_LEFT]:
	self.direction.x = -1
	self.status = &#x27;left&#x27;
elif keys[pygame.K_RIGHT]:
	self.direction.x = 1
	self.status = &#x27;right&#x27;</pre>
  <p id="hYTF">Тут всё достаточно прозрачно. Движение = статусу. Подправим функцию статуса:</p>
  <pre id="cLzF" data-lang="python">if not &#x27;idle&#x27; in self.status:
	self.status = self.status + &#x27;_idle&#x27;</pre>
  <p id="P6Cv">Теперь, если мы отпускаем кнопку — статус равен idle, а если держим просто название направления.</p>
  <p id="VFCb">Теперь окончательно проапгрейдим код для атак и комбинаций с &quot;_idle&quot;:</p>
  <pre id="Mpsh" data-lang="python">def get_status(self):
	if self.direction.x == 0 and self.direction.y == 0:
		if not &#x27;idle&#x27; in self.status and not &#x27;attack&#x27; in self.status:
			self.status = self.status + &#x27;_idle&#x27;
	if self.attacking:
		self.direction.x = 0 #координаты по x
		self.direction.y = 0 #координаты по y
		if not &#x27;attack&#x27; in self.status: #если нет подписи &quot;attack&quot;
			if &#x27;idle&#x27; in self.status: #но есть &quot;idle&quot;
				self.status = self.status.replace(&#x27;_idle&#x27;, &#x27;_attack&#x27;) #убираем _idle, но оставляем _attack
			else:
				self.status = self.status + &#x27;_attack&#x27; #если idle не было, просто стави attack
	else:
		if &#x27;attack&#x27; in self.status:
			self.status = self.status.replace(&#x27;_attack&#x27;, &#x27;&#x27;) #удаляем attack при завершении статуса</pre>
  <p id="h3wC">Наконец, заанимируем Линка. Установим два новых демона <code>self.frame_index = 0</code> — индекс первой картинки и скорость смены картинок — <code>self.animation_speed = 0.15</code>. Далее, создадим метод <code>animate()</code>:</p>
  <pre id="mBDR" data-lang="python">def animate(self):
	animation = self.animations[self.status] #узнаём статус для ссылки на нужный файл
	self.frame_index += self.animation_speed #добовляем нашу скорость и когда добавится единица (из 0.15), сменяем картинку
	if self.frame_index &gt;= len(animation): #при вылете из массива
		self.frame_index = 0 #возвращаемся к начальной картинке и тем самым зацикливаемся
	self.image = animation[int(self.frame_index)] #указываем картику
	self.rect = self.image.get_rect(center = self.hitbox.center) #указываем хитбокс</pre>
  <p id="NTe8">Всё что тут происходит, мы перебираем все наши картинки и главное — их зациклить, как в рилсах. Не забываем в update-функцию <code>self.animate()</code>.</p>
  <p id="dXDh">Тут у меня залогала анимация атаки, так как кнопка продолжала нажиматься. Исправим это в input-методе:</p>
  <pre id="Rb37" data-lang="python">def input(self): #варьируем кнопки
	if not self.attacking:
		keys = pygame.key.get_pressed()

		if keys[pygame.K_UP]:
			self.direction.y = -1
			self.status = &#x27;up&#x27;
		elif keys[pygame.K_DOWN]:
			self.direction.y = 1
			self.status = &#x27;down&#x27;
		else:
			self.direction.y = 0

		if keys[pygame.K_LEFT]:
			self.direction.x = -1
			self.status = &#x27;left&#x27;
		elif keys[pygame.K_RIGHT]:
			self.direction.x = 1
			self.status = &#x27;right&#x27;
		else:
			self.direction.x = 0

		if keys[pygame.K_SPACE]:
			self.attacking = True
			self.attack_time = pygame.time.get_ticks()</pre>
  <p id="zSG5">Итог:</p>
  <figure id="95Pl" class="m_original">
    <img src="https://habrastorage.org/webt/mm/r7/pw/mmr7pwjcipk6fzlcmnanaclguye.gif" width="600" />
  </figure>
  <p id="yEFB">Далее, прорисуем оружие. <a href="https://disk.yandex.ru/d/VVjRMFfvxHqLHg" target="_blank">Файлы этого этапа</a>.</p>
  <h3 id="nWXi">Оружие героя</h3>
  <p id="4dmy">Тут я немного поменял карту, так как Линк врезался в мосты, которые соединяют нижние острова. Изменения делала непосредственно в Tiles и сохранял карту и csv-файлы. Чтобы всё было канонично, Линку выдадим меч. Спрайты на мечи я тоже отрисовал. Он лежит в папке weapons/sword. Там 5 картинок, где full обозначает сам меч, а остальные 4 — направления меча. Приступим к коду.</p>
  <p id="R7c7">В файле <a href="http://setting.py/" target="_blank">setting.py</a>, я создал словарь из оружий. У меня будет только один меч, но вы можете добавить больше оружия. Сам словарь:</p>
  <pre id="nA9S" data-lang="python">weapon_data = {&#x27;sword&#x27;: {&#x27;cooldown&#x27;: 300, &#x27;damage&#x27;: 15, &#x27;graphic&#x27;:&#x27;../graphic/weapons/sword/full.png&#x27;}}</pre>
  <p id="8vL0">Далее, создадим новый файл с настойкой оружия <code>weapon.py</code>:</p>
  <pre id="9ndr" data-lang="python">import pygame

class Weapon(pygame.sprite.Sprite):
	def __init__(self, player, groups):
		super().__init__(groups)
		self.image = pygame.Surface((40, 40)) #сама графика
		self.rect = self.image.get_rect(center = player.rect.center) #место отрисовки</pre>
  <p id="OPKa">Тут всё традиционно и без нового. Мы центруемся от самого игрока последней строкой в коде. Сейчас посередине будет рисоваться чёрный квадрат 40 на 40 пикселей. Импортируем новый файл в Level и создаём новый метод <code>create_attack</code>.</p>
  <pre id="6BXe" data-lang="python">def create_attack(self):
	Weapon(self.player, [self.visible_sprites])	</pre>
  <p id="wE7c">Далее, в самой отрисовке игрока, добавим наш метод как ссылку на него:</p>
  <pre id="64L8" data-lang="python">self.player = Player((1000, 1000), [self.visible_sprites], self.obstacle_sprites, self.create_attack)</pre>
  <p id="0yIZ">Далее, перейдём в файл <a href="http://player.py/" target="_blank">player.py</a> и там передадим create_attack и создадим демона. Также, при нажатии на пробел, добавим метод <code>self.create_attak()</code>. Теперь можем вернуться к отрисовке нашего оружия:</p>
  <pre id="seAf" data-lang="python">import pygame

class Weapon(pygame.sprite.Sprite):
	def __init__(self, player, groups):
		super().__init__(groups)
		direction = player.status.split(&#x27;_&#x27;)[0] #обрезаем строку по &quot;_&quot; чтобы понимать куда он смотрит
		full_path = f&#x27;../graphic/weapons/{player.weapon}/{direction}.png&#x27; #адрес оружия
		self.image = pygame.image.load(full_path).convert_alpha() #сама графика
		if direction == &#x27;right&#x27;:
			self.rect = self.image.get_rect(midleft = player.rect.midright + pygame.math.Vector2(-10, 16))
		elif direction == &#x27;left&#x27;:
			self.rect = self.image.get_rect(midright = player.rect.midleft + pygame.math.Vector2(10, 16))
		elif direction == &#x27;down&#x27;:
			self.rect = self.image.get_rect(midtop = player.rect.midbottom + pygame.math.Vector2(-15, 0))
		else:
			self.rect = self.image.get_rect(midbottom = player.rect.midtop + pygame.math.Vector2(-15, 0))</pre>
  <p id="5ePy">Тут появилось несколько интересного. Во-первых, мы обрезаем строку по &quot;_&quot; чтобы понять куда смотрит герой (неважно с &quot;attack&quot; или без). Далее, отрисовка. Нам нужно чтобы меч рисовался в руке у Линка. Я выбрал следующий метод, если меч слева, то &quot;приклеиться&quot; он должен справа от Линка, то есть <code>midleft = player.rect.midright + pygame.math.Vector2(-10, 16)</code>. Далее, плюсуем вектор направления чтобы меч был ровно в руке. Далее, всё повторяется в зависимости от направления.</p>
  <p id="6h9Q">Добавим в <a href="http://player.py/" target="_blank">player.py</a> новых демонов:</p>
  <pre id="Yu5A" data-lang="python">self.create_attak = create_attak #создали атаку
self.weapon_index = 0 #номер оружия (если у вас будет несколько орудий пыток монстров)
self.weapon = list(weapon_data.keys())[self.weapon_index] #выбрали конкретное оружие и все его параметры= None</pre>
  <p id="VA8X">Теперь есть меч, но есть проблема. Мечи не исчезают:</p>
  <figure id="EF5B" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/-q/pj/7k/-qpj7kfcf-hjzxg_qyjvekzbeye.png" width="487" />
  </figure>
  <p id="AK90">Что ж, создадим новый метод в <code>level.py</code>: <code>destroy_weapon</code>. Помимо прочего, нужно немного переработать код в самом <code>level.py</code>. Создадим нового демона <code>self.current_attack = None</code>, а также переработаем метод <code>create_attack</code>.</p>
  <pre id="QNKu" data-lang="python">def create_attack(self):
	self.current_attack = Weapon(self.player, [self.visible_sprites])	

def destroy_weapon(self):
	if self.current_attack:
		self.current_attack.kill()
	self.current_attack = None</pre>
  <p id="8Wsf">Таким образом, при наличии атаки, мы убиваем процесс и обнуляем указатель атаки (<code>current_attak</code>). Нужен ещё кулдаун. Также, не забудьте сослаться на <code>self.destroy_weapon</code> в player:</p>
  <pre id="epSb" data-lang="python">self.player = Player((1000, 1000), [self.visible_sprites], self.obstacle_sprites, self.create_attack, self.destroy_weapon)</pre>
  <p id="BGXL">Далее пропишем метод в <a href="http://player.py/" target="_blank">player.py</a> и внесём в кулдаун новую функцию: <code>self.destroy_weapon()</code>. Результат:</p>
  <figure id="wMHp" class="m_original">
    <img src="https://habrastorage.org/webt/hx/uz/cf/hxuzcfzagyusjhvnw6dqnlnzn2w.gif" width="600" />
  </figure>
  <p id="rKX1"><a href="https://disk.yandex.ru/d/iNPvgc6Yu52cGg" target="_blank">Файлы этапа можно скачать здесь</a>. Далее, настроим интерфейс.</p>
  <h3 id="0kCm">Интерфейс</h3>
  <p id="ZSdy">Наша задача — сделать интерфейс игры. Первым делом, нужно создать такие простые вещи как базовые параметры. У нас уже есть один параметр. Это скорость. Сейчас допишем остальные параметры. В демоны в файле <code>player.py</code> запишем следующие параметры:</p>
  <pre id="of7E" data-lang="python">self.stats = {&#x27;health&#x27;: 100, &#x27;energy&#x27;: 60, &#x27;attack&#x27;: 10, &#x27;speed&#x27;: 5} #все параметры героя
self.health = self.stats[&#x27;health&#x27;] #соотношение со здоровьем
self.energy = self.stats[&#x27;energy&#x27;] #соотношение с энергией
self.exp = 4221 #количество очков
self.speed = self.stats[&#x27;speed&#x27;] #скорость игрока</pre>
  <p id="On8L">Все параметры указаны и можно удалить параметр скорости из демона ранее. Особенно хорошо, что Линк уже набрал 4221 очка за просмотр себя на ютюбе у Артура из Уфы. В файле <a href="http://settings.py/" target="_blank">settings.py</a> Добавим немного параметров отображения:</p>
  <pre id="pvyh" data-lang="python">BAR_HEIGHT = 20 #толщина всех панелек
HEALTH_BAR_WIDTH = 200  #длина панельки здоровья
ENERGY_BAR_WIDTH = 140 #длина панельки энергии
ITEM_BOX_SIZE = 80 #размер значка под предмет
UI_FONT = &#x27;../graphic/font/joystix.ttf&#x27; #основной шрифт
UI_FONT_SIZE = 18 #кегель шрифта

UI_BG_COLOR = &#x27;#222222&#x27; #цвет задника
UI_BORDER_COLOR = &#x27;#111111&#x27; #цвет обводки
TEXT_COLOR = &#x27;#EEEEEE&#x27; #цвет текста

HEALTH_COLOR = &#x27;red&#x27; #цвет здоровья
ENERGY_COLOR = &#x27;green&#x27; #цвет энергии</pre>
  <p id="9OBL">Тут самый важный момент — добавить шрифт. Самый его большой плюс это то, что он поддерживает русский язык. Теперь, в настройках уровня укажем нового демона <code>self.ui = UI()</code> и импортируем сам файл в проект. Под конец, добавим в run-метод правило отрисовки:</p>
  <pre id="D3Mz" data-lang="python">self.ui.display(self.player)</pre>
  <p id="Rm7w">Теперь создадим новый файл <code>ui.py</code>:</p>
  <pre id="ppfg" data-lang="python">import pygame
from settings import *

class UI:
	def __init__(self):
		self.display_surface = pygame.display.get_surface() #прорисовка самого экрана
		self.font = pygame.font.Font(UI_FONT, UI_FONT_SIZE) #добавление стандартного шрифта
		self.healt_bar_rect = pygame.Rect(10, 10, HEALTH_BAR_WIDTH, BAR_HEIGHT) #панелька для здоровья
		self.energy_bar_rect = pygame.Rect(10, 34, ENERGY_BAR_WIDTH, BAR_HEIGHT) #панелька для энергии

	def show_bar(self, current, max_amountm, bg_rect, color):
		pygame.draw.rect(self.display_surface, UI_BG_COLOR, bg_rect) #отрисовка задника панельки
		ratio = current / max_amountm
		current_with = bg_rect.width * ratio
		current_rect = bg_rect.copy()
		current_rect.width = current_with
		pygame.draw.rect(self.display_surface, color, current_rect) #рисование панельки
		pygame.draw.rect(self.display_surface, UI_BORDER_COLOR, bg_rect, 3) #рисование обводки панельки

	def display(self, player):
		self.show_bar(player.health, player.stats[&#x27;health&#x27;], self.healt_bar_rect, HEALTH_COLOR) #обращение к отрисовке панели здоровья
		self.show_bar(player.energy, player.stats[&#x27;energy&#x27;], self.energy_bar_rect, ENERGY_COLOR) #обращение к отрисовке панели энергии</pre>
  <p id="sNhI">Из интересного, тут есть строки расчётов:</p>
  <pre id="WbVO" data-lang="python">ratio = current / max_amountm
current_with = bg_rect.width * ratio
current_rect = bg_rect.copy()
current_rect.width = current_with</pre>
  <p id="PDYS">Тут мы переводим значения нашего здоровья в проценты прорисовки в поле пикселей. Нам нужно перевести даже 140 очков здоровья в 100%. Для этого, мы запрашиваем <code>current</code> — очки здоровья и делим их на длину нашего поля здоровья (<code>max_amountm</code>), далее перемножаем это с <code>bg_rect.width</code> для отображения в поле. Я поставил в <a href="http://player.py/" target="_blank">player.py</a> значение здоровья на -10 и -50 на энергию:</p>
  <pre id="TUun" data-lang="python">self.health = self.stats[&#x27;health&#x27;] - 10 #соотношение со здоровьем
self.energy = self.stats[&#x27;energy&#x27;] - 50 #соотношение с энергией</pre>
  <p id="s1kl">Результат:</p>
  <figure id="zh6p" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/lo/m-/mx/lom-mxxf6k8obbhxd6tbl8547qc.png" width="344" />
  </figure>
  <p id="xbq6">Нарисуем же наши очки. Переходим опять к <code>ui.py</code> и создадим новый метод <code>show_exp</code>:</p>
  <pre id="Cwlq" data-lang="python">def show_exp(self, exp):
	text_surf = self.font.render(str(int(exp)), False, TEXT_COLOR) #рендер шрифта с экспой, без сглаживания и с цветом
	x = self.display_surface.get_size()[0] - 20 #отступ снизу на 20 пикселей по x
	y = self.display_surface.get_size()[1] - 20 #отступ снизу на 20 пикселей по y
	text_rect = text_surf.get_rect(bottomright = (x, y)) #цепляемся за низ экрана справа

	pygame.draw.rect(self.display_surface, UI_BG_COLOR, text_rect.inflate(20, 20)) #цепляемся за низ экрана справа
	self.display_surface.blit(text_surf, text_rect) #отображаем панельку
	pygame.draw.rect(self.display_surface, UI_BORDER_COLOR, text_rect.inflate(20, 20), 3) #обводка панели</pre>
  <p id="j49t">Из интересного, тут стоит False в методе <code>self.font.render</code>. Данный метод выключает сглаживание, так как у меня пиксельный шрифт. А также, pygame сделали крутой метод <code>text_rect.inflate</code>, который помогает вписать текст в панельку. Результат удивительно прекрасен:</p>
  <figure id="2l4Q" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/nh/ho/oe/nhhooenw_zub2mrxxsbbibq2hrc.png" width="148" />
  </figure>
  <p id="nBnl">Последний шаг — прорисовка меча Линка. Для начала, нужно прописать в базовых демонов наш список оружия. У меня в наличии только одно оружие, так что этот кусок кода можно упростить, но я оставил возможность подбирать оружие и добавить его в словарь оружия, а затем и в этот список:</p>
  <pre id="BKGw" data-lang="python">self.weapon_graphics = []
for weapon in weapon_data.values():
	path = weapon[&#x27;graphic&#x27;]
	weapon = pygame.image.load(path).convert_alpha()
	self.weapon_graphics.append(weapon)</pre>
  <p id="7JS0">Далее, пишем простой метод для отображения предметов:</p>
  <pre id="UrqR" data-lang="python">def weapon_overlay(self, weapon_index):
	bg_rect = pygame.Rect(10, 630, ITEM_BOX_SIZE, ITEM_BOX_SIZE)
	pygame.draw.rect(self.display_surface, UI_BG_COLOR, bg_rect)
	weapon_surf = self.weapon_graphics[weapon_index]
	weapon_rect = weapon_surf.get_rect(center = bg_rect.center)

	self.display_surface.blit(weapon_surf, weapon_rect)</pre>
  <p id="mT2m">В конце не забудьте добавить отображение оружия в display-методе: <code>self.weapon_overlay(player.weapon_index)</code>.</p>
  <p id="wh83">Результат:</p>
  <figure id="QWjD" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/jy/te/cr/jytecrdqzdmwjgtqv9jiacewklg.png" width="1560" />
  </figure>
  <p id="WUuv"><a href="https://disk.yandex.ru/d/WwhG3l8y5LrT5A" target="_blank">Файлы проекта</a> и дальше будем писать монстров (более известных как бебы).</p>
  <h3 id="3tPc">Монстры</h3>
  <p id="BUix">Для начала, я прописал референсы для монстров. Они хранятся в папке <code>graphic/monsters</code>. Также, я добавил звуки ударов и закинул их в папку <code>audio/attack</code> Далее, в <a href="http://setting.py/" target="_blank">setting.py</a> прописаны их входные данные:</p>
  <pre id="IDuA" data-lang="python">monster_data = {
	&#x27;axalot&#x27;: {&#x27;health&#x27;: 200, &#x27;exp&#x27;: 400, &#x27;damage&#x27;: 40, &#x27;attack_type&#x27;: &#x27;slash&#x27;, &#x27;attack_sound&#x27;: &#x27;../audio/attack/slash.wav&#x27;, &#x27;speed&#x27;: 3, &#x27;resistance&#x27;: 3, &#x27;attack_radius&#x27;: 80, &#x27;notice_radius&#x27;: 300},
	&#x27;lizard&#x27;: {&#x27;health&#x27;: 50, &#x27;exp&#x27;: 100, &#x27;damage&#x27;: 15,&#x27;attack_type&#x27;: &#x27;claw&#x27;,  &#x27;attack_sound&#x27;: &#x27;../audio/attack/claw.wav&#x27;, &#x27;speed&#x27;: 2, &#x27;resistance&#x27;: 3, &#x27;attack_radius&#x27;: 100, &#x27;notice_radius&#x27;: 400},
	&#x27;snake&#x27;: {&#x27;health&#x27;: 100,&#x27;exp&#x27;:100,&#x27;damage&#x27;: 10,&#x27;attack_type&#x27;: &#x27;claw&#x27;, &#x27;attack_sound&#x27;: &#x27;../audio/attack/claw.wav&#x27;, &#x27;speed&#x27;: 4, &#x27;resistance&#x27;: 3, &#x27;attack_radius&#x27;: 80, &#x27;notice_radius&#x27;: 350},
	&#x27;spirit&#x27;: {&#x27;health&#x27;: 150,&#x27;exp&#x27;:200,&#x27;damage&#x27;: 15,&#x27;attack_type&#x27;: &#x27;claw&#x27;, &#x27;attack_sound&#x27;: &#x27;../audio/attack/claw.wav&#x27;, &#x27;speed&#x27;: 3, &#x27;resistance&#x27;: 3, &#x27;attack_radius&#x27;: 100, &#x27;notice_radius&#x27;: 400}}</pre>
  <p id="sXGd">Давайте пробежимся по параметрам:</p>
  <ul id="Ho3w">
    <li id="onZg"><code>health</code> — здоровье беба</li>
    <li id="shxx"><code>exp</code> — сколько очков за смерть беба</li>
    <li id="x6gd"><code>damage</code> — какой урон он нанесёт герою</li>
    <li id="Tpzc"><code>attack_type</code> — тип атаки</li>
    <li id="bCkp"><code>attack_sound</code> — звук удара</li>
    <li id="p6hu"><code>speed</code> — скорость зверька</li>
    <li id="ICiE"><code>resistance</code> — на сколько враг отлетит после нашего удара</li>
    <li id="uCSh"><code>attack_radius</code> — радиус, с которого беб опасен и может ударить</li>
    <li id="Zrqx"><code>notice_radius</code> — радиус зрения вражины</li>
  </ul>
  <p id="oi9g">Далее, создадим новый файл сущностей (<code>entity.py</code>) и добавим туда супер демона с наследованием групп:</p>
  <pre id="UKD5" data-lang="python">import pygame

class Entity(pygame.sprite.Sprite):
	def __init__(self, groups):
		super().__init__(groups)</pre>
  <p id="5uUg">Скопируем методы <code>move</code> и <code>collision</code> из <code>player.py</code>. Теперь удаляем из <code>player.py</code> эти методы и ссылаться будем в классе не на <code>pygame.sprite.Sprite</code>, а на <code>Entity</code> (не забывайте импортировать файл). Эти небольшие танцы с бубном нужны для того, чтобы не переписывать каждый раз правила движений для нашего героя и врагов. Все они — одинаковые сущности. Также я перенёс демонов скорости анимации, фрейма и определения вектора скорости. Когда всё сделаете, перепроверьте, что всё работает.</p>
  <p id="EdNe">Затем, наконец, создадим файл <code>enemy.py</code>:</p>
  <pre id="cvQb" data-lang="python">import pygame
from settings import *
from entity import Entity

class Enemy(Entity):
	def __init__(self, monster_name, pos, groups):
		super().__init__(groups)
		self.sprite_type = &#x27;enemy&#x27; #новый тип спрайтов — враги
		self.image = pygame.Surface((64, 64)) #наш традиционный размер тайла
		self.rect = self.image.get_rect(topleft = pos) #традиционная отрисовка</pre>
  <p id="n76C">Перейдём к настройке уровня. Для начала, сделаем так, чтобы наш герой спаунился там, где надо (зелёный квадрат на карте). Для этого, нам нужно импортировать новый csv-файл из уже созданной карты <code>&#x27;entities&#x27;: import_csv_layout(&#x27;../map/map_Spawn.csv&#x27;)</code>. И пропишем в методе <code>creat_map</code> новый объект:</p>
  <pre id="hS66" data-lang="python">if style == &#x27;entities&#x27;:
	if col == &#x27;8&#x27;:
	self.player = Player((x, y), [self.visible_sprites], self.obstacle_sprites, self.create_attack, self.destroy_weapon)</pre>
  <p id="ffLg">Результат вас удивит:</p>
  <figure id="zA3S" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/dz/bb/m4/dzbbm4lxnmod4ucsux9yj2etg08.png" width="1560" />
  </figure>
  <p id="YSFm">Герои Хайрула размножились. Проблема в том, что я прорисовывал карту разными наборами элементов. Не повторяйте моих ошибок и давайте всё исправлять. Дело в том, что номер тайла автоматически рассчитывается программой Tiles, а я указал, разные тайлы и номера задублировались, так как у меня был отдельный файл Bebs.png для спауна врагов и Link_and_block.png для Линка и блоков-стен. Теперь я объединил два набора тайлов и присвоил линку номер 16. Результат:</p>
  <figure id="vFNL" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/cf/6z/pz/cf6zpzgvogebhablacrdfavisqs.png" width="1560" />
  </figure>
  <p id="iH2E">Линк на своём законном месте. Давайте заспаумим врагов, добавив лишь один else:</p>
  <pre id="gEoY" data-lang="python">else:
	Enemy(&#x27;monster&#x27;, (x, y), [self.visible_sprites])</pre>
  <figure id="f7Wj" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/ey/ed/ql/eyedqlpnxark47ej0p1ztoi8y3a.png" width="1560" />
  </figure>
  <p id="Tzie">Монстры отобразились, но теперь нужно отобразить их верно. Работаем с файлом <code>enemy.py</code>:</p>
  <pre id="LUlP" data-lang="python">import pygame
from settings import *
from entity import Entity
from support import *

class Enemy(Entity):
	def __init__(self, monster_name, pos, groups):
		super().__init__(groups)
		self.sprite_type = &#x27;enemy&#x27; #новый тип спрайтов — враги
		self.import_graphics(monster_name) #обращаемся к новой функции перебора картинок
		self.status = &#x27;idle&#x27; #установим базовый статус
		self.image = self.animations[self.status][self.frame_index] #перебираем номер фрейма в папке из функции ниже
		self.rect = self.image.get_rect(topleft = pos) #традиционная отрисовка

	def import_graphics(self, monster_name):
		self.animations = {&#x27;idle&#x27;: [], &#x27;move&#x27;: [], &#x27;attack&#x27;: []} #перебираем возможные варианты анимаций в папках
		main_path = f&#x27;../graphic/monsters/{monster_name}/&#x27; #обращаемся к монстру по имени :)
		for animation in self.animations.keys(): #перебираем все картинки
			self.animations[animation] = import_folder(main_path + animation) #перебор благодаря support-файлу</pre>
  <p id="rz6V">Тут мы делаем всё ровно также, как и ранее, но если в файле <code>level.py</code> мы внесём имя любого монстра, то получим картинку монстра на карте:</p>
  <figure id="J7dP" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/8c/qp/nt/8cqpntdcv9af2s9txpo8x6b9e2a.png" width="302" />
  </figure>
  <p id="e4HB">Осталось только перебрать монстров по их номерам тайлов на карте:</p>
  <pre id="ylGO" data-lang="python">else:
	if col == &#x27;0&#x27;:
		monster_name = &#x27;axolot&#x27;
	elif col == &#x27;4&#x27;:
		monster_name = &#x27;lizard&#x27;
	elif col == &#x27;8&#x27;:
		monster_name = &#x27;snake&#x27;
	else:
	monster_name = &#x27;spirit&#x27;

	Enemy(monster_name, (x, y), [self.visible_sprites])</pre>
  <figure id="wU7U" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/0d/bx/2v/0dbx2vpdvrznqapup6a0dilsiji.png" width="1560" />
  </figure>
  <p id="VtR7">Теперь, добавим аргумент <code>obstacle_sprites</code> в нашу конструкцию, что бебы могли взаимодействовать с Линком. Далее, создадим update-метод для файла <code>enemy.py</code>:</p>
  <pre id="7Od5" data-lang="python">def update(self):
	self.move(self.speed)</pre>
  <p id="HGx9">Далее, нужно прописать несколько статусов для наших плохишей. Добавим их в демонов данного файла:</p>
  <pre id="wqcc" data-lang="python">self.monster_name = monster_name #имя монстра
monster_info = monster_data[self.monster_name] #перехват данных монстра по имени
self.health = monster_info[&#x27;health&#x27;]
self.exp = monster_info[&#x27;exp&#x27;]
self.speed = monster_info[&#x27;speed&#x27;]
self.attack_damage = monster_info[&#x27;damage&#x27;]
self.resistance = monster_info[&#x27;resistance&#x27;]
self.attack_radius = monster_info[&#x27;attack_radius&#x27;]
self.notice_radius = monster_info[&#x27;notice_radius&#x27;]
self.attack_type = monster_info[&#x27;attack_type&#x27;]</pre>
  <p id="nU0P">Тут мы ссылаемся на файл <a href="http://settings.py/" target="_blank">settings.py</a> и перехватываем все параметры монстров оттуда. Теперь наша задача прописать метод определения дистанции до объекта. Я думал, что эта задача непроста, так как координаты объекта рассчитываются с верхнего левого угла, у них есть свои вектора (скорости), да ещё и нужна нормализация для предотвращения &quot;диагонального чита&quot; (как это было у Линка). Собственно весь метод:</p>
  <pre id="ADrG" data-lang="python">def get_player_distance_direction(self, player):
	enemy_vec = pygame.math.Vector2(self.rect.center) #координата врага
	player_vec = pygame.math.Vector2(player.rect.center) #координата Линка
	distance = (player_vec - enemy_vec).magnitude() #Евклидова величина
	if distance &gt; 0:
		direction = (player_vec - enemy_vec).normalize() #вычисление вектора сближения
	else:
		direction = pygame.math.Vector2() #точка, мы друг в друге
	return(distance, direction)</pre>
  <p id="JSax">Я искренне не ожидал, что это <strong>так</strong> просто. По сути, все сложные методы вычисления Евклидовой величины по поиску дистанции мы переложили на функцию <code>magnitude()</code>, а с читерской функцией <code>normalize()</code> вы уже знакомы. И зачем я учил математику? Далее, пропишем метод определения статуса беба по отношению к Линку:</p>
  <pre id="q4FP" data-lang="python">def get_status(self, player):
	distance = self.get_player_distance_direction(player)[0]
	if distance &lt;= self.attack_radius:
		self.status = &#x27;attack&#x27;
	elif distance &lt;= self.notice_radius:
		self.status = &#x27;move&#x27;
	else:
		self.status = &#x27;idle&#x27;</pre>
  <p id="vzFt">Тут мы отсекаем изнутри во вне &quot;окружности&quot; зрения (близко — атака, средняя дистанция — преследование, далеко — idle), но чтобы оно заработало, нам нужно обновлять данные в фале <code>level.py</code>:</p>
  <pre id="g4lb" data-lang="python">def enemy_update(self, player):
	enemy_sprites = [sprite for sprite in self.sprites() if hasattr(sprite,&#x27;sprite_type&#x27;) and sprite.sprite_type == &#x27;enemy&#x27;]
	for enemy in enemy_sprites:
		enemy.enemy_update(player)</pre>
  <p id="HXez">Тут самая интересная строка — строка прорисовывания спрайтов для врага. Тут можно как в анекдоте: &quot;Потерядлся атрибут? Ничего страшного! Всегда есть метод <code>hasattr</code>&quot;. Далее, в run-методе пропишем отрисовку спрайтов врага:</p>
  <pre id="hT3a" data-lang="python">self.visible_sprites.enemy_update(self.player)</pre>
  <p id="3hd9">Теперь мы сможем замкнуть врага на игрока, а игрока на уровень. Для этого пропишем новый метод в <code>enemy.py</code>:</p>
  <pre id="hmT2" data-lang="python">def enemy_update(self, player):
	self.get_status(player)</pre>
  <p id="7n3e">Теперь, у нас есть способ получения методов, но мы с ними не взаимодействуем. Исправим это новым методом:</p>
  <pre id="8Cre" data-lang="python">def actions(self, player):
	if self.status == &#x27;attack&#x27;:
		print(&#x27;attack&#x27;) #тут мы только пишем в терминале атаку
	elif self.status == &#x27;move&#x27;:
		self.direction = self.get_player_distance_direction(player)[1] #нанюхивать Линка
	else:
		self.direction = pygame.math.Vector2() #остановиться по координатам</pre>
  <p id="yzQs">В этом методе всё ровно также как мы работали ранее, но не забудьте закинуть его вызов в <code>enemy_update</code>-функцию командой <code>self.actions(player)</code>. Тетерь пропишем анимацию. Она полностью аналогична анимации Линка:</p>
  <pre id="NUI7" data-lang="python">def animate(self):
	animation = self.animations[self.status]
	self.frame_index += self.animation_speed
	if self.frame_index &gt;= len(animation):
		self.frame_index = 0
	self.image = animation[int(self.frame_index)]
	self.rect = self.image.get_rect(center = self.hitbox.center)</pre>
  <p id="g0MX">Также, добавьте animate в update-функцию. Теперь можно получить ачивку: &quot;Собрал всех чушпанов с района&quot;:</p>
  <figure id="85sF" class="m_original">
    <img src="https://habrastorage.org/r/w1560/webt/qz/kv/np/qzkvnpmic_-_zq9edveqno6-dhg.png" width="1560" />
  </figure>
  <p id="hTMu">Но есть проблема. Они атакуют несчастного Линка толпой без остановки. Это нужно исправить, а значит время нового метода и нового кулдауна. Для начала, я добавил нового демона <code>self.can_attack = True</code>. Это флаг, который будет указывать на то, что беб может пнуть Линка. Соответственно, нужно подправить условие атаки и помимо дистанции, указать данный флаг. Если вы добавили флаг на <code>True</code>, то обязательно сразу нужно прописать ситуацию, когда он будет опускаться (положение <code>False</code>). Запишем этот пункт в методе анимации:</p>
  <pre id="cfcp" data-lang="python">if self.frame_index &gt;= len(animation):
	if self.status == &#x27;attack&#x27;:
		self.can_attack = False</pre>
  <p id="7jIg">Немного объясню происходящее. Анимация атаки не должна прерывать анимацию перехода и если мы завершили весь цикл из переходов от картинки к картинке, то только тогда можно менять флаг на опущенное состояние. Простыми словами, все враги могут ударить нас только 1 раз, так как флаг не поднимается обратно. Поднимать тот самый флаг мы будем по кулдауну через паузу. То есть, я дабалвю два демона, которые будут обозначать время атаки и кулдаун после атаки:</p>
  <pre id="11TK" data-lang="python">self.attack_time = None
self.attack_cooldown = 400</pre>
  <p id="x19x">Теперь пропишем сам метод кулдауна по вычислению разницы текущего времени и времени задержки:</p>
  <pre id="fpCm" data-lang="python">def cooldown(self):
	if not self.can_attack:
		current_time = pygame.time.get_ticks()
		if current_time - self.attack_time &gt;= self.attack_cooldown:
			self.can_attack = True</pre>
  <p id="zFoQ">Тут самое главное, не забыть про место старта времени, то есть про установку времени на момент атаки:</p>
  <pre id="tEid" data-lang="python">self.attack_time = pygame.time.get_ticks()</pre>
  <p id="geg5">После этого, не забудьте закинуть метод в update-метод. Результат:</p>
  <figure id="NGQM" class="m_original">
    <img src="https://habrastorage.org/webt/8y/oj/p7/8yojp7whdb3ugbn1mdkc3fxtody.gif" width="600" />
  </figure>
  <p id="P9g7">Мы не закончили работу с врагами, но давайте оставлю <a href="https://disk.yandex.ru/d/R_we7k1uGvTW7Q" target="_blank">бэкап проекта</a> сейчас и в следующей части создадим методы взаимодействия нас с врагами и врагов с нами.</p>
  <h3 id="XH8l">Драки с бебами</h3>
  <p id="sXRd">Итак, для начала создадим два новых демона для атак в <code>level.py</code>:</p>
  <pre id="5AQE" data-lang="python">self.attack_sprites = pygame.sprite.Group() #атакующий спрайт
self.attackable_sprites = pygame.sprite.Group() #атакуемый спрайт</pre>
  <p id="n0EC">Думаю, по названиям понятно, что демоны нужны для обозначения процесса атаки. Дополним метод вызова врагов помимо видимых спрайтов, атакуемыми спрайтами (<code>self.attack_sprites</code>):</p>
  <pre id="RHSt" data-lang="python">Enemy(monster_name, (x, y), [self.visible_sprites, self.attackable_sprites], self.obstacle_sprites)</pre>
  <p id="1LR1">Также, дополним метод <code>create_attack</code> атакующим спрайтом (<code>self.attack_sprites</code>) :</p>
  <pre id="QOvF" data-lang="python">def create_attack(self):
	self.current_attack = Weapon(self.player, [self.visible_sprites, self.attack_sprites])</pre>
  <p id="hOaJ">Далее, пропишем новый метод с логикой атаки игрока:</p>
  <pre id="ivxC" data-lang="python">def player_attack_logic(self):
	if self.attack_sprites:
		for attack_sprites in self.attack_sprites:
			collision_sprites = pygame.sprite.spritecollide(attack_sprites, self.attackable_sprites, False)
			if collision_sprites:
				for target_sprite in collision_sprites:
					target_sprite.kill()</pre>
  <p id="jXzo">Самая интересная строка тут, это строка с методом пайгейма <code>pygame.sprite.spritecollide</code>. Данный метод позволяет удалять спрайт из группы. Первый аргумент функции — спрайты для атаки, второй — группа спрайтов из которой мы будем удалять спрайт, третий — DoKill. Если у DoKill установлено значение <code>True</code>, все спрайты, которые сталкиваются, будут удалены из группы. Далее, в run-методе пропишем наш метод. Исход:</p>
  <figure id="QS3E" class="m_original">
    <img src="https://habrastorage.org/webt/jq/ev/w0/jqevw0gvyg0lioewqm7ddg_pu_k.gif" width="600" />
  </figure>
  <p id="Vz8p">Немного улучшим метод <code>player_attack_logic</code>:</p>
  <pre id="DOVD" data-lang="python">if target_sprite.sprite_type == &#x27;enemy&#x27;:
	target_sprite.get_damage(self.player, attack_sprites.sprite_type)</pre>
  <p id="uWbv">Мы стали сопоставлять наши спрайты по типам. В моём проекте, типов только два (enemy и weapon). Я прописал в файле <code>weapon.py</code> в демоне строку для присваивания ему нового типа:</p>
  <pre id="l4V5" data-lang="python">self.sprite_type = &#x27;weapon&#x27;</pre>
  <p id="d7tn">Далее, нам не нужно удалять врага при ударе. Нам нужно прописывать ему урон от нашего оружия. Собственно, теперь нужно в файле <a href="http://enemy.py/" target="_blank">enemy.py</a> прописать новый метод — <code>get_damage</code>:</p>
  <pre id="GaO0" data-lang="python">def get_damage(player, attack_type):
	if attack_type == &#x27;weapon&#x27;:
	    self.health -= player.get_full_weapon_damage()</pre>
  <p id="vqnG">Тут мы прописываем новый метод (<code>get_full_weapon_damage</code>), который должен высчитывать сумму урона от оружия и от силы самого Линка (прямо как в Dark Souls). Пропишем же данный метод в <code>player.py</code>:</p>
  <pre id="lbKI" data-lang="python">def get_full_weapon_damage(self):
	base_damage = self.stats[&#x27;attack&#x27;] #урон самого Линка
	weapon_damage = weapon_data[self.weapon][&#x27;damage&#x27;] #урон от выбранного оружия
	return base_damage + weapon_damage</pre>
  <p id="nWjN">Тут мы находим и складываем уроны их наших списков. Возможно, тут встанет вопрос: &quot;Зачем так сложно, если у нас только один меч и всё?&quot;. Я хотел бы сделать проект так, чтобы вы могли самостоятельно с ним &quot;поиграться&quot;. Собственно и цель статьи не номинация &quot;Игра года&quot; в The Game Awards, а лишь попытка продемонстрировать работоспособность языка Python как неплохого движка. Ну да вернёмся к коду. Помимо урона, я решил сразу прописать кулдаун оружия и заменил строку:</p>
  <pre id="aL6n" data-lang="python">if current_time - self.attack_time &gt;= self.attack_cooldown</pre>
  <p id="KQK5">На строку:</p>
  <pre id="3rfe" data-lang="python">if current_time - self.attack_time &gt;= self.attack_cooldown + weapon_data[self.weapon][&#x27;cooldown&#x27;]</pre>
  <p id="oyVX">Напишем новый метод в <code>enemy.py</code> на проверку смерти вражины:</p>
  <pre id="5GwH" data-lang="python">def check_death(self):
	if self.health &lt;= 0:
		self.kill()</pre>
  <p id="YjcA">Тут я даже не знаю что ещё подсветить в коде :) Не забудьте добавить данный метод в update-метод. Теперь один удар приводит к смерти врага. Таким образов, PyGame считает, что пока оружие соприкасается с врагом (вызывается метод коллизий), удары наносятся один за другим. Как итог — Линк танк, который уничтожает всё на своём пути. Исправим это. Для начала, создадим новых демонов <code>enemy.py</code>:</p>
  <pre id="s7Tm" data-lang="python">self.vulnerable = True #флаг уязвимости
self.hit_time = None #время удара
self.invincibility_duration = 300 #продолжительность неуязвимости</pre>
  <p id="oWv6">Тут достаточно прозрачные демоны. Важный момент — флаг уязвимости. Если он поднят — враг может получать урон. Теперь встроим их в <code>get_damage</code>:</p>
  <pre id="iWUF" data-lang="python">def get_damage(self, player, attack_type):
	if self.vulnerable:	
		if attack_type == &#x27;weapon&#x27;:
			self.health -= player.get_full_weapon_damage()
		self.hit_time = pygame.time</pre>
  <p id="Y0fl">Далее, необходимо дополнить код cooldown-метода:</p>
  <pre id="B09X" data-lang="python">if not self.vulnerable:
	if current_time - self.hit_time &gt;= self.invincibility_duration:
		self.vulnerable = True</pre>
  <p id="WN8w">Тут, как я говорил ранее, мы сразу добавляем вариацию флага. У нас было место, где флаг опускается и теперь в cooldown-методе он поднимается по истечению указанного времени неуязвимости. Теперь все враги убиваются весьма приятно. Теперь, нужно добавить отбивание врага на дистанцию, которая указана у каждого врага. Создадим ещё метод:</p>
  <pre id="vKBn" data-lang="python">def hit_reaction(self):
	if not self.vulnerable:
		self.direction *= -self.resistance</pre>
  <p id="I1eW">Осталось вычислить положение в методе <code>get_damage</code>:</p>
  <pre id="2NuT" data-lang="python">self.direction = self.get_player_distance_direction(player)[1]</pre>
  <p id="Jk8Z">Теперь добавим мерцание во время удара, чтобы понять что удар был сделан. В PyGame все сигнатуры (синусоидные функции) лежат в диапазоне от -255 до 255, а позиции удобно брать из синусоид, так как интерпретация в Python будет работать на основе степеней (как и любой калькулятор), а затем будет процесс получения точки на синусоиде. Этот процесс я описывал дольше, чем будет писаться метод отображения пульсации:</p>
  <pre id="2qG8" data-lang="python">def wave_value(self):
	value = sin(pygame.time.get_ticks())
	if value &gt;= 0:
		return 255
	else:
		return 0</pre>
  <p id="CSXU">Данный метод написан в <code>entity.py</code>. Не забудьте импортировать sin-метод из библиотеки math. Теперь вызовем данный метод при ударе по врагу в методе <code>animate</code>:</p>
  <pre id="3twl" data-lang="python">if not self.vulnerable:
	alpha = self.wave_value()
	self.image.set_alpha(alpha)
else:
	self.image.set_alpha(255)</pre>
  <p id="XiVQ">Итак, сейчас мы бьём врагов абсолютно верно и можем отследить когда враги атакуют нас (в терминал приходит сообщение &quot;attack&quot;). Осталось сделать метод, который коцает нашего Линка. Пропишем его в <code>level.py</code>:</p>
  <pre id="1YEB" data-lang="python">def damage_player(self, amount, attack_type):
	if self.player.vulnerable:
		self.player.health -= amount
		self.player.vulnerable = False
		self.player.hurt_time = pygame.time.get_ticks()</pre>
  <p id="R2jb">Дополним в <code>create_map</code> в строку вызова врагов нанесение урона Линку:</p>
  <pre id="7CDQ" data-lang="python">Enemy(monster_name, (x, y), [self.visible_sprites, self.attackable_sprites], self.obstacle_sprites, self.damage_player)</pre>
  <p id="vozE">Добавим в Enemy-класс наш новый только созданный параметр (<code>damage_player</code>) и пропишем нового демона — <code>self.damage_player = damage_player</code>. Теперь вместо простого вывода сообщения &quot;attack&quot; выполним вызов нашего метода:</p>
  <pre id="iAw0" data-lang="python">self.damage_player(amount, attack_type)</pre>
  <p id="Ev8d">Добавим параметры таймеров в демонов нашего player-класса:</p>
  <pre id="RnUm" data-lang="python">self.vulnerable = True
self.hurt_time = None
self.invulnerablity_duration = 500</pre>
  <p id="lCl3">Они аналогичны демонам в <code>enemy.py</code>. Далее, традиционно пропишем смену флага в наш кулдаун-метод:</p>
  <pre id="MRqT" data-lang="python">if not self.vulnerable:
	if current_time - self.hurt_time &gt;= self.invulnerablity_duration:
		self.vulnerable = True</pre>
  <p id="KPut">Теперь пропишем наше мерцание. Тут всё также, как и ранее. Прописывать будем в animate-методе:</p>
  <pre id="62m9" data-lang="python">if not self.vulnerable:
	alpha = self.wave_value()
	self.image.set_alpha(alpha)
else:
	self.image.set_alpha(255)</pre>
  <p id="ZBO6">Теперь нам нужно восстанавливать энергию (повторим механику из Dark Souls). Для этого создадим метод <code>energy_recover</code>:</p>
  <pre id="IHAy" data-lang="python">def energy_recover(self):
	if self.energy &lt; self.stats[&#x27;energy&#x27;]:
		self.energy += 0.1
	else:
		self.energy = self.stats[&#x27;energy&#x27;]</pre>
  <p id="sDFP">Далее, пропишем, что при ударе у нас теряется 10 очков стамины, а если её не хватает — атака не проходит:</p>
  <pre id="uKyD" data-lang="python">if keys[pygame.K_SPACE]:
	if self.energy &gt;= 10:
		self.energy -= 10
		self.attacking = True
		self.attack_time = pygame.time.get_ticks()
		self.create_attak()
		self.weapon_attack_sound.play()</pre>
  <p id="iqQ3">Последнее, что я хотел бы сделать — добавить экспу за убийство врага в <code>level.py</code>:</p>
  <pre id="4mGW" data-lang="python">def add_xp(self, amount):
	self.player.exp += amount</pre>
  <p id="9O1P">Добавим этот же метод для <code>create_map</code> в <code>Enemy</code>. Далее, повторим всё, что делали ранее с <code>damage_player</code>.</p>
  <p id="yKo9"><a href="https://disk.yandex.ru/d/fH7ArtoIx-sQSw" target="_blank">Файлы данного шага тут</a> и давайте приступим к последнему шагу — музыке.</p>
  <h3 id="ZfxM">Музыка</h3>
  <p id="ea3q">Мы на финишной прямой. В нашего <code>player.py</code> добавим демонов:</p>
  <pre id="6Vrs" data-lang="python">self.weapon_attack_sound = pygame.mixer.Sound(&#x27;../audio/attack/slash.wav&#x27;)
self.weapon_attack_sound.set_volume(0.4)</pre>
  <p id="MpWC">Первый демон укажет на название файла, а второй на громкость. Далее, вызовем звук при нажатии на клавишу:</p>
  <pre id="EEq5" data-lang="python">self.weapon_attack_sound.play()</pre>
  <p id="Rlp9">Повторим успех с ударом от монстра:</p>
  <pre id="WQZC" data-lang="python">self.hit_sound = pygame.mixer.Sound(&#x27;../audio/attack/claw.wav&#x27;)
self.hit_sound.set_volume(0.4)</pre>
  <pre id="r54I" data-lang="python">self.hit_sound.play()</pre>
  <p id="zZdZ">Данный метод я вызвал в get_damage после успешного попадания. Теперь мы слышим попадания при ударе. А враг? Сейчас сделаем. Добавим ещё пару демонов и вызов:</p>
  <pre id="0D70" data-lang="python">self.attack_sound = pygame.mixer.Sound(monster_info[&#x27;attack_sound&#x27;])
self.attack_sound.set_volume(0.3)</pre>
  <pre id="IrSc" data-lang="python">self.attack_sound.play()</pre>
  <p id="luKT">Вызов функции в методе actions-методе в <code>enemy.py</code>. Осталось только главная музыка игры. Переходим в <code>main.py</code>:</p>
  <pre id="6EcB" data-lang="python">main_sound = pygame.mixer.Sound(&#x27;../audio/main.wav&#x27;)
main_sound.play(loops = -1)</pre>
  <p id="vMDH">Это два новых демона. Отличие только одно — метод <code>play(loops = -1)</code>. Тут мы создаём музыку, которая будет играть снова и снова во время игры и не закончится до выхода.</p>
  <p id="Eo5w">В конце, я забыл, что игра не заканчивается. Я исправил это функцией <code>final</code> в <code>level.py</code>:</p>
  <pre id="dFX5" data-lang="python">def final(self):
	if self.player.health &lt;= 0:
		print(&#x27;\n&#x27;, &#x27;\n&#x27;, &#x27;Линк умер. Хана Хайрулу&#x27;)
		exit()
	if self.player.exp &gt; 5000:
		print(&#x27;\n&#x27;, &#x27;\n&#x27;, &#x27;Линк победил&#x27;)
		exit()</pre>
  <p id="SB5O">Тут всё просто. При получении более 5000 очков — вы победили, менее — проиграли. Ну и конечно, вернул здоровье и энергию на 100%, а экспу на 0. <a href="https://disk.yandex.ru/d/iTkKdIS_vjVurA" target="_blank">Все файлы с доработками оставлю тут</a>. Вот что получилось:</p>
  <figure id="666ab0e8d1b5b66d8de0caa6" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/666ab0e8d1b5b66d8de0caa6"></iframe>
  </figure>
  <h3 id="MkTs">Итоги</h3>
  <p id="4ujC">В результате работы мы создали игру на голом Python только с библиотекой PyGame. Было использовано ещё парочка для обхода директорий, но можно было и без них. Выводы данной статьи, которые я хотел бы сделать не заключаются в том, чтобы подчёркивать мысль о том, что Python скоро заменит C# с Unity и Unreal. Цель статьи — продемонстрировать возможность работы с Python как с движком для программирования игр. В России, я думаю, этот вариант написания игр будет популярен. Не из-за World Of Tanks, который написан на Python, а из-за мультиплатформенности интерпретируемого языка программирования. Данный код я могу спокойно запускать из любой Unix-системы и это круто. Но встаёт пара вопросов:</p>
  <ol id="qGec">
    <li id="AYou"><strong>Насколько сложно написать игру самому с нуля?</strong> Если вы только входите в геймдев и вообще не понимаете что происходит с играми — не используйте питон. Данный сектор сейчас очень узок и вряд ли вы сможете быстро найти работу (как и вообще в геймдеве). Выбирайте Unity. Он проще Unreal Engine, но при этом весьма работоспособен. Если же вы понимаете язык программирования Python и хотите сделать игру — делайте её на Python. Нет смысла выучивать новый язык только для создания игры. Python весьма на многое способен. В качестве доказательств моих слов, могу сослаться на игры написанные на Python, а могу и на 3D-движок, который набирает обороты под название <a href="https://www.harfang3d.com/en_US/" target="_blank">HARFANG</a>. Он ничем не хуже Unity.</li>
    <li id="WQVV"><strong>Ну а как быть с опытом разработчиков?</strong> На Unity и Unreal много пресетов. Это правда. Но и на Python не меньше. Я не геймдевер, как можно было понять из введения в статью. Я системный администратор со знанием Python на +/- Middle-уровне (да простят меня разрабы). Я писал код для оптимизации работы в сетях, а вот с играми знаком только как игрок со стажем или программист крестиков-ноликов. Всё что я сделал — я начал изучать вопрос. И каково было моё удивление в том, что есть куча людей, которые помогают написать игру на Python. Лично я пользовался гайдами от <a href="https://www.youtube.com/@ClearCode" target="_blank">Clear Code</a> (чувак очень подробно рассказывает на какие библиотеки в PyGame ссылаться), собственно, <a href="https://www.pygame.org/" target="_blank">официальным мануалом по PyGame</a> и книгой Making Games with Python &amp; Pygame (внутри базовые математические концепции игр). Эти три элемента позволили мне написать игру меньше чем за месяц.</li>
  </ol>
  <p id="G1Ml">Конечно, мой проект по ПуЗельде можно долго дорабатывать. Можно сделать фон из деревьев, чтобы экран не оставался чёрным, добавить оружия, подбираемых предметов. Можно сделать больших боссов. Можно создать менюшку с перезапуском и выходом из игры. В общем, есть много точек роста. Весь проект я <a href="https://disk.yandex.ru/d/6FQ_XjY2nwg5LQ" target="_blank">оставляю</a> вам на обсуждение и возможные доработки. Надеюсь было интересно! Закончу как один известный выпускник 13 школы.</p>
  <p id="Iawx">Последние коммиты на <a href="https://gitverse.ru/montirovka/The-Legend-of-PyZelda-Breath-of-the-Snakes" target="_blank">GitVerse</a>!</p>
  <p id="fVao">Ииииииииииииииииииииииииии помните! Питон — игривая змея!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/oYL7TTVllqI</guid><link>https://teletype.in/@valerylinkov/oYL7TTVllqI?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/oYL7TTVllqI?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Что такое Flipper и почему он Zero. Разбираемся в тамагочи для гиков руками чайника</title><pubDate>Wed, 30 Oct 2024 15:33:18 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/3e/00/3e004a61-c341-4508-8c8f-07e66bf29e25.png"></media:content><category>EdTech 🎓</category><description><![CDATA[<img src="https://img1.teletype.in/files/8b/28/8b28f2ea-b726-4c3f-a936-385dcef7786e.png"></img>Не так давно, примерно год назад я наконец получил свою долгожданную посылку. Flipper Zero. Для тех кто не знает, Flipper Zero - это небольшое устройство, которое позволяет заниматься всякими весёлыми затеями в жизни. Веселье начинается с Sub-1 GHz антенны и продолжается микро-скриптами для ПК. Интересующихся, прошу под кат.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#oTYG">Приложения</a></li>
      <li class="m_level_1"><a href="#VWnJ">Sub-GHz</a></li>
      <li class="m_level_1"><a href="#RS0F">125 кГц RFID</a></li>
      <li class="m_level_1"><a href="#EEUW">NFC</a></li>
      <li class="m_level_1"><a href="#kB0W">Инфракрасный порт</a></li>
      <li class="m_level_1"><a href="#4msR">GPIO</a></li>
      <li class="m_level_1"><a href="#WogL">iButton</a></li>
      <li class="m_level_1"><a href="#At0p">Bad USB</a></li>
      <li class="m_level_1"><a href="#8uSs">U2F</a></li>
      <li class="m_level_1"><a href="#7FRk">Часы и настройки</a></li>
      <li class="m_level_1"><a href="#sjvB">Прошивки</a></li>
      <li class="m_level_1"><a href="#lQCE">Где, что и как купить?</a></li>
      <li class="m_level_1"><a href="#fvG4">А кому оно надо?</a></li>
    </ul>
  </nav>
  <p id="LaFL">Не так давно, примерно год назад я наконец получил свою долгожданную посылку. Flipper Zero. Для тех кто не знает, Flipper Zero - это небольшое устройство, которое позволяет заниматься всякими весёлыми затеями в жизни. Веселье начинается с Sub-1 GHz антенны и продолжается микро-скриптами для ПК. Интересующихся, прошу под кат.</p>
  <p id="ZD0y">Ваше знакомство буду выполнять в хронологическом порядке разделов в меню самого флипера.</p>
  <h2 id="oTYG">Приложения</h2>
  <figure id="Vl7W" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/73d/d74/591/73dd745915f8b6d87806c599e7fc7038.png" width="512" />
  </figure>
  <p id="W1VO">Я бы не стал выбирать самым основным пунктом данный, так как задача флипера, на мой взгляд, работа с физическим миром вокруг нас, а не программные приколюхи внутри устройства. Как устройство по работе с приложениями - флипер не лучший вариант. Я бы рекомендовал использовать Raspberry Pi или на худой конец Arduino.</p>
  <p id="g5lk">Тем не менее, внутри достаточно много приложений уже написанных прекрасными пользователями интернета. Скажу сразу, я установил себе кастомную прошивку DarkFlipper. Об этом позже.</p>
  <figure id="B5iA" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/4b8/331/0d7/4b83310d7b27b8394fe3dce37b9ba6a2.png" width="512" />
  </figure>
  <figure id="RuIN" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/86f/a75/092/86fa7509290b5c63c6f21314003b130a.png" width="512" />
  </figure>
  <p id="NU6x">Из предустановок - 8-битные игры типа DOOM, надстройки для распиновки GPIO, аудио-проигрыватель, калькуляторы и доп. приложения и доп. приложения для антенны в 1 ГГц.</p>
  <figure id="wEBq" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/85a/397/406/85a39740622b5ccf423105dcd29c0edc.png" width="512" />
  </figure>
  <p id="FRr4">Повторюсь, данный раздел совсем не самый интересный.</p>
  <h2 id="VWnJ">Sub-GHz</h2>
  <figure id="M4W0" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/343/c53/140/343c5314012d64674b326e531f58a939.png" width="512" />
  </figure>
  <p id="M8lP">Тут всё просто. В диапазоне от 300 до 928 МГц в AM и FM модификациях можно сканировать все сырые и не сырые данные.</p>
  <figure id="tZUH" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c6/75b/3db/2c675b3db2068f28eae9f80ee48428f4.png" width="512" />
  </figure>
  <figure id="krHt" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b22/e80/2b2/b22e802b2a051671be24e39901b8c5e6.png" width="512" />
  </figure>
  <p id="uAc8">Для тех, кто не очень понимает зачем, могу привести простой пример - коды шлагбаумов. В данном диапазоне передаются данные в шлагбаумы. Как пример, я смог скопировать свой ключ от шлагбаума. Любых шлагбаумов и ворот.</p>
  <p id="1Cke">Как это можно реализовать? Расскажу свою историю. Я живу в центре города, где есть такое поверие: &quot;нет шлагбаума - нет парковки&quot;. Живя в уникальном, не побоюсь этого слова, доме, где в один небольшой двор размером с небольшой &quot;плевочек&quot; с детской площадкой и местом для парковки примерно на 30 машин установили аж 3 шлагбаума. Три, Карл!</p>
  <p id="ujyH">Боль данного пункта заключается в том, что шлагбаумы были установлены трёх разных фирм, трёх разных диапазонов, да ещё и двух типов закрытия. Будучи законопослушным гражданином, я решил запросить данный пульт для парковки своего авто. Позвонив по номерам, которые были упорно замазаны на шлагбауме, я попал не много, не мало в город Реутов (сам нахожусь я в Москве). Там, мне сказали, что сделать можно, но без физического ключа - ничего не получится. На вопрос где его добыть, я получил неутешительный ответ: &quot;Не знаю&quot;. Месяц поисков и чудом я выяснил у соседей, что данный ключ находится у &quot;старшей по подъезду&quot; (рубрика &quot;Центр Москвы&quot;). Старшая по подъезду переехала, а подъезд остался. Не ленясь, я дозвонился до данной хозяйки медного шлагбаума. Выяснилось, что данные три шлагбаума были установлены до закона о централизованной установке шлагбаумов и каждый подъезд поставил то что хочет и то как хочет данный аппарат. Каждый шлагбаум - совместная собственность, где все бумаги носит при себе старшая по подъезду. Цирк продолжился. Требования для получения заветного ключа были следующие:</p>
  <ol id="wSF6">
    <li id="9yHV">Заплатить 7 тысяч рублей за вызов бригады (оно и понятно, из Реутова-то ехать)</li>
    <li id="w1qf">Купить резидентную парковку для бесплатной парковки в районе дома, что стоило 3 тысячи рублей в год. Она у меня была, так как ставить машину у дома я не мог.</li>
    <li id="9f2R">Отдать &quot;на сканирование в архив&quot; старшей по подъезду, проживающей в другом доме все документы на машину и меня.</li>
  </ol>
  <p id="I0v7">Если первые два пункта были хотя бы понятны и хоть на сколько-то разумны (хотя сейчас резидентной парковки сейчас у меня нет, так как ставя машину в дворовой территории, она не нужна), то последний пункт меня возмутил. И я бы не против был бы и купить за 10 тысяч &quot;ключик от домика&quot;, даже был бы не против купить данную подписку у женщины, которая поставила данный шлагбаум, ведь благодаря ней, во дворе уменьшилось количество такси и сторонних машин. Но вот отдавать документы куда-то в другой дом незнакомому человеку, как-то не хотелось. Я любезно отказался от данного предложения.</p>
  <p id="6jew">Шаг в сторону парковки подарила мне компания <a href="https://prime-pult.ru/" target="_blank">Прайм Пульт</a>. Вопрос решился просто.</p>
  <figure id="LEgf" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b9a/039/799/b9a039799691be00f6bddeb8b3a373e6.png" width="1920" />
  </figure>
  <p id="Jqls">Кто не понял - это ключ, который копирует сигнал. Нужно было просто понять в каком диапазоне работает ключ. Цена вопроса за 10 ключей была 3 тысячи рублей.</p>
  <p id="j1lC">Зная фирму производителя (в моём случае Nice Flor-S), можно узнать герцовку данного производителя (в моём случае 433,92 МГц). Далее - всё просто.</p>
  <p id="8J9d">Флиппер же помог мне сделать то же самое, но не в отдельном шлагбауме, а на всех трёх простым чтением сырых (RAW) данных. Также, в кастомной прошивке есть подбор ключей по диапазону (приложение находится в отдельной папке в меню Applications).</p>
  <figure id="MICl" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/d41/c14/fe2/d41c14fe2458a80832bbecef04cb4450.png" width="512" />
  </figure>
  <h2 id="RS0F">125 кГц RFID</h2>
  <figure id="wwqO" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/9a9/359/abb/9a9359abb9e85de3a46e7cbad0c7b514.png" width="512" />
  </figure>
  <p id="p4Nx">Переводя с русского на русский, данный раздел нужен для чтения ключей и смарт карт доступа.</p>
  <figure id="5a8H" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/87f/5e7/9fb/87f5e79fb72847a5706936b0c2278c2e.png" width="1020" />
    <figcaption>Ключики на 125 кГц</figcaption>
  </figure>
  <p id="S08p">Данные ключи сейчас активно используются в новостройках для открытия балконов или (простите) комнат для мусора. В многих учреждениях, открывается турникеты для входа в помещения.</p>
  <p id="hyAl">Я работаю в университете и у нас такие же ключи доступа. Как прочитать её - просто. Нажать кнопку &quot;Read&quot; и положить её под флипер. Примерно так:</p>
  <figure id="wsdS" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/901/b1d/877/901b1d877d7c6e48ddb4bce39e8a53d2.png" width="1280" />
  </figure>
  <h2 id="EEUW">NFC</h2>
  <figure id="j8EH" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/4dc/855/e2c/4dc855e2c25c1cd32944ce49261bc447.png" width="512" />
  </figure>
  <p id="I4Br">Аналог ключей, но с большей защитой. Бывает два типа защиты - PSK. В нём - всё также как и в 125 кГц ключах.</p>
  <figure id="645aa928ba194ffbd3482e5b" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645aa928ba194ffbd3482e5b"></iframe>
  </figure>
  <p id="7dMU">Второй вариант - ASK.</p>
  <p id="NrbV">Тут нужно сделать 2 пункта - записать ключ и считыватель. Мужчина на видео по ASK - создатель флипера <strong>Павел Жовнер</strong> <a href="https://habr.com/users/zhovner" target="_blank">@zhovner</a></p>
  <figure id="645aa8e449a83800dcce55b8" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645aa8e449a83800dcce55b8"></iframe>
  </figure>
  <h2 id="kB0W">Инфракрасный порт</h2>
  <figure id="6ta6" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/93c/b81/485/93cb8148574b8fc9f70bfbdb696208f2.png" width="512" />
  </figure>
  <p id="o8zO">Инфракрасный излучатель позволяет управлять всем с ИК-приёмником. Тут справится даже ребёнок. Выбираем универсальный пульт:</p>
  <figure id="mRwA" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/760/014/6aa/7600146aad437f2df9bbe473cbcb83e6.png" width="512" />
  </figure>
  <p id="dxId">Затем, выбираем конкретный тип прибора:</p>
  <figure id="hTI5" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/15b/395/12d/15b39512d413c8d389475b252da7b8da.png" width="512" />
  </figure>
  <p id="sben">Далее, переворачиваем флипер, так чтобы сверху оказался ИК-передатчик и после нажатия на кнопку - отправляются все типы ИК-сигналов.</p>
  <figure id="7qo6" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/d06/ea1/c6e/d06ea1c6e5e598336fb4866951ba3ea1.png" width="512" />
  </figure>
  <h2 id="4msR">GPIO</h2>
  <p id="D0gp">Жаба меня задушила купить Wi-Fi модуль для флипера. По нему не смогу ничего рассказать. Спасибо YouTube за контент.</p>
  <figure id="645aab3b1a7f54fbab01d4bf" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645aab3b1a7f54fbab01d4bf"></iframe>
  </figure>
  <p id="c5ck">Как дополнение, распиновка:</p>
  <figure id="tIE3" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/5d0/07a/000/5d007a000230a8706370666f75690df9.png" width="1680" />
  </figure>
  <h2 id="WogL">iButton</h2>
  <figure id="FUxT" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/5c7/918/f47/5c7918f47c22c02bb1e5e21ce71014e1.png" width="512" />
  </figure>
  <p id="dGYA">Под надписью iButton спрятался сканнер ключей. Работает всё просто. Сканируем ключ на + и - к разным выпирающим точкам:</p>
  <figure id="vyH6" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/303/639/8b6/3036398b6c9786589c0bdbf7c50c7faf.png" width="1680" />
  </figure>
  <p id="lMAi">Далее, эмулируем их же и подносим к домофону:</p>
  <figure id="lQ4y" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/7c7/03d/6f3/7c703d6f30a4dc6ab6338d85134ae414.png" width="1680" />
  </figure>
  <h2 id="At0p">Bad USB</h2>
  <figure id="HgTu" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/c88/34d/d7c/c8834dd7cb1c4d0cb859886d92a145f4.png" width="512" />
  </figure>
  <p id="BNAx">Мой любимый раздел. По умолчанию, доступно всего 2 демо для Mac и Windows. Так как сижу на винде, скриншот вывода:</p>
  <figure id="ZXFe" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/925/5ae/984/9255ae984438164a011db55d6e823dd1.png" width="1426" />
  </figure>
  <p id="7g6t">Конечно, этим всё не заканчивается. Далеко не заканчивается. Из моих любимых уже готовых скриптов под винду на PowerShell - разработка от <a href="https://github.com/I-Am-Jakoby/Flipper-Zero-BadUSB" target="_blank">Jakoby</a>. Там много различных вариаций использования от простой смены обоев, до Wi-Fi стиллера.</p>
  <h2 id="8uSs">U2F</h2>
  <figure id="h4V1" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/507/3bd/07c/5073bd07c58ce9b3809341c4332a8b63.png" width="512" />
  </figure>
  <p id="VvyC">Двухфакторная аутентификация возможна и на флипере. Всё что нужно - подключить его без утилиты qFlipper.</p>
  <p id="DRCk">К слову про qFlipper. Приложение можно скачать <a href="https://flipperzero.one/update" target="_blank">здесь</a>. Смысл приложения прост - работа со сторонним устройством (ПК или же телефоном). Также есть работа через блютуз.</p>
  <figure id="c28q" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/7f3/341/c00/7f3341c00adfd7216f1b0f67f4be32d2.png" width="1724" />
    <figcaption>Десктопное приложение</figcaption>
  </figure>
  <figure id="2tZQ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/dae/ee6/146/daeee61460c77bb6e0a359366386bd79.png" width="591" />
    <figcaption>Мобильное приложение</figcaption>
  </figure>
  <h2 id="7FRk">Часы и настройки</h2>
  <figure id="qHYZ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b5f/39a/5ba/b5f39a5baa861905cd900ba7f68b2f60.png" width="512" />
  </figure>
  <p id="ZaYH">Тут что-то добавить сложно. Часы необходимы, если хотите узнать время, а в настройках можно доработать ваш флипер.</p>
  <h2 id="sjvB">Прошивки</h2>
  <p id="S9O7">Из моих фаворитов кастомных прошивок - <a href="https://github.com/DarkFlippers" target="_blank">DarkFlippers</a>.</p>
  <figure id="ZXNz" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/1af/27a/9eb/1af27a9ebd6794841af531a8fd582c4c.png" width="600" />
  </figure>
  <p id="ZbYV">На мой взгляд, данная прошивка самая стабильная из кастомных. Изменений довольно много. Все они описаны по ссылке на репозиторий гитхаба.</p>
  <p id="pZ59">Второй крутой вариант - вариант от <a href="https://github.com/skizzophrenic/awesome-flipperzero-withModules" target="_blank">TalkingSasquach</a>. Там также есть крутые <a href="https://github.com/skizzophrenic/Talking-Sasquach/tree/main" target="_blank">обои</a> такого типа:</p>
  <figure id="645bddc8d2201800a1b42a7f" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645bddc8d2201800a1b42a7f"></iframe>
  </figure>
  <h2 id="lQCE">Где, что и как купить?</h2>
  <p id="9YW2">Сейчас с поставками флипера сложности. Я свой флипер получил спустя почти год после его официального выхода, как пользователь поддерживающий проект на кикстарте. В комплекте: коробочка, USB type-C, стикер и инструкция по быстрому старту.</p>
  <figure id="1rWp" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/352/8d9/8b6/3528d98b699021085f70740a5f61b13a.png" width="1280" />
  </figure>
  <p id="9QRU">Сам флипер, как сказано в <a href="https://t.me/zhovner_hub" target="_blank">официальном телеграмм-канале Павла</a>, купить можно <a href="https://www.joom.com/ru/products/6448f04bf29f0401729eed7f" target="_blank">через Joom</a>. Всё остальное (чехол, Wi-Fi модуль, плату) можно купить в <a href="https://amperka.ru/search?q=flipper+zero" target="_blank">Амперке</a>.</p>
  <h2 id="fvG4">А кому оно надо?</h2>
  <p id="NMBU">Как итог моего использования, могу сказать следующее (учтите, это только моё мнение): устройство прикольное, но нужно &quot;понимающим&quot; пользователям или тем, у кого много ключ-карт и всякого рода пультов.</p>
  <p id="uBsV">В реальной жизни я использовал флипер порой и веселее включая кондиционеры и проекторы в кабинетах, где оно всё терялось. Ну и конечно, убивалка времени - классная. Лично для меня - устройство очень удобно и главное - приятно. Однако, есть два момента. Первый - я гик и кайфую с этого. Второй - купил я устройство в хорошие годы за 8 000 - 10 000 тысяч рублей (в зависимости от курса банка за евробаксы). Особые весельчаки взламывают лючки теслы.</p>
  <figure id="645be2a37942b7fb9d1cc755" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645be2a37942b7fb9d1cc755"></iframe>
  </figure>
  <p id="s8Rp">Потенциал у устройства есть. Об этом потенциале говорит Линус Себастьян (канал Linus Tech Tips). По мнению Себастьяна, Flipper Zero — это на самом деле это один из самых универсальных хакерских инструментов, которые когда-либо появлялись на рынке.</p>
  <figure id="645be15a7942b7fb9d1cc675" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/645be15a7942b7fb9d1cc675"></iframe>
  </figure>
  <p id="Ftwp">Как всегда, выбор остаётся за вами. Я же пойду дальше юзать свой флипер и играться с новыми и новыми прошивками.</p>
  <figure id="NbfL" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b48/b20/000/b48b200003362d379c3b6a7a27b23f23.png" width="512" />
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/k6BVC-BWN-T</guid><link>https://teletype.in/@valerylinkov/k6BVC-BWN-T?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/k6BVC-BWN-T?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Проблематика текущей концепции мировой сетевой инфраструктуры и решение при помощи децентрализованного детерминизма</title><pubDate>Wed, 30 Oct 2024 15:31:17 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/06/42/0642a6bc-7533-458d-afa1-64ba3604222b.png"></media:content><category>Сети 🕸️</category><description><![CDATA[<img src="https://img1.teletype.in/files/cc/eb/cceb262e-7220-49f5-b96a-388ac6495661.png"></img>Пишу вам о наболевшем. О WEB 3.0. Понимаю, что и информация была много где и много разрозненной информации, но в этой статье я постарался рассказать всю основную информацию по всем основным понятиям. Часть из информации понятна мастодонтам в области, часть очень ознакомительна, однако, думаю, информация будет интересна многим и надеюсь весьма понятна. Не будем откладывать вопрос в долгий ящик и приступим.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#Bkgx">Проблематика концепции мировой сети</a></li>
      <li class="m_level_1"><a href="#pGUv">WWW</a></li>
      <li class="m_level_1"><a href="#E3Dr">WEB 1.0</a></li>
      <li class="m_level_1"><a href="#D9W2">WEB 2.0</a></li>
      <li class="m_level_1"><a href="#5DFL">Теория детерминизма</a></li>
      <li class="m_level_1"><a href="#D6DY">Криптовалюта</a></li>
      <li class="m_level_1"><a href="#KNmV">WEB 3.0</a></li>
      <li class="m_level_1"><a href="#cQxb">Необходимость WEB 3.0</a></li>
      <li class="m_level_1"><a href="#i0E1">(Не)возможность WEB 3.0</a></li>
    </ul>
  </nav>
  <p id="VnFs">Пишу вам о наболевшем. О WEB 3.0. Понимаю, что и информация была много где и много разрозненной информации, но в этой статье я постарался рассказать всю основную информацию по всем основным понятиям. Часть из информации понятна мастодонтам в области, часть очень ознакомительна, однако, думаю, информация будет интересна многим и надеюсь весьма понятна. Не будем откладывать вопрос в долгий ящик и приступим.</p>
  <h2 id="Bkgx">Проблематика концепции мировой сети</h2>
  <p id="p5qq">Для обсуждения вопроса мировой сети, нужно дать определение сети, а также сказать о том, как сеть стала мировой паутиной, хотя изначально предполагалась библиотечным хранилищем.</p>
  <p id="pJTo">Информационная сеть – коммуникационная сеть, в которой информация выступает в качестве продукта создания, переработки, хранения и использования. С появлением персональных компьютеров стали широко распространятся компьютерные сети. Начиная с Тима-Бёрнса Ли, более известного как основателя Интернета, была ключевая концепция Интернета как киберпространства. Под киберпространством в данном контексте подразумевается виртуальная реальность, т.е. второй мир как «внутри» компьютеров, так и «внутри» компьютерных сетей. Было понятие сеть и Интернет (от англ. InterNet, где Inter - интернациональная, Net - сеть). Интернет был ключевым разделом в системе связанных воедино устройств. Смысл данного раздела, который получил своё название уже после создания 29 октября 1969 на базе ARPANET, был в хранении, передачи и работе с информацией. Соответственно, было необходимо создать систему, которая будет хранить информацию и прописывать доступ к ней путём иерархических подходов (аутентификации по ассиметричному или же симметричному шифрованию). Концепция разрасталась и ARPANET стал Интернетом, который правильно писать именно с заглавной буквы как название, а не с прописной как устоявшийся объект в реальной жизни.</p>
  <p id="PBAj">Изначальная концепция предполагала, что сеть станет подобием цифровой библиотеки с множеством разветвлений и простыми алгоритмами поиска как по тексту, так и по более сложному содержанию. Можно сказать, что концепция не поменялась, однако на практике нынешний Интернет не используется по назначению и концепция требовала тотального пересмотра и расширения.</p>
  <p id="Yke0">Сейчас не существует общепринятого определения Интернета, поэтому мною дается не само понятие, а концепция, в которой описано какие идеи вкладывали в это создатели сайтов и технологий. Даже само понимание «Отец» Интернета – звучит очень странно. Тим-Бёрнс Ли создал протоколы (правила) работы библиотечной системы отправки и получения данных, пользователи же вместе с инженерами изменили привычную идею (концепцию), после чего родилось новое виденье сети в целом и Интернета в частности.</p>
  <h2 id="pGUv">WWW</h2>
  <p id="hHhm">В сетях и Интернете, в частности, используется аббревиатура Всемирной паутины - WWW или World Wide Web. Всемирная паутина — это распределённая система, предоставляющая доступ к связанным между собой документам, расположенным на различных компьютерах, подключённых к сети Интернет. Для обозначения Всемирной паутины также используют слово веб (англ. <em>web</em> «паутина»). К этому слову мы вернёмся в следующем разделе данной работы.</p>
  <figure id="8qLI" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/d40/7c5/526/d407c5526588cd06ad1fc48a2d62f71b.png" width="1024" />
    <figcaption>Ключевые уровни Интернета</figcaption>
  </figure>
  <p id="SYuN">Мировая паутина представляет из себя сложную систему, и как любую сложную систему её разбили на более простые уровни для удобства работы. Разбитие было названо моделью OSI или ISO, так как читать её можно сверху вниз и снизу вверх, не боясь потерять смысл. Сетевая модель OSI (The Open Systems Interconnection model) — сетевая модель стека (набора) сетевых протоколов OSI/ISO. Сама модель выглядит сейчас концептуально иначе:</p>
  <figure id="ck1F" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/4ba/99b/9ef/4ba99b9ef50ba2e53fe57cd5ce443b60.jpg" width="512" />
    <figcaption>Модель OSI</figcaption>
  </figure>
  <p id="0Z5F">Разница заключается в отступлении от стандартных приложений и протоколов, но переход к новым стандартам логического мышления, дабы открыть доступ инженерам нового времени к созданию совершенно других технологий, которые базировались бы на старой логике. Проблема в том, что модель OSI описывает логистику, а уровни Интернета демонстрируют технологию, разработанную на том или ином уровне. Как бы то ни было, нас волнует технология Всемирной паутины и её концептуальное представление ранее и сейчас.</p>
  <h2 id="E3Dr">WEB 1.0</h2>
  <p id="5DWS">Концепция WEB 1.0 появилась не сразу, а после появления в 2005 году концепции WEB 2.0. С приходом нового устарело то, что было ранее (иными словами, появление WEB 2.0 породило WEB 1.0, как предшественника), и получило своё название на полках истории. О WEB 2.0 мы поговорим в следующем разделе, а про ретроспективно созданную WEB 1.0 необходимо расписать ключевые данные в этом разделе.</p>
  <p id="03UX">WEB 1.0 продлился с 1991 по 2004 год. Работа велась следующим образом: в случае, если был инженер, который хотел поделиться с миром своим сайтом, он писал его самостоятельно и после чего выгружал его на удалённый сервер, затем пользователь, обладающий компьютером и браузером (программный продукт для просмотра страниц в Интернете) на нём, а также купленным у провайдера доступом к Интернету, мог открыть и посмотреть содержимое сайта инженера.</p>
  <figure id="HFOR" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/98c/446/0f3/98c4460f3068a71ef8dd209619dc2d0f.png" width="900" />
    <figcaption>WEB 1.0</figcaption>
  </figure>
  <p id="7kK0">Сайты выглядели тоже весьма посредственно, так как доработка требовала большое количество итерационных действий, и для введения одного нового слова на страницу, приходилось переписывать сайт полностью.</p>
  <figure id="vmr2" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/230/ba3/5cb/230ba35cb6e689ec1ba626407f64485f.jpeg" width="900" />
    <figcaption>Вид сайта WEB 1.0</figcaption>
  </figure>
  <p id="cjL0">Альтернативное название сети WEB 1.0 было Read-Only Web (от англ. только для чтения). Это был ключевой и фатальный недостаток технологии (речь идёт о наборе технологий WEB 1.0, а не о конкретном протоколе), так как люди делились на тех, кто может только писать книги и тех, кто мог только читать. Также было с реальными книгами логично поначалу, но весьма неудобно в результате, так как многие читатели хотели также доработать контент на сайте, написать свой сайт или вообще сделать иной сервис, а сделать это было весьма проблематично. Проблема была не столько в цене (за данную услугу платили неохотно и не много), сколько в отсутствии необходимости и логичности, так как Интернет в то время был малопопулярен с точки зрения самопродвигающейся социальной площадки. Как итог, в WEB 1.0 получилось: отсутствие интерактивности и автоматизации, минимальное участие пользователей в формировании контента и примитивный дизайн.</p>
  <h2 id="D9W2">WEB 2.0</h2>
  <p id="wl5D">Всё поменял Тим О’Райли. В 2005 году американский издатель и активист движения за свободное программное обеспечение опубликовал статью <a href="https://www.oreilly.com/pub/a/web2/archive/what-is-web-20.html" target="_blank">What Is Web 2.0</a>, которая датируется 30 сентября 2005 года. В ней изложены все основные изменения концепции по сравнению с WEB 1.0. К основным изменениям относят: пользователи могут сами участвовать в жизни Интернета и наполнять его контентом, появились тренды на рынке и крупные корпорации стали их негласными законодателями (всё это произошло в результате капиталистического подхода к сетям), исходя из предыдущего пункта, пользовательские данные стали «товаром» для рекламодателей. Ключевой неизменный пункт - информация по-прежнему хранится на единых серверах и выдается по требованию. Схема подключения аналогична схеме ниже.</p>
  <figure id="2H0a" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/1fe/069/773/1fe069773bf9fdd1b95699aea79e285e.png" width="900" />
    <figcaption>WEB 2.0</figcaption>
  </figure>
  <p id="zPKL">Чтобы увидеть сайт исконно WEB 2.0 - откройте сайты типа Instagram.com или, например habr.com. Все пользователи могу писать статьи, выдавать контент и писать комментарии, однако они не стали сетевыми мастерами и не стали владеть индустрией. Сейчас происходит мировой апокалипсис WEB 2.0.</p>
  <p id="9wHE">Апокалипсис можно условно назвать так: &quot;Эра таргетированной рекламы и недостатка приватности&quot;. Произошло это по двум причинам: развитие социальных функций Сети и потеря контроля пользователями своих данных. Как результат: корпорации могут удалять, сохранять, изменять, приватизировать и патентовать любой контент. Для упрощения контроля появилась технология RSS.</p>
  <p id="gIQa">Из определения: RSS (англ. Rich Site Summary — обогащённая сводка сайта) — семейство XML-форматов, предназначенных для описания лент новостей, анонсов статей, изменений в блогах и т. п. Информация из различных источников, представленная в формате RSS, может быть собрана, обработана и представлена пользователю в удобном для него виде специальными программами-агрегаторами или-сервисами.</p>
  <p id="msTP">Таким образом - <strong>все стали знать всё про всех</strong>. Конечно, вопрос в том, что можно не вылезать в Интернет и/или ничего там не выкладывать, но тогда получается жесточайшая цензура путём запугивания людей открытостью их жизни. Появилась ценность приватности. За переписки или фото опубликованные заранее стали платить астрономические суммы.</p>
  <p id="jSXu">Пример от 7 марта 2023 года. Русскоязычные хакеры BlackСat опубликовали в даркнете интимные фото больных раком, после того как группа здравоохранения Пенсильвании отказалась платить выкуп. LVHN заявляет, что этот поступок является отвратительным и жестоким по отношению к пациентам, которые получают лечение от онкологии.</p>
  <p id="Euur">Или другой пример от 23 марта 2022 года. Крупная база данных клиентов «Яндекс.Еды» была опубликована в интернете. В ней указаны местоположение заказчика, электронная почта, номера телефонов и еще несколько строк информации. Самый полный список данных содержит: Ф.И.О; адрес местоположения, этаж, квартира, электронная почта, модель телефона (iOS или Android), код домофона и сумма, потраченная на заказы за последние полгода.</p>
  <p id="SSYz">Проблема сейчас встала очень остро и решение было предложено философским сообществом в далёком 2007 году.</p>
  <h2 id="5DFL">Теория детерминизма</h2>
  <p id="2Yda">Детерминизм — это философское учение о закономерной универсальной взаимосвязи и взаимообусловленности явлений объективной действительности. Понятие &quot;детерминизм&quot; в философском поле сформулировали в древней Греции. Его изучали материалисты-атомисты. Позже, понятие детерминизма начинает приобретать новый смысл — смысл обусловленности — и употребляется в этике для выражения позиции, противостоящей «свободе воли». В XVII веке в период выработки элементарных понятий механики происходит сближение понятия детерминизма и причинности, устанавливается тесная связь категории закономерности и причинности, закладываются основы механистического детерминизма. Успехи механики закрепляют представления об исключительно динамическом характере закономерностей, об универсальности причинной обусловленности.</p>
  <p id="Z4Lv">Таким образом, если извлечь из философского учения нужное для технологий знание, можно извлечь следующую мысль. Детерминизм — это условные рельсы, по которым движется технологический прогресс. Другого варианта, как сделать ровно так как есть сейчас быть не могло и не может. Было только &quot;до&quot; и есть только &quot;после&quot;. На каждое &quot;после&quot; влияет своё &quot;до&quot;.</p>
  <p id="tnaM">Взяв это умозаключение за основу, можно дойти до очень интересных процессов. Например, как появились нейронные сети - вполне объяснимо, однако почему они работают именно так, как работают - понять до сих пор не удаётся. Значит можно изучить всё прошлое и восстановить точную картину вплоть до Иисуса Христа или даже динозавров, лишь при достаточно больших вычислительных мощностях (данная концепция была описана в сериале &quot;Devs&quot;). Раз так, то почему нельзя структурировать данные в детерминистическом поле путём банальной реверс-инженерии рельс жизни? Данные есть, но существует проблема вычислительных мощностей, которые сейчас весьма развиты, но недостаточно для того, чтобы сотворить такое. Итог - развитие квантовых компьютеров, которые кратно быстрее всех ныне изученных компьютеров. В сентябре 2019 года Google удалось достичь квантового превосходства — квантовый компьютер выполнил за 200 секунд вычисления, на которые у мощнейшего обычного компьютера ушло бы 10 тысячелетий. В декабре 2020 года о достижении квантового превосходства заявили и китайские исследователи. Прототип квантового компьютера из Поднебесной сумел за три минуты решить задачу, на которую у самого быстрого в мире компьютера уйдет более 600 млн лет. И снова недостаток мощностей и слишком большая цена разработки. Однако данная проблема целиком и полностью придумана маркетингом.</p>
  <h2 id="D6DY">Криптовалюта</h2>
  <p id="n12O">Кто разогнал и &quot;обжил&quot; квантовый компьютер до скоростей, что описаны выше? Мировой лидер в области IT - копания Google. На момент 26 октября 2006 г.; 22:52 МСК тройка лидеров мирового технологического рынка выглядела так: 1 место. Microsoft ($281,85 млрд), 2 место. Google ($147,77 млрд), 3 место. Cisco ($147,08 млрд). Компании Microsoft и Cisco также применяют технологии квантовых вычислений, и весь мир надеется на их успех. Но он вовсе не нужен. Это было активно продемонстрировано в 2018-19 годах майнингом криптовалют в России и мире. Впервые о добыче цифровой валюты заговорили более десяти лет назад. С того момента курс биткоина вырос в сотни раз, а за криптовалютой начали охотиться тысячи людей со всего мира.</p>
  <p id="q9Z4">Слово «майнинг» (от англ. mining — добыча полезных ископаемых) в контексте финансов и информационных технологий добывается криптовалюта. Майнинг – это добыча цифровой валюты с помощью специального оборудования. Криптовалюта — разновидность цифровой валюты, учёт внутренних расчётных единиц которой обеспечивает децентрализованная платёжная система, работающая в полностью автоматическом режиме.</p>
  <p id="FvDh">Таким образом, майнинг - инструмент добычи некой субстанции, которая не существует в реальной природе, однако стоит реальных денег. Всё дело в вычислительных мощностях. Криптовалюта - цена за вычисление (точнее за железо). Как только в мире появилась реальная цена за железку, на которой работает человек - появилась ферма по майнингу криптовалюты, а соответственно и денег &quot;из воздуха&quot;. Многие люди, которые были далеки от науки, но близки к понятию &quot;деньги&quot; были в диком восторге от идеи и начали создавать фермы валют в каждом подъезде. Итог - дикий прирост биткоина (главной криптовалюты) в несколько раз (см. скриншот ниже).</p>
  <figure id="oXXG" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/f18/509/1f4/f185091f49a549b46ee4ed2aa1645ad1.png" width="1902" />
    <figcaption>Данные с сайта <a href="https://investfunds.ru/indexes/9021/" target="_blank">investfunds.ru</a></figcaption>
  </figure>
  <p id="3xjO">Смысл технологии майнинговых ферм заключался в том, чтобы объединить несколько устройств и благодаря большому количеству мощных устройств добиться большой мощности. В то время, как компании создают одну и супермощную систему – квантовый компьютер. Если же объединить даже двадцатую часть мощностей носимой электроники, получится устройство (или система устройств) в разы, обгоняющая один квантовый компьютер.</p>
  <p id="v9Yl">О чём можно судить, заводя разговор про криптовалютный рынок? Вычислительные мощности необходимы для ряда техник в реальной жизни и бой за очередной капиталистический рынок (теперь под названием &quot;Биткойн&quot;). А что, если применить все эти вычисления не только в Биткойн, но и во все криптовалюты? А что, если объединять не специально созданные фермы, а просто все устройства? Последний iPhone 14 Pro Max мощнее любого компьютера 2007 года. А если их объединить?</p>
  <h2 id="KNmV">WEB 3.0</h2>
  <p id="RIYC">Если объединить все устройства - получится WEB 3.0 или бессерверная архитектура Интернета, более известная как децентрализованная сеть (сеть без почти центра).</p>
  <figure id="ShOf" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/905/234/aa2/905234aa23f868ca588a19f12b1d17e8.png" width="900" />
    <figcaption>WEB 3.0</figcaption>
  </figure>
  <p id="Aqyg">Основные концепции Web 3.0 обозначил руководитель компании Netscape Джейсон Калаканис (Jason Calacanis). Основной проблемой руководитель считает обесценивание ресурсов и сервисов: относительная простота создания сайтов повлияла на возникновение однообразия. Тим О’Райли поддержал в свое время идеи Калаканиса, а также отметил, что Web 3.0 должен выйти за рамки привычного понимания Сети и начать «взаимодействовать с физическим миром».</p>
  <p id="OnN7">Концепция децентрализованного Интернета базируется на следующих идеях:</p>
  <ul id="MfHB">
    <li id="aooV"><strong>Данные хранятся децентрализовано</strong>. Данные хранятся на всех устройствах частично, и никто не может прочитать данные друг друга, так как нет единого центра. Только ссылки друг на друга. Помимо этого - нет ценности красть ссылку, так как вашу можно также без проблем украсть. Отсутствует неравенство систем безопасности.Для примера возьмём две компании. Компания «Один» будет иметь кучу сложных и дорогостоящих устройств (Cisco ASA как межсетевой экран, новейшие маршрутизаторы и т.п.). Компания «Два» будет иметь один самый дешёвый роутер от провайдера. Понятно, что для взлома компании «Один» потребуется гораздо больше времени и сил, однако цена устройств разительно выше, в то время как компания «Два» - лёгкая «добыча». В случае, когда все компании (в том числе «Один» и «Два» работают в одной сети – безопасность будет на одном уровне и иерархии. Для одной компании технологии станут сильно дешевле, для другой – надёжнее.</li>
    <li id="bRPB"><strong>Наполнение контентом - дело человека</strong>. В отсутствии машинных сайтов, сайтов компании - нет разницы в цене и нет отличий в дизайне. Каждый пользователь создаёт свой уникальный контент, а это значит, что будет оплата не за дизайн сайта, а за работу (постоянную работу) дизайнера.В идеальном мире WEB 3.0 – сайты не необходимость, а желание и искусство. Как сейчас стало искусством – картины. Есть именитый художник, а есть начинающий, оба создают работы и оба продают их на условном аукционе и как итог – деньги и слава художнику, чья работа лучше.</li>
    <li id="CgYz"><strong>Открытая архитектура</strong>. Всё, что есть в Интернете не зашифровано, а значит открыто как для преступников, так и для правозащитников. Всё как в жизни.</li>
    <li id="yYhW"><strong>Модерацией контента будут заниматься сообщества</strong>. Правила сообщества - правила участия в нём и публикации в сети сообщества.Наглядный пример предыдущих двух пунктов – открытое общество с членством. Если вы живёте в городе – вы существуете и занимаетесь своими делами. Если вы захотите стать частью какого-то ни было клуба – придётся выполнить ряд его условий. При принадлежности к клубу – будет ряд условий, по которым вы сможете лишиться членства в клубе по внутренним правилам сообщества.</li>
  </ul>
  <figure id="bcHF" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/507/d00/7b1/507d007b14409890db68d13f616fa1a0.png" width="612" />
    <figcaption>Децентрализация наглядно</figcaption>
  </figure>
  <p id="tAYM">В сети можно найти <a href="https://www.seocheckin.com/web-3-0-sites-list/" target="_blank">список</a> сайтов, децентрализованных приложений dApps и сервисов, которые устроены по принципу Web 3.0. Вот некоторые из них:</p>
  <ul id="RV6x">
    <li id="mKxY"><a href="https://decenternet.com/" target="_blank"><strong>Браузер Decenternet</strong></a>. Использует технологию блокчейна для создания бесшовной архитектуры. В нем есть встроенный VPN, он устраняет навязчивую рекламу, обеспечивает более высокую скорость просмотра и не отслеживает поведение пользователей в интернете.</li>
    <li id="sLBM"><a href="https://www.mysterium.network/" target="_blank"><strong>Маркетплейс Mysterium Network</strong></a>. Платформа peer-to-peer, где пользователи могут обмениваться данными. Платформа защищена от несанкционированного доступа, анонимная и зашифрованная, но с удобным интерфейсом для пользователя.</li>
    <li id="8B94"><a href="https://steemit.com/" target="_blank"><strong>Платформа Steemit</strong></a>. Аналог Reddit, где пользователи могут создавать аккаунты и обмениваться сообщениями. Ценный контент вознаграждается криптовалютой Steem.</li>
    <li id="4jMc"><a href="https://www.atlas.work/" target="_blank"><strong>Платформа фрилансеров Atlas Work</strong></a>. Работодатели могут размещать на платформе разные задания и оплачивать их криптовалютой. Алгоритмы машинного обучения предлагают кандидатуры работодателей и исполнителей друг другу.</li>
    <li id="ZT9U"><a href="https://d.tube/" target="_blank"><strong>Платформа для потокового видео DTube</strong></a>. Аналог YouTube: пользователи могут загружать на платформу свои видео. Платформа предлагает инструменты поощрения за загрузки и количество просмотров криптовалютой.</li>
    <li id="gpvY"><a href="https://audius.co/" target="_blank"><strong>Плеер Audius</strong></a>. Сервис позволяет артистам монетизировать музыку с помощью криптовалюты и общаться со своими слушателями.</li>
    <li id="13Be"><a href="https://www.biconomy.io/" target="_blank"><strong>Платежный сервис Biconomy</strong></a>. Предлагает возможность оплаты несколькими криптовалютами, его можно интегрировать в свою систему с помощью API.</li>
    <li id="CBtJ"><a href="https://www.huddle01.com/" target="_blank"><strong>Сервис конференций Huddle01</strong></a>. В нем реализована децентрализованная система видеозвонков — это помогает контролировать нагрузку и улучшает качество конференций.</li>
    <li id="S3eY"><a href="https://brave.com/ru/" target="_blank"><strong>Браузер Brave</strong></a>. В браузер встроена технология быстрого просмотра и блокировки рекламы, есть интеграция с блокчейном и собственная криптовалюта BAT.</li>
    <li id="oQuY"><a href="https://bitpay.com/" target="_blank"><strong>Криптоприложение BitPay</strong></a>. Пользователи могут покупать, хранить, обменивать и тратить криптовалюту. Могут превратить биткоин в доллары и расплачиваться валютой с помощью криптовалютной дебетовой карты.</li>
  </ul>
  <p id="K33N">Для поддержки интернета будущего был создан специальный фонд и инструменты разработчика Web 3.0:</p>
  <ul id="Bj1o">
    <li id="KP6M"><a href="https://web3.foundation/" target="_blank"><strong>Фонд поддержки Web 3.0</strong></a>. Он финансирует проекты, освещает и продвигает их в СМИ, предлагает консультации экспертов.</li>
    <li id="nHpe"><a href="https://moralis.io/" target="_blank"><strong>Платформа для разработки Moralis</strong></a>. Большая часть проектов для блокчейна создана с помощью Moralis.</li>
    <li id="sp94"><a href="https://hardhat.org/" target="_blank"><strong>Платформа для создания приложений Hardhat</strong></a>. Масштабируемая платформа, которая позволяет разработчикам создавать dApps c низкими комиссиями за транзакции без ущерба для безопасности.</li>
    <li id="8CZA"><a href="https://polygon.technology/" target="_blank"><strong>Платформа Polygon</strong></a>. Разные решения для работы с Etherium.</li>
    <li id="DLhQ"><a href="https://consensys.net/" target="_blank"><strong>Инструмент ConsenSys</strong></a>. Позволяет создавать децентрализованные приложения и инструменты для конечных пользователей.</li>
    <li id="keWx"><a href="https://www.koinearth.com/" target="_blank"><strong>Инструмент KoineArth</strong></a>. Помогает преобразовывать физические продукты, материалы и документы в NFT, чтобы отслеживать их по всей цепочке поставок.</li>
  </ul>
  <h2 id="cQxb">Необходимость WEB 3.0</h2>
  <p id="hnUq">Говоря о самой технологии WEB 3.0, технические специалисты начинают впадать в мир грёз о лучшем мире, однако обычным пользователям не понятно, с чем это связано. Связано это с концептуально иным подходом к технологиям. Если объяснить простыми словами, то WEB 3.0 – это технология (или набор технологий), к которому стремилось мировое IT-сообщество. А именно:</p>
  <ul id="0V2m">
    <li id="MJc8">Доступность Интернета. Входной билет в сеть – устройство с антенной или сетевой картой.</li>
    <li id="mMx8">Свобода слова. Свобода всего, так как не будет каких-либо регуляторных инструментов со стороны «крупных игроков» на рынке.</li>
    <li id="MGhv">Полная анонимность и защищённость. Нет разницы в цене устройств и в правилах настройки – тотальная анонимность.</li>
  </ul>
  <h2 id="i0E1">(Не)возможность WEB 3.0</h2>
  <p id="dntO">Данная концепция при всех плюсах, возможности продемонстрированной криптовалютой и выгодах для человечества на пути к мировым идеалам не поддерживается ни одной крупной компанией в мире. Поддержка компании чаще всего выражается в количестве инвестиций. Инвестиции должны приносить обратные инвестиции (откат), а при развитии WEB 3.0 компании потеряют статусность и необходимость и автоматически станут банкротами.</p>
  <p id="MMPf">Обратная сторона медали - не противление идеям, так как многие IT-специалисты готовы работать с WEB 3.0, так как понимают ценность данный технологии для человека и человечества. Итог один - всё в наших руках.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/u0aW3tLQZKS</guid><link>https://teletype.in/@valerylinkov/u0aW3tLQZKS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/u0aW3tLQZKS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Разговор о самих себе или кто такие IT-шники</title><pubDate>Wed, 30 Oct 2024 15:24:28 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/4f/7b/4f7b3f33-b1fc-4501-8b16-19e17fe42aae.png"></media:content><category>Бомбёж 🔥</category><description><![CDATA[<img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/9c1/55d/0b8/9c155d0b89006a333c26ed44df003ebb.jpg"></img>Доброго времени суток, прекрасные покорители гор знаний Хабра! Сегодня я пришёл с размышлениями о простом вопросе к себе - &quot;Кто такой ITшник?&quot;. Вопрос кажется простым, пока не начинаешь его обсуждать. Собственно, я постараюсь начать отвечать на данный вопрос, а что вышло - сейчас расскажу. Милости прошу под кат!]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#EA0Y">Главные файндеры IT профессий</a></li>
      <li class="m_level_1"><a href="#rb22">Карта IT</a></li>
      <li class="m_level_1"><a href="#Z4Pd">Юзверь</a></li>
      <li class="m_level_1"><a href="#vQT0">Эникейщик</a></li>
      <li class="m_level_1"><a href="#Bang">Сетевик</a></li>
      <li class="m_level_1"><a href="#VjS1">ИБшник</a></li>
      <li class="m_level_1"><a href="#sMqh">Хелпдеск</a></li>
      <li class="m_level_1"><a href="#4ciB">Админ</a></li>
      <li class="m_level_1"><a href="#j5eE">Юрист</a></li>
      <li class="m_level_1"><a href="#Qojg">Аналитик</a></li>
      <li class="m_level_1"><a href="#ysT9">Программисты</a></li>
      <li class="m_level_1"><a href="#DU6E">И это всё?!</a></li>
      <li class="m_level_1"><a href="#I3bA">Почему стоит слушать нас?</a></li>
    </ul>
  </nav>
  <p id="2OAh">Доброго времени суток, прекрасные покорители гор знаний! Сегодня я пришёл с размышлениями о простом вопросе к себе - &quot;Кто такой ITшник?&quot;. Вопрос кажется простым, пока не начинаешь его обсуждать. Собственно, я постараюсь начать отвечать на данный вопрос, а что вышло - сейчас расскажу. Милости прошу под кат!</p>
  <figure id="Thmp" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/9c1/55d/0b8/9c155d0b89006a333c26ed44df003ebb.jpg" width="649" />
  </figure>
  <p id="gZCg">Стоит начать с того, откуда взялся вопрос. Мне задала его жена. Она философ. Дело в том, что философы - такие люди, которые задают вопросы про все базовые понятия. Например: &quot;Что такое любовь?&quot;, &quot;В чём смысл смысла?&quot;, &quot;Создатель и Бог - в чём принципиальное отличие?&quot;. В общем, люди интересующиеся миром. И вот как-то раз Настя спросила меня &quot;Валер, а кем ты работаешь?&quot;. Я встал в ступор, услышав такой вопрос от жены. Когда я немного смутившись ответил на вопрос: &quot;Айтишником...&quot;, Настя продолжила: &quot;А кто это?&quot;. Собственно, с результатами я и пришёл.</p>
  <h2 id="EA0Y">Главные файндеры IT профессий</h2>
  <figure id="9Wcc" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/680/46f/597/68046f597f2f4c4510b8b14571f64dad.png" width="640" />
    <figcaption>Валерий Линьков</figcaption>
  </figure>
  <p id="bk2F">Ваш покорный слуга, которые вот уже 7 лет работает в IT сфере и где <s>его</s> (то есть меня) только черти не душили. От эникейщика до ген. директора компании, через инженера ИБ Cisco.</p>
  <figure id="T2CV" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/aca/1bc/1f6/aca1bc1f61c21271a8f1454d580ada7f.png" width="960" />
    <figcaption>Анастасия Линькова</figcaption>
  </figure>
  <p id="aGNe">Моя любимая супруга. Человек, который обожает задавать вопросы, на которые сложно дать простые односложные ответы. Магистр философских наук в МГУ, автор ряда статей по этике и IT-этике.</p>
  <p id="SOSW">Мы поставили себе задачу понять кто такой IT-специалист и выработать какую-то дорожную карту всех IT-шников.</p>
  <p id="tiM1">Необходимо обсудить один момент. Каждый айтишник понимает чем он занимается и чем занимается его коллега, который скажет простую для него фразу: &quot;Ну я на фулстеке с пыхой и явой сижу&quot;. Для обычного человека (даже понимающего английский, что уже не минимум) фраза будет звучать типа &quot;Ну он полностью прокурен сигаретами &quot;Ява&quot;&quot;. И теперь становиться понятно, что человек вообще не от мира сего и делает он что-то нереальное. Когда же обычный человек переспросит чем же занимается его друг, он получит ответ типа &quot;Ну сайты пишу&quot;...</p>
  <figure id="CZ0Z" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/2e9/b05/430/2e9b054304f14d61fca329ab14790e50.png" width="998" />
  </figure>
  <h2 id="rb22">Карта IT</h2>
  <p id="0jtH">Чтобы упростить себе задачу рассказывания, а вам чтения, позвольте продемонстрировать условную карту, которую я позволил себе предположить. Она описывает моё виденье IT. Это не истина, но и не абсолютно далёкая от реальности картина. Схему можно читать сверху вниз и снизу вверх.</p>
  <figure id="kSwN" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/afd/16f/82a/afd16f82ac51bbad4fefe0a248361a4b.png" width="1610" />
    <figcaption>Карта IT</figcaption>
  </figure>
  <p id="8Rsq">Итак, давайте расскажу как устроена схема. Я буду рассказывать про неё снизу вверх.</p>
  <h2 id="Z4Pd">Юзверь</h2>
  <p id="8cSk">Есть обычный человек. Если он не пользуется технологиями он не очень интересен нам, так как мы IT-шники, то есть специалисты Information Technologies (И-информация, Т-технология), работаем с <strong>технологиями</strong>. Когда человек хочет узнать что-то новое, поработать с информацией и он пользуется каким-либо технологическим устройством, он приобретает статус - <em>пользователь.</em></p>
  <p id="dsh1">Пользователи ничего не понимают в IT. И не должны они только пользуются технологиями, которые мы им поставляем. Однако, есть пара оговорок, которые я хотел бы рассказать каждому пользователю, которые читает данную статью. Есть несколько основных пунктов:</p>
  <ol id="5H5J">
    <li id="WywO">Наши услуги стоят <strong>денег</strong>. Пользователи платят IT-шникам не за условное время потраченное на фрилансе (хотя и это тоже), а за своё <strong>знание</strong>. Знание мы получаем не с неба, и применить это большая проблема. Дети с начальной школы идут в программисты, и далеко не все &quot;доходят&quot; до конца обучения в институте. Одно <a href="https://habr.com/ru/post/585718/" target="_blank">ЕГЭ по информатике</a> до сих пор считается одним из самых сложных (после обществознания).</li>
    <li id="NTHj">Вы должны выполнять наши указания в системах <strong>в точности, как мы описали</strong>. Конечно, если хотите, чтобы система работала как надо. Пользователи же, которые не выполняют это условия сразу окрещаются IT-спецами как &quot;<strong>юзверь</strong>&quot; (от слова User - пользователь и зверь).</li>
  </ol>
  <p id="tSkD">Почему я так резок? Сейчас поясню. Первый пункт пошёл от умозаключения: &quot;Ну айтишник - куча бабла из воздуха&quot;. Во-первых, далеко не куча, во-вторых, не из воздуха. Давайте в цифрах.</p>
  <p id="u3Hz">Согласно данным Росстата, по итогам 2021 года средняя заработная плата в Москве составила 111 092 рубля. По промежуточным результатам 2022 года (январь — май) средняя зарплата в Москве составляет <strong>116 354 рубля </strong>(<a href="https://sovcombank.ru/blog/umnii-potrebitel/srednyaya-zarplata-v-moskve-v-2022-godu" target="_blank">источник</a>). Понимаю, что данные очень расплывчаты и могут быть не точны, но тем не менее - чем не мерило? По данным сайта zarplan.com средняя зарплата по должности &#x27;IT-инженер&#x27; составляет <strong>109 857 рублей</strong> (<a href="https://zarplan.com/zarplata/IT-%D0%98%D0%9D%D0%96%D0%95%D0%9D%D0%95%D0%A0/%D0%A0%D0%9E%D0%A1%D0%A1%D0%98%D0%AF/" target="_blank">источник</a>) по Москве. Получается ниже средней. К слову, сам сайт имеет оговорку.</p>
  <blockquote id="ly6f"><strong>Как мы считали</strong>. Средние и медианные зарплаты рассчитаны на основе найденных свежих вакансий с указанной предлагаемой заработной платой. Таким образом, рассчитанные зарплаты характеризуют в большей степени предложение рынка труда (на основе вакансий), а НЕ реальные зарплаты, которые получают работники. Рассчитанные зарплаты имеют приблизительные значения.</blockquote>
  <p id="MBWk">Становится понятно, что всё не так однозначно.</p>
  <p id="OkEm">На счёт юзверей и второго пункта. Мы, конечно, понимаем, что работаем с пользователями, которые не знают как пользоваться новейшими решениями и просим что-то запускать, а что-то не трогать, но юзверь - везде юзверь.</p>
  <p id="Lq5Q">История из реальной практики, которая произошла со мной буквально 2 месяца назад. Меня попросили починить сайт на Битриксе. Сайт работал исправно, но часть функционала была ограничена. Я залез на сайт и понял, что проблема была связана со стилем, который съел этот функционал. Починил и попросил не трогать стилистическое оформление до демонстрации директору (разговаривал с заказчиком в лице <em>маркетолога</em>). Итог - чуть не сломали сайт играя со шрифтами и внося изменения в стиль. Вопрос: <strong>Зачем?!</strong>.</p>
  <p id="qWHb">Юзверь - это не человек, это - состояние души. Когда слушать исполнителя - не важно. И когда можно потестить &quot;как бы систему сломать&quot; и маяться с кучей проблем.</p>
  <figure id="zXLx" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/f45/658/cf3/f45658cf38cc05f3e519ff93e2dc702e.jpeg" width="500" />
    <figcaption>Маркетолог</figcaption>
  </figure>
  <p id="mfKt">Если говорить серьёзно, то пользователи в большинстве своём приятные люди, которые не являются диванными анархистами, а просто хотят получить качественный продукт. Соответственно, наша задача - им помочь.</p>
  <h2 id="vQT0">Эникейщик</h2>
  <p id="vgcF">Первый помощник - это человек-швейцарский нож, более известный как эникейщик. Он способен сделать всё (от настройки ПК, до сборки сервера и написания сайтов). Одна оговорка. Он способен на всё, но <em>плохо</em>. Плохо не в том плане, что человек плохой работник, а в том плане, что он знает IT сферы поверхностно. Потом из эникейщика вырастает специалист в конкретной области, исходя из своих предпочтений.</p>
  <p id="fioF">Эникейщик самый младший специалист в нашей сфере, поэтому его не очень уважают, однако, он - очень важен, так как благодаря ему пользователи понимают что и как делать с созданной нами же системой. Но чаще всего, они завалены бумагой, деталями и работой в целом.</p>
  <figure id="ZA3w" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/58a/928/54c/58a92854c2d775097faee177026035d4.jpeg" width="750" />
    <figcaption>Будни эникейщика</figcaption>
  </figure>
  <h2 id="Bang">Сетевик</h2>
  <p id="cuFf">Самый частый рост эникейщика - это сетевой инженер. Это человек, который работает с передачей информации. Он занимается связкой сетей, их настройкой и общей коммутацией с новыми устройствами и новыми пользователями. Также его задача работать с подключениями всего и вся и настройкой интернета. Сайт он не пишет, он делает его доступным.</p>
  <figure id="Wb9P" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/post_images/62a/116/6d7/62a1166d7c5cacc397bf449309055277.jpg" width="600" />
    <figcaption>Сетевой будда</figcaption>
  </figure>
  <h2 id="VjS1">ИБшник</h2>
  <p id="x7ov">Специалист информационной безопасности. Этого человека также называют хакером. Он работает над технической защитой информации. Как с железом, так и с программами. Профессия своеобразная (к ней я себя причисляю уже давно). Своеобразие в том, что кто-то будет систему защищать, а кто-то прибегнет к древней мудрости: лучшая защита - это нападение, и станет хакером. Хакер - специалист по взлому систем. Ну а сериал про эту прекрасную профессию - <a href="https://habr.com/ru/post/491512/" target="_blank">Мистер Робот</a>. В нём и расскажут как работает специалист по безопасности одной компании.</p>
  <figure id="rfBH" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/875/146/ddc/875146ddc994aef6687731454b517a80.jpeg" width="640" />
    <figcaption>Хакер/ИБшник</figcaption>
  </figure>
  <h2 id="sMqh">Хелпдеск</h2>
  <p id="NeIf">Человек помогающий пользователям уже удалённо и по конкретному вопросу. Грубо говоря эникейщик, но на своей системе. Он выше эникейщика за счёт того, что должен разбираться в конкретной системе и работе с ней. Им посвящён целый сериал - <a href="https://habr.com/ru/post/498766/" target="_blank">Компьютерщики (The IT Crowd)</a>.</p>
  <figure id="pcZP" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/529/b01/8b4/529b018b405084f9106dc997a2fcd621.png" width="1024" />
    <figcaption>Хелпдеск</figcaption>
  </figure>
  <h2 id="4ciB">Админ</h2>
  <p id="UzzE">Сетевой или системный администратор. Человек, занимающийся продумыванием крупных сетей и систем. Он является своего рода архитектором сетей/систем. Если вы являетесь бизнесменом, то ваш прямой путь - к нему. Он поможет и расскажет, что и как делать на старте, рассчитает и расскажет, как сетевику собрать, что он придумал. К слову, про него есть отдельная бесплатная <a href="https://xakep.ru/2020/04/24/admin-howto/" target="_blank">статья в журнале Xakep</a> от вашего покорного слуги.</p>
  <figure id="2nhh" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/3bc/fea/7d4/3bcfea7d4ae7084196b1ee6c7a2b8aef.jpeg" width="600" />
    <figcaption>Будни админа</figcaption>
  </figure>
  <h2 id="j5eE">Юрист</h2>
  <p id="eJO8">IT-юрист, это как обычный юрист, но в сфере IT. Про него все очень часто забывают, но он пусть и не является ITшником, но ни одна крупная IT-компания не может обойтись без него. Вспомните сериал &quot;<a href="https://habr.com/ru/post/498766/" target="_blank">Кремниевая долина</a>&quot; и вам всё станет понятно.</p>
  <figure id="Et6J" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/7ff/6c5/a4e/7ff6c5a4eea1d19e664488778e5fc726.png" width="515" />
    <figcaption>IT-юрист</figcaption>
  </figure>
  <h2 id="Qojg">Аналитик</h2>
  <p id="BRzV">Бизнес-аналитик в IT - очень <s>нудная</s> нужная вещь, так как аналитики занимаются сбором требований от заказчика и передачей этих требований техническим специалистам. Звучит просто, но на деле человек должен понимать и сторону IT, и сторону бизнеса. К слову, есть очень крутой <a href="https://music.yandex.ru/album/12998464?dir=desc&activeTab=about" target="_blank">подкаст</a> о том, кто такие аналитики в айти и как ими стать.</p>
  <figure id="5gVh" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/88c/f36/a42/88cf36a42135a5277cd936e28f1c878d.jpeg" width="640" />
    <figcaption>Аналитики</figcaption>
  </figure>
  <h2 id="ysT9">Программисты</h2>
  <p id="WXr5">Если первый уровень карты я рассказал, то на втором появился мифический объект - <em>программист</em>. Я ни в коем случае не хочу сказать, что программисты лучше остальных ITшников. Нет. Они просто другие. Большинство программистов получили статус &quot;Не от мира сего&quot; и не просто так.</p>
  <p id="uhxk">Во-первых, они учат кучу языков программирования. Не один десяток лет.</p>
  <p id="gZZN">Во-вторых, они чаще других имеют свой язык общения и не только относительно пользователей, но и относительно друг друга.</p>
  <p id="ga0T">В-третьих, программисты работают ближе к информации и дальше от пользователей, а из это вытекает четвёртое и самое главное.</p>
  <p id="tR61"><strong>Программисты способны создать что-то уникальное</strong>. Это не значит, что условный сетевик не может. Каждый человек способен совершить открытие, однако кто-то работает в <strong>располагающей для этого среде</strong>, а кто-то - нет.</p>
  <p id="5OQK">Яркий пример такого расположение - программисты. Они все знают опыт предыдущих поколений, а также умеют создавать что-то новое и ключевой навык - создание. Их также называют разрабами (<s>Deus</s> Devs). У них есть своя внутренняя <a href="https://habr.com/ru/post/499176/" target="_blank">философия</a> и взгляд на жизнь и себя в ней.</p>
  <figure id="Yq0t" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/9d3/db0/bef/9d3db0bef585b53e2e958b9bd8b78188.jpeg" width="1920" />
    <figcaption>Программист в работе</figcaption>
  </figure>
  <h2 id="DU6E">И это всё?!</h2>
  <p id="OiUc">Нет. Далеко не всё. Каждый из перечисленных мной IT-спецов имеют свои собственные разделения и точки роста. Программисты могут знать много языков и разбираться в сетях или вообще уйти в лидов и админов, сетевики часть переходят в белый хакинг, а затем и в чёрный минуя серый, ИБшники могут стать крутыми разрабами нового защитного ПО.</p>
  <p id="6qPU">Очень сложно (я бы сказал невозможно), описать каждого специалиста в одной статье, да и читать это будет очень не просто. Поэтому мы запустили свой подкаст. Лежачий подкаст.</p>
  <figure id="63a8b24c14d7249a467a2e13" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/63a8b24c14d7249a467a2e13"></iframe>
  </figure>
  <p id="sSrI">В нём мы и будем рассказывать более детально про каждого разработчика и я, уважаемые читатели хабра, прошу вас об услуге. Если среди вас есть специалист, который готов поделиться с нами своим опытом в подкасте, пожалуйста, свяжитесь со мной через Хабр. Расскажите свою историю всему миру!</p>
  <figure id="hkv0" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/8b8/d18/148/8b8d18148376eec6be6cc0de6ef8e2be.jpeg" width="704" />
  </figure>
  <h2 id="I3bA">Почему стоит слушать нас?</h2>
  <p id="SG1C">К сожалению, простому человеку сложно понять, кто такой айтишник, однако мы сами, отвечая на вопрос &quot;кем ты работаешь?&quot; чаще всего отвечаем &quot;айтишником&quot;, потому что объяснить всё, что ты делаешь - довольно проблематично. Тут и возникает проблема - айтишник становится мифическим существом. Тем не менее, программист и сетевик - совершенно разные профессии (что было для моей жены открытием). Поэтому хотим простым языком объяснить тем, кто хочет разобраться, кто мы такие и почему не все айтишники умеют писать сайты, ставить винду и чинить принтер</p>
  <p id="IRBh">Я знаю, что есть куча подкастов от разных площадок IT-обучалок. Я сам работаю в ряде из них, поэтому мы и хотели бы работать с вами <strong>без рекламы</strong>, <strong>без &quot;красивых&quot; историй с хеппи-эндом</strong>, <strong>без цензуры</strong> и <strong>без проплаченного мнения</strong>. Как думаете, получится?</p>
  <p id="HDNX">У меня на этом всё! Поздравляю всех наступающим новым 2023 годом и надеюсь в новом году мы сможем плодотворно посотрудничать!</p>
  <p id="e8xf">P.S. Статья была написана не с целью рекламы, а с целью привлечения внимания к проблеме недопонимания IT-профессионалов с рядовыми пользователями. Надеюсь, у меня получилось!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/QqRbFXkvxrH</guid><link>https://teletype.in/@valerylinkov/QqRbFXkvxrH?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/QqRbFXkvxrH?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>ЗаPython'ил ЕГЭ на сотку или почему Python поможет на ЕГЭ</title><pubDate>Wed, 30 Oct 2024 15:22:35 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/b0/7f/b07fb242-cd3b-4e38-bd83-b3076b9c9045.png"></media:content><category>EdTech 🎓</category><description><![CDATA[<img src="https://img3.teletype.in/files/6a/94/6a94d963-e957-4d6e-9154-822db8db2ca7.jpeg"></img>В сегодняшней статье поговорим о насущной для многих выпускников школ теме - ЕГЭ. Да-да-да! Ребят опять посадили на дистант. Пока не ясно на какой период, но уже сейчас можно сказать, что ЕГЭ по информатике будет на компьютерах и его можно зарешать при помощи языка Python.]]></description><content:encoded><![CDATA[
  <nav>
    <ul>
      <li class="m_level_1"><a href="#MuAN">Быстрый перевод из системы в систему</a></li>
      <li class="m_level_1"><a href="#OcMX">Задача 2</a></li>
      <li class="m_level_1"><a href="#c6vq">Задача 5</a></li>
      <li class="m_level_1"><a href="#MGxJ">Задача 6</a></li>
      <li class="m_level_1"><a href="#TW0n">Задача 12</a></li>
      <li class="m_level_1"><a href="#sClC">Задача 14</a></li>
      <li class="m_level_1"><a href="#WhBm">Задача 16</a></li>
      <li class="m_level_1"><a href="#XR9T">Задача 17</a></li>
      <li class="m_level_1"><a href="#lkcm">Задача 19, 20 и 21</a></li>
      <li class="m_level_1"><a href="#hAOH">Задача 22</a></li>
      <li class="m_level_1"><a href="#SHB0"></a></li>
    </ul>
  </nav>
  <p id="4aaX">В сегодняшней статье поговорим о насущной для многих выпускников школ теме - ЕГЭ. Да-да-да! Ребят опять посадили на дистант. Пока не ясно на какой период, но уже сейчас можно сказать, что ЕГЭ по информатике будет на компьютерах и его можно зарешать при помощи языка Python.</p>
  <p id="AxQw">Вот я и подумал, чтобы не получилось как в песне, стоит этим заняться. Я расскажу про все задачи первой части и их решения на примере демо варианта ЕГЭ за октябрь.</p>
  <p id="bbsT">Всех желающих - приглашаю ниже!</p>
  <figure id="VNQP" class="m_column">
    <iframe src="https://music.yandex.ru/iframe/#track/104865829/22622868"></iframe>
  </figure>
  <h3 id="MuAN">Быстрый перевод из системы в систему</h3>
  <p id="dvVG">В Python есть интересные функции <code>bin()</code>, <code>oct()</code> и <code>hex()</code>. Работают данные функции очень просто:</p>
  <pre id="iHbd" data-lang="python">bin(156) #Выводит &#x27;0b10011100&#x27;
oct(156) #Выводит &#x27;0o234&#x27;
hex(156) #Выводит &#x27;0x9c&#x27;</pre>
  <figure id="s6ii" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/107/da0/461/107da0461adeb3a00378a8af32efb01b.png" width="979" />
    <figcaption>Вывод в интерпретационном режиме</figcaption>
  </figure>
  <p id="F0Pt">Как вы видите, выводится строка, где 0b - означает, что число далее в двоичной системе счисления, 0o - в восьмеричной, а 0x - в шестнадцатеричной. Но это стандартные системы, а есть и необычные...</p>
  <p id="96Fq">Давайте посмотрим и на них:</p>
  <pre id="f4rI" data-lang="python">n = int(input()) #Вводим целое число
 
b = &#x27;&#x27; #Формируем пустую строку
 
while n &gt; 0: #Пока число не ноль
    b = str(n % 2) + b #Остатот от деления нужной системы (в нашем сл записываем слева
    n = n // 2 #Целочисленное деление
 
print(b) #Вывод</pre>
  <p id="BHiN">Данная программа будет работать при переводе из десятичной системы счисления в любую до 9, так как у нас нет букв. Давайте добавим буквы:</p>
  <pre id="g6VY" data-lang="python">n = int(input()) #Вводим целое число

b = &#x27;&#x27; #Формируем пустую строку

while n &gt; 0: #Пока число не ноль
    if (n % 21) &gt; 9: #Если остаток от деления больше 9...
        if n % 21 == 10: #... и равен 10...
            b = &#x27;A&#x27; + b #... запишем слева A
        elif n % 21 == 11:#... и равен 11...
            b = &#x27;B&#x27; + b#... запишем слева B

&#x27;&#x27;&#x27;

И так далее, пока не дойдём до системы счисления -1 (я переводил в 21-ную систему и шёл до 20)

&#x27;&#x27;&#x27;

        elif n % 21 == 11:
            b = &#x27;B&#x27; + b
        elif n % 21 == 12:
            b = &#x27;C&#x27; + b
        elif n % 21 == 13:
            b = &#x27;D&#x27; + b
        elif n % 21 == 14:
            b = &#x27;E&#x27; + b
        elif n % 21 == 15:
            b = &#x27;F&#x27; + b
        elif n % 21 == 16:
            b = &#x27;G&#x27; + b
        elif n % 21 == 17:
            b = &#x27;H&#x27; + b
        elif n % 21 == 18:
            b = &#x27;I&#x27; + b
        elif n % 21 == 19:
            b = &#x27;J&#x27; + b
        elif n % 21 == 20:
            b = &#x27;K&#x27; + b
    else: #Иначе (остаток меньше 10)
        b = str(n % 21) + b #Остатот от деления записываем слева
    n = n // 21 #Целочисленное деление

print(b) #Вывод</pre>
  <p id="jND7">Способ объёмен, но понятен. Теперь давайте используем тот же функцию перевода из любой системы счисления в любую:</p>
  <pre id="PZVV" data-lang="python">def convert_base(num, to_base=10, from_base=10):
    # Перевод в десятичную систему
    if isinstance(num, str): # Если число - строка, то ...
        n = int(num, from_base) # ... переводим его в нужную систему счисления
    else: # Если же ввели число, то ...
        n = int(num) # ... просто воспринять его как число
    # Перевод десятичной в &#x27;to_base&#x27; систему
    alphabet = &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot; # Берём алфавит
    if n &lt; to_base: # Если число меньше системы счисления в которую переводить...
        return alphabet[n] # ... вернуть значения номера в алфавите (остаток от деления)
    else: # Иначе...
        return convert_base(n // to_base, to_base) + alphabet[n % to_base] # ... рекурсивно обратиться к функии нахождения остатка</pre>
  <p id="Xpyl">Вызвав функцию вывода <code>print(convert_base(156, 16, 10))</code> мы переведём 156 из 10 в 16 систему счисления, а введя <code>print(convert_base(&#x27;23&#x27;, 21, 4))</code> переведёт 23 из 4-ичной в 21-ичную систему (ответ: B).</p>
  <h3 id="OcMX">Задача 2</h3>
  <p id="ExtS">Все задания беру из первого октябрьского варианта (он же вариант № 9325894) с сайта <a href="https://inf-ege.sdamgia.ru/test?id=9325894" target="_blank">Решу.ЕГЭ</a>.</p>
  <figure id="q5MP" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/f04/f14/09f/f04f1409f50aa91bac10feba607a2a94.png" width="852" />
  </figure>
  <p id="xStM">Решение данной задачи совсем простое: банальный перебор.</p>
  <pre id="vElC" data-lang="python">print(&#x27;y&#x27;, &#x27;x&#x27;, &#x27;z&#x27;, &#x27;F&#x27;) #Напечатаем заголовки таблицы
for y in range(2): #Берём все переменные и меняем их в циклах &#x27;0&#x27; и &#x27;1&#x27;
    for x in range(2):
        for z in range(2):
            for w in range(2):
                F = ((not x or y) == (not z or w)) or (x and w) #Записываем функцию
                print(x, y, z, F) #Выводим результат</pre>
  <p id="iJwg">Результат:</p>
  <figure id="F1Ed" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b44/ac0/029/b44ac002998bf0a69d46315be639eeac.png" width="979" />
  </figure>
  <p id="uteM">Нам вывелась вся таблица истинности (1 = True, 0 = False). Но это не очень удобно. Обратите внимание, что в задании, функция равно 0, так и давайте подправим код:</p>
  <pre id="miRA" data-lang="python">print(&#x27;y&#x27;, &#x27;x&#x27;, &#x27;z&#x27;, &#x27;F&#x27;) #Напечатаем заголовки таблицы
for y in range(2): #Берём все переменные и меняем их в циклах &#x27;0&#x27; и &#x27;1&#x27;
    for x in range(2):
        for z in range(2):
            for w in range(2):
                F = ((not x or y) == (not z or w)) or (x and w) #Записываем функцию
                if not F:
                    print(x, y, z, F) #Выводим результат</pre>
  <p id="bsC7">Результат:</p>
  <figure id="2KnJ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4c/8b9/67c/c4c8b967c54340e337b17eb9732522e8.png" width="979" />
  </figure>
  <p id="JI6b">Далее - простой анализ.</p>
  <h3 id="c6vq">Задача 5</h3>
  <figure id="j2R7" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/61f/6e2/f0d/61f6e2f0dd2f7378ae4aec09e13e578a.png" width="837" />
  </figure>
  <p id="lIHn">Данная задача легко решается простой последовательностью действий в интерпретационном режиме:</p>
  <figure id="7D6H" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/41c/21b/40b/41c21b40ba7779a8d468fc14997e928e.png" width="979" />
  </figure>
  <h3 id="MGxJ">Задача 6</h3>
  <figure id="5CFO" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/4b2/234/efc/4b2234efc992a0cf1aa31496bdbe80d9.png" width="832" />
  </figure>
  <p id="C71S">Перепечатали и получили ответ:</p>
  <pre id="p3cM" data-lang="python">s = 0
k = 1
while s &lt; 66:
    k += 3
    s += k
print(k)</pre>
  <h3 id="TW0n">Задача 12</h3>
  <figure id="M2R7" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/946/931/bca/946931bcacf5d4d827bd9ec29b31f412.png" width="844" />
  </figure>
  <p id="0UFe">В очередной раз, просто заменим слова на код:</p>
  <pre id="Q12T" data-lang="python">a = &#x27;9&#x27; * 1000

while &#x27;999&#x27; in a or &#x27;888&#x27; in a:
    if &#x27;888&#x27; in a:
        a = a.replace(&#x27;888&#x27;, &#x27;9&#x27;, 1)
    else:
        a = a.replace(&#x27;999&#x27;, &#x27;8&#x27;, 1)
print(a)</pre>
  <h3 id="sClC">Задача 14</h3>
  <figure id="QYyD" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b8e/262/971/b8e2629718bb8fd442199a86ccafe479.png" width="827" />
  </figure>
  <p id="8YAk">Компьютер железный, он всё посчитает:</p>
  <pre id="zn02" data-lang="python">a = 4 ** 2020 + 2 ** 2017 - 15
k = 0

while a &gt; 0:
    if a % 2 == 1:
      	k += 1
    a = a // 2
 
print(k)</pre>
  <h3 id="WhBm">Задача 16</h3>
  <figure id="AAq5" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/330/ce4/14c/330ce414cdebc3dff111822d3d5b7a74.png" width="818" />
  </figure>
  <p id="G1hM">Опять же, просто дублируем программу в python:</p>
  <pre id="ckYv" data-lang="python">def F(n):
    if n &gt; 0:
        F(n // 4)
        print(n)
        F (n - 1)
print(F(5))</pre>
  <p id="3pAf">Результат:</p>
  <figure id="THTZ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/5b3/923/b6e/5b3923b6e0eaa7c20fce425235be4fff.png" width="979" />
  </figure>
  <h3 id="XR9T">Задача 17</h3>
  <figure id="Yeaa" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/e54/fc3/46b/e54fc346bc4dc7261e117042af942488.png" width="834" />
  </figure>
  <p id="0r1X">Задача с <a href="https://inf-ege.sdamgia.ru/get_file?id=91146" target="_blank">файлом</a>. Самое сложное - достать данные из файла. Но где наша не пропадала?!</p>
  <pre id="16EQ" data-lang="python">with open(&quot;17.txt&quot;, &quot;r&quot;) as f: #Открыли файл 17.txt для чтения
    text = f.read() #В переменную text запихнули строку целиком
a = text.split(&quot;\n&quot;) #Разбили строку энтерами (\n - знак перехода на новую строку)

k = 0 #Стандартно обнуляем количество
m = -20001 #Так как у нас сумма 2-ух чисел и минимальное равно -10000, то минимум по условию равен -20000, поэтому...

for i in range(len(a)): #Обходим все элементы массива
    if (int(a[i - 1]) % 3 == 0) or (int(a[i]) % 3 == 0): #Условное условие
        k += 1 #Счётчик
        if int(a[i - 1]) + int(a[i]) &gt; m: #Нахождение минимума
            m = int(a[i - 1]) + int(a[i])

print(k, m) #Вывод</pre>
  <p id="PshT">Немного пояснений. Функция with() открывает файл считывает данные при помощи функции read() и закрывает файл. В остальном - задача стандартна.</p>
  <h3 id="lkcm">Задача 19, 20 и 21</h3>
  <p id="165v">Все три задачи - задачи на рекурсию. Задачи идентичны, а вопросы разные. Итак, первая задача:</p>
  <figure id="kSpD" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/05a/add/e7b/05aadde7b07966acfdc62720d88e7288.png" width="837" />
  </figure>
  <p id="QPEA">Пишем рекурсивную функцию и цикл перебора S:</p>
  <pre id="5CQV" data-lang="python">def f(x, y, p): #Рекурсивная функция
    if x + y &gt;= 69 or p &gt; 3: #Условия завершения игры
        return p == 3
    return f(x + 1, y, p + 1) or f(x, y + 1, p + 1) or\
           f(x * 2, y, p + 1) or f(x, y * 3, p + 1) #Варианты действий

for s in range (1, 58 + 1): #Перебор S
    if f(10, s, 1): #Начали с 10 камней
        print(s)
        break</pre>
  <p id="xkTR">Немного пояснений. В рекурсивной функции существует 3 переменные <code>x</code> - число камней в первой куче, <code>y</code> - число камней во второй куче, <code>p</code> - позиция. Позиция рассчитывается по таблице:</p>
  <figure id="e5Pt" class="m_original">
    <img src="https://img3.teletype.in/files/aa/47/aa479817-afbc-45c1-9832-9ba1de51dece.png" width="755" />
  </figure>
  <p id="yUro">Далее - всё по условию задачи.</p>
  <p id="aqUO">Вторая задача на теорию игр:</p>
  <figure id="Erxp" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/1e4/8a7/b0d/1e48a7b0db3f2da08b6a10008b9c1df2.png" width="839" />
  </figure>
  <p id="tR5a">Все отличия в рамке. Ну и код, соответственно, не сильно отличается:</p>
  <pre id="bzMt" data-lang="python">def f(x, y, p): #Рекурсивная функция
    if x + y &gt;= 69 or p &gt; 4: #Условия завершения игры
        return p == 4
    if p % 2 != 0:
        return f(x + 1, y, p + 1) or f(x, y + 1, p + 1) or\
               f(x * 2, y, p + 1) or f(x, y * 3, p + 1) #Варианты действий
    else:
        return f(x + 1, y, p + 1) and f(x, y + 1, p + 1) and\
               f(x * 2, y, p + 1) and f(x, y * 3, p + 1) #Варианты действий


for s in range (1, 58 + 1): #Перебор S
    if f(10, s, 1): #Начали с 10 камней
        print(s)</pre>
  <p id="rxQ0">Отличия:</p>
  <ol id="Qpz2">
    <li id="uYap">Выиграл Петя, соответственно, позиция 4</li>
    <li id="0UlB">Так как Петя не может выиграть за один ход - он выигрывает за 2 хода (and, а не or на нечётных позициях (играх Пети))</li>
    <li id="LqNj">Убрали break, так как нам нужны все S, а не единственный</li>
  </ol>
  <p id="F2MX">Последняя вариация задачи:</p>
  <figure id="n9vy" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/76c/374/be7/76c374be7d9d0601f2a4eb77fc268e30.png" width="836" />
  </figure>
  <p id="XxqC">Сразу код:</p>
  <pre id="UAuX" data-lang="python">def f(x, y, p): #Рекурсивная функция
    if x + y &gt;= 69 or p &gt; 5: #Условия завершения игры
        return p == 3 or p == 5
    if p % 2 == 0:
        return f(x + 1, y, p + 1) or f(x, y + 1, p + 1) or\
               f(x * 2, y, p + 1) or f(x, y * 3, p + 1) #Варианты действий
    else:
        return f(x + 1, y, p + 1) and f(x, y + 1, p + 1) and\
               f(x * 2, y, p + 1) and f(x, y * 3, p + 1) #Варианты действий


for s in range (1, 58 + 1): #Перебор S
    if f(10, s, 1): #Начали с 10 камней
        print(s)</pre>
  <p id="AHMw">Ну и всего лишь 2 отличия:</p>
  <ol id="kfK7">
    <li id="OlCr">Позиции 3 или 5, а не 4, так как выиграл Ваня</li>
    <li id="MVVw">На второй ход выигрывает Ваня и нам нужно or и and поменять. Я заменил только кратность 2.</li>
  </ol>
  <h3 id="hAOH">Задача 22</h3>
  <figure id="Wi9R" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/403/423/618/40342361838fb0db70a6eb3c89e32121.png" width="823" />
  </figure>
  <p id="YfNr">Ctrl+C, Ctrl+V - наше всё! :)</p>
  <pre id="m8OK" data-lang="python">for i in range(1, 100000):
    x = i
    L = 0
    M = 0
    while x &gt; 0 :
        L = L+1
        if (x % 2) != 0:
            M = M + x % 8
        x = x // 8
    if L == 3 and M == 6:
        print(i)</pre>
  <h3 id="SHB0"></h3>
  <figure id="CHaU" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b63/d6a/997/b63d6a9978f92d6ce40be18ce054076e.png" width="836" />
  </figure>
  <p id="kYeU">Итак, код:</p>
  <pre id="vOyy" data-lang="python">def f(x, y):
    if x &gt; y: #Перегнали цель
        return 0
    if x == y:  #Догнали цель
        return 1
    if x &lt; y: #Догоняем цель тремя методами
        return f(x + 1, y) + f(x + 2, y) + f(x * 2, y)

print(f(3, 10) * f(10, 12)) #Прошло через 10, значит догнали 10 и от де догоняем 12</pre>
  <p id="RZSt">Так как в условии задачи мы увеличиваем число, но будем числа &quot;догонять&quot;. Три метода описаны, ну а пройти через 10 - значит дойти до него и идти от него.</p>
  <p id="5rAH">Собственно, это и есть вся первая часть ЕГЭ по информатике решённая на Python.</p>
  <p id="hXLK"><a href="https://github.com/Babaika25/EGE" target="_blank">Ссылка на репозиторий со всеми программами</a>.</p>
  <p id="unhu">Надеюсь, что смог помочь в своей статье выпускникам и готовящимся ;)</p>
  <p id="FMhJ">Остался один вопрос - нужен ли разбор второй части ЕГЭ по информатике на Python? Оставлю этот вопрос на ваше голосование.</p>
  <p id="k08X">Всем удачи!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@valerylinkov/cWbT0W_F3m7</guid><link>https://teletype.in/@valerylinkov/cWbT0W_F3m7?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov</link><comments>https://teletype.in/@valerylinkov/cWbT0W_F3m7?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=valerylinkov#comments</comments><dc:creator>valerylinkov</dc:creator><title>Свойства блочной модели CSS. Объяснение с примерами</title><pubDate>Wed, 30 Oct 2024 15:16:40 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/89/de/89ded829-cf4b-4bae-8ae9-1b9f59ce4853.png"></media:content><category>Гайды 📖</category><description><![CDATA[<img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/da6/fd4/0cc/da6fd40cc3b9707b7d88a30640001681.png"></img>Сегодня я подготовил для вас материал по основам по блочной модели CSS. Безусловно, многие из вас знают о чём идёт речь, но сегодня я постараюсь объяснить прописные истины более понятно и наглядно, что поможет вам создавать веб-сайты, с идеально подходящими друг другу элементами (с точностью до пикселя), и научит более точно использовать свойства размеров, полей, отступов и границ. Итак, всех приглашаю под кат и погнали!]]></description><content:encoded><![CDATA[
  <p id="1tqZ">Сегодня я подготовил для вас материал по основам по блочной модели CSS. Безусловно, многие из вас знают о чём идёт речь, но сегодня я постараюсь объяснить прописные истины более понятно и наглядно, что поможет вам создавать веб-сайты, с идеально подходящими друг другу элементами (с точностью до пикселя), и научит более точно использовать свойства размеров, полей, отступов и границ. Итак, всех приглашаю под кат и погнали!</p>
  <figure id="FcUq" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/da6/fd4/0cc/da6fd40cc3b9707b7d88a30640001681.png" width="1910" />
  </figure>
  <h2 id="bswk">Оглавление</h2>
  <ul id="dPVn">
    <li id="EOyD"><a href="https://habr.com/ru/articles/569530/#1" target="_blank">Зачем изучать блочную модель CSS?</a></li>
    <li id="gaZR"><a href="https://habr.com/ru/articles/569530/#2" target="_blank">Структура блочной модели CSS</a></li>
    <li id="TUXY"><a href="https://habr.com/ru/articles/569530/#3" target="_blank">Свойство Padding</a></li>
    <li id="U4DA"><a href="https://habr.com/ru/articles/569530/#4" target="_blank">Свойство Border</a></li>
    <li id="3IAK"><a href="https://habr.com/ru/articles/569530/#5" target="_blank">Свойство Margin</a></li>
    <li id="e8wL"><a href="https://habr.com/ru/articles/569530/#6" target="_blank">Свойство box-sizing</a></li>
    <li id="ivmy"><a href="https://habr.com/ru/articles/569530/#7" target="_blank">Content-box VS Border-box</a></li>
  </ul>
  <h2 id="jzeC">Зачем изучать блочную модель CSS?</h2>
  <figure id="D2pL" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/80a/2ab/007/80a2ab007f77399939a7f73c7fa11841.png" width="861" />
  </figure>
  <p id="4gwq">Блочная модель CSS состоит из свойств: <strong>box-sizing</strong>, <strong>padding </strong>и <strong>margin</strong>. Если их <strong>не</strong> использовать, то получим что-то похожее ​</p>
  <figure id="ExJw" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/441/f22/b2b/441f22b2b680cafc1e673b08618f896a.png" width="1440" />
    <figcaption>Веб-сайт без полей и отступов</figcaption>
  </figure>
  <p id="F0QO">Но если вы будете правильно использовать свойства блочной модели, ваш сайт будет выглядеть так ​</p>
  <figure id="0Pxe" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/101/189/2bf/1011892bffd572f05ce5f5e7d3152ee7.png" width="1440" />
    <figcaption>Веб-сайт, использующий свойства блочной модели</figcaption>
  </figure>
  <p id="bQgL">Выглядит гораздо более привлекательно, не так ли? Если вы хотите создать свой сайт с точными расчетами, как тот, что указан выше​, то вы попали по адресу. Изучение блочной модели CSS - один из многих способов, которые помогут вам сделать <strong>веб-сайты, идеальные до пикселя.</strong></p>
  <p id="fot8">В этой статье мы поговорим о том, как использовать эти свойства:</p>
  <ul id="N3Ux">
    <li id="mQq0">Padding</li>
    <li id="p1zI">Margin</li>
    <li id="4onX">Border</li>
    <li id="eh38">box-sizing</li>
  </ul>
  <h3 id="3Hbl">Как использовать свойства блочной модели CSS</h3>
  <p id="ITlf">Давайте посмотрим на несколько примеров, где мы можем использовать свойства блочной модели CSS. Мы собираемся проанализировать <strong>сайт, показанный выше. ​</strong></p>
  <p id="2KHG">Давайте внимательнее посмотрим на навигационную панель (<strong>navbar</strong>). Вы можете заметить разницу между примером, в котором используется свойство <strong>padding</strong>, и примером, в котором его нет:</p>
  <figure id="d1qo" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/a8f/ca0/1cb/a8fca01cb333433307765a5e7c1aa93c.png" width="990" />
    <figcaption>Элементы навигационной панели, использующие свойство padding</figcaption>
  </figure>
  <p id="8hZ1">Теперь давайте подробнее рассмотрим <strong>раздел содержимого вместе с кнопками</strong>. Опять же, вы заметите разницу - на правой картинке также используется свойство <strong>padding</strong>.</p>
  <figure id="VrBj" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/f87/f44/4bc/f87f444bc25a0487cb3bd3f7589b80ef.png" width="990" />
    <figcaption>Раздел содержимого, использующий свойство padding</figcaption>
  </figure>
  <h3 id="PaF9">Структура блочной модели CSS</h3>
  <p id="YZ4m">Говоря о блочной модели, стоит воспринимать её как <strong>луковицу</strong>. И эта &quot;луковица&quot; имеет <strong>4 слоя</strong>:</p>
  <ul id="6knM">
    <li id="aIdA"><strong>1</strong> слой: Content</li>
    <li id="zzmg"><strong>2 </strong>слой: Padding</li>
    <li id="SJI0"><strong>3 </strong>слой: Border</li>
    <li id="b6ji"><strong>4 </strong>слой: Margin</li>
  </ul>
  <h3 id="Pac8">1 слой блочной модели: Content</h3>
  <p id="2Hz7">В HTML <strong>все ведет себя как ящик с контентом</strong>. Давайте вставим контент с изображением котенка. ​</p>
  <figure id="65NW" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/d7f/ad8/4a5/d7fad84a50937820fb0b8bd74630fa09.png" width="857" />
    <figcaption>Первый слой</figcaption>
  </figure>
  <h3 id="rjP2">2 слой блочной модели: Padding</h3>
  <p id="OGpu">Следующий слой блочной модели CSS - это слой <strong>заполнения</strong>. Он обертывает наш контент следующим образом ​</p>
  <figure id="AH5u" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/376/abe/18a/376abe18ada076ff3ffe2307366478e7.png" width="857" />
    <figcaption>Второй слой</figcaption>
  </figure>
  <h3 id="24Hp">3 слой блочной модели: Border</h3>
  <p id="zuP3">Следующий слой блочной модели CSS - это <strong>пограничный</strong> слой. Он обертывает наш контент + отступы следующим образом ​</p>
  <figure id="E6bB" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/96f/b54/e3b/96fb54e3b2ef16763c229889efcee4e9.png" width="857" />
    <figcaption>Черная пунктирная линия - граница</figcaption>
  </figure>
  <h4 id="nvIe">4 слой блочной модели: Margin</h4>
  <p id="pZuy">Следующим и последним слоем блочной модели CSS является слой <strong>полей</strong>. Он обертывает наш <strong>контент + отступ + границу </strong>следующим образом<strong> ​</strong></p>
  <figure id="sunK" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/afe/975/404/afe975404bad4c07454385c21b1a6a65.png" width="857" />
    <figcaption>Четвёртый слой</figcaption>
  </figure>
  <p id="YzlL">Итак, давайте посмотрим, как эти свойства работают в проекте.</p>
  <h2 id="FPZ1">Как настроить проект</h2>
  <figure id="OmuL" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/3d0/beb/888/3d0beb888b9f4d6ce66b493c8adcc5af.png" width="748" />
  </figure>
  <p id="gDm2">Это руководство <strong>подходит для всех, в том числе для новичков. </strong>Если вы хотите писать код, выполните следующие действия.</p>
  <h3 id="bPCS">HTML</h3>
  <p id="9dZO">Откройте VS Code или <a href="http://codepen.io/" target="_blank"><u>Codepen.io</u></a> и напишите этот код ​ внутри <strong>тега body:</strong></p>
  <pre id="wBO0" data-lang="html">&lt;div class=&quot;box-1&quot;&gt; Box-1 &lt;/div&gt;</pre>
  <h3 id="wY1D">CSS</h3>
  <p id="Uoh7">Очистите стили нашего браузера по умолчанию ​</p>
  <pre id="pgw4" data-lang="css">* {
  margin: 0px;
  padding: 0px;
  font-family: sans-serif;
}</pre>
  <p id="SDQ2">Теперь давайте стилизуем наш блок ​</p>
  <pre id="9klQ" data-lang="css">.box-1 {
  width: 300px;
  background-color: skyblue;
  font-size: 50px;
}Все готово, приступим к программированию! ​</pre>
  <figure id="6zW0" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b08/993/2b6/b089932b693baad0ed0a7a4c339f2b21.png" width="748" />
  </figure>
  <h2 id="9Iep">Свойство Padding</h2>
  <p id="9Tdv">Но сначала давайте обсудим <strong>практическое использование</strong> свойства padding. Затем мы увидим, как использовать это свойство.</p>
  <p id="IVHV">Обычно я использую отступы, <strong>чтобы оставить пространство между содержимым. </strong>Посмотрите на эту навигационную панель<strong> ​</strong></p>
  <figure id="yEk3" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/37f/a27/d34/37fa27d34c5ad75d1ad98dc60c186b48.png" width="990" />
    <figcaption>Элементы навигационной панели, использующие свойство padding</figcaption>
  </figure>
  <p id="lU4p">Вот вам еще один пример - посмотрите на содержимое ниже с двумя кнопками​</p>
  <figure id="HP5y" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/38d/881/75e/38d88175e0af4548934b11d8002d67fe.png" width="990" />
    <figcaption>раздел содержимого с использованием свойства заполнения</figcaption>
  </figure>
  <h3 id="3ty6">Как использовать свойство padding в CSS</h3>
  <p id="d1wO">Ниже представлены названия четырех свойств заполнения:</p>
  <ul id="U3fi">
    <li id="Jpl8">padding-top</li>
    <li id="dmyC">padding-right</li>
    <li id="NRDr">padding-bottom</li>
    <li id="y3am">padding-left</li>
  </ul>
  <figure id="uToE" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/ba2/497/aff/ba2497affc9e76e15595f55eceb69a76.png" width="748" />
    <figcaption>Свойства padding</figcaption>
  </figure>
  <p id="kwAc">И помните, что отступы - это пространство, которое вы добавляете<strong> поверх </strong>основного контента<strong>:</strong></p>
  <figure id="fPhl" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/142/81f/d03/14281fd03d6f5cfe453e7d8e355aecd3.png" width="857" />
    <figcaption>Второй слой</figcaption>
  </figure>
  <p id="4Zs8">Давайте добавим отступы к нашему контенту. <strong>Область красного цвета - это отступ ​</strong></p>
  <figure id="b80k" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/87e/2ef/291/87e2ef291042ae47b535e05f6fd0341f.gif" width="864" />
    <figcaption>Область красного цвета - это отступ</figcaption>
  </figure>
  <p id="ccYf">Чтобы воссоздать результаты, указанные выше, ​ напишите этот код в свой CSS: ​</p>
  <pre id="Mn1B" data-lang="css">// Padding added on top, right, left, bottom of .box-1

.box-1{
   padding : 100px;
}</pre>
  <p id="I3i5">Откроем консоль разработчика и <strong>перейдем в вычисляемый раздел</strong>:</p>
  <figure id="fi6O" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/279/046/1e5/2790461e5fb59e4e338ceb3d1e1f7075.png" width="1013" />
  </figure>
  <p id="8xnI">В самом центре - <strong>контент</strong>, который <strong>300px</strong> в ширину. Посмотрите, вокруг контента мы добавили <strong>отступы по 100 пикселей</strong>.</p>
  <p id="Y9xh">Давайте попробуем добавить отступ <strong>только к одной стороне нашего контента (только с правой стороны):</strong></p>
  <figure id="anRQ" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/2f6/0b5/a4a/2f60b5a4a605ad5d293cdc3ab693575a.png" width="664" />
    <figcaption>свойство padding-right</figcaption>
  </figure>
  <p id="xbqq">Чтобы воссоздать результаты, указанные выше, ​ напишите этот код в свой CSS: ​</p>
  <pre id="ROoi" data-lang="css">.box-1{
   padding: 0 100px 0 0;
}

// Or you can use ​
.box-1{
   padding-right: 100px;
}</pre>
  <p id="Wsba">Теперь откройте вычисляемый раздел в консоли разработчика ​</p>
  <figure id="KAt1" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/c05/46b/2ad/c0546b2ad017b507d18e461992f3a40e.png" width="995" />
  </figure>
  <p id="hF6X">Посмотрите - отступ в 100 пикселей был добавлен <strong>только с правой стороны</strong> нашего контента, как мы указали.</p>
  <h2 id="FSES">Свойство Border</h2>
  <p id="Byov">Обычно вы будете использовать свойство border при создании<strong> кнопок</strong>. Вот демонстрация GIF ​</p>
  <figure id="0Po7" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/3d0/f8d/6be/3d0f8d6bea300820c57f894a97ffe902.gif" width="480" />
    <figcaption>Кнопки, использующие свойство Border</figcaption>
  </figure>
  <p id="vv9e">Обратите внимание, как появляется <strong>белая рамка</strong> вокруг кнопки, когда наводится указатель мыши на кнопку.</p>
  <h3 id="1sti">Как использовать свойство границы в CSS</h3>
  <p id="9nB9">И помните, <strong>граница</strong> - это пространство, добавленное поверх нашего <strong>контента + отступа</strong>: <strong>​</strong></p>
  <figure id="fY2W" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/499/b6a/ed3/499b6aed3b1bcc5eae2f0dd82b3f134b.png" width="857" />
    <figcaption>Черная пунктирная линия - граница</figcaption>
  </figure>
  <p id="QPCq">Есть три важных <strong>параметра</strong> свойства границы:</p>
  <ul id="FqqC">
    <li id="StlL">border size</li>
    <li id="dhqv">border style: <strong>solid </strong>(сплошная линия)<strong> / dotted </strong>(&quot;точечная&quot; линия)<strong> / dashed </strong>(пунктир)</li>
    <li id="9BxI">border color</li>
  </ul>
  <figure id="zNKa" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/62c/bd4/9a8/62cbd49a8bae6a8a10609880789e3711.png" width="748" />
    <figcaption>Синтаксис свойства границы</figcaption>
  </figure>
  <p id="qvk2">Как я перечислил выше, существует три стиля свойства границы. В этом примере мы будем использовать <strong>пунктирный</strong> стиль:</p>
  <figure id="NYa3" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/ce8/bb7/e10/ce8bb7e104305e0ec9fae8a675086071.png" width="636" />
  </figure>
  <p id="gO5e">Чтобы воссоздать приведенные выше результаты, напишите этот код в своем CSS: ​</p>
  <pre id="vwhw" data-lang="css">.box-1 {
  width: 300px;
  font-size: 50px;
  padding: 50px;
  border: 10px dashed black;
}</pre>
  <p id="w250">Откроем консоль и посмотрим расчеты блочной модели:</p>
  <figure id="ezkg" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/c4e/b1d/e02/c4eb1de02052699611e9b0beae789448.png" width="967" />
  </figure>
  <p id="BCR8">Теперь посмотрите на изображение выше​ - вокруг нашего <strong>контента + отступа</strong> добавлена ​​<strong>граница</strong> 10 пикселей.</p>
  <h2 id="x2oN">Свойство Margin</h2>
  <p id="EBJr">Обычно я использую свойство <strong>margin,</strong> чтобы добавить <strong>отступ</strong> между моим контентом и экраном на макете рабочего стола. Посмотрите на эту гифку:</p>
  <figure id="djL2" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/2ca/496/051/2ca496051674a2495df26a24d322247a.gif" width="680" />
    <figcaption>Добавление отступов на сайт</figcaption>
  </figure>
  <p id="g1vH">Обратите внимание, что я добавил поля к левому и правому краям веб-сайта выше ​</p>
  <p id="iKUc">Вот еще один пример <strong>использования</strong> свойства margin: ​</p>
  <figure id="CcKH" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/218/c16/135/218c1613575c6c333ff577faf88d820b.gif" width="680" />
    <figcaption>Добавление отступов на сайт</figcaption>
  </figure>
  <h3 id="0rcR">Как использовать свойство margin в CSS</h3>
  <p id="egHp">Margin имеет всего четыре <strong>свойства</strong> поля:</p>
  <ul id="eilH">
    <li id="ZqUl">margin-top</li>
    <li id="VNRo">margin-right</li>
    <li id="vwwp">margin-bottom</li>
    <li id="pb3B">margin-left</li>
  </ul>
  <figure id="ij3h" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/1a5/907/703/1a5907703aaff57d313eb8a1d176dbcb.png" width="748" />
    <figcaption>Свойства margin</figcaption>
  </figure>
  <p id="USq6">И помните, <strong>margin</strong> - это пространство, добавленное поверх нашего <strong>контента + отступы </strong>(по padding)<strong> + границы</strong>:</p>
  <figure id="Jq1W" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/b71/23d/68f/b7123d68f7a9ed9a67c56968fe144b1f.png" width="857" />
    <figcaption>Серая область - margin</figcaption>
  </figure>
  <p id="HfCj">Давайте добавим отступ к нашему контенту. Весь наш набор <strong>смещается</strong> из-за <strong>margin</strong>,как в этом GIF: <strong>​</strong></p>
  <figure id="wCG0" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/444/d74/a99/444d74a9902e8a647ffe31b12acdc454.gif" width="876" />
    <figcaption>Смещение</figcaption>
  </figure>
  <p id="ZfVD">Чтобы воссоздать приведенные выше результаты, напишите этот код в своем CSS: ​</p>
  <pre id="fWab" data-lang="css">.box-1 {
  padding: 50px;
  border: 10px dashed black;
  
  margin: 50px;
}</pre>
  <p id="pPnh">Можем еще раз проверить расчеты: ​</p>
  <figure id="ml3s" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/e6b/dc9/e3a/e6bdc9e3a0d52372e809f269320ff88f.png" width="947" />
  </figure>
  <p id="GjhG">Посмотрите, вокруг нашего <strong>контента + отступов + границы</strong> было добавлено поле 50 пикселей .</p>
  <p id="t4VZ">Давайте попробуем добавить <strong>поле</strong> только к одной стороне нашего контента (только левой стороне):</p>
  <figure id="TAWW" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/ec8/a8e/7bf/ec8a8e7bfa6fff9d28db12285f588c07.png" width="636" />
    <figcaption>Свойство margin-left</figcaption>
  </figure>
  <p id="m9f2">Чтобы воссоздать результаты выше, напишите этот код в своем CSS ​</p>
  <pre id="zR4y" data-lang="css">.box-1 {
  padding: 50px;
  border: 10px dashed black;
  margin-left: 50px;
}</pre>
  <p id="wOH2">На консоли мы видим, что <strong>поле</strong> в <strong>50 пикселей</strong> применено только к <strong>левой стороне</strong> ​</p>
  <figure id="Cx9z" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/2c2/c4f/414/2c2c4f4144b5060d4e7add7793213203.png" width="827" />
  </figure>
  <h2 id="lYEJ">Свойство box-sizing</h2>
  <p id="QSmM">Это свойство определяет, как будут рассчитываться поля, отступы и границы. Есть <strong>три типа вычислений</strong> (можно называть их <strong>свойствами</strong>):</p>
  <ul id="jURe">
    <li id="5FV6">border-box</li>
    <li id="yXmV">padding-box</li>
    <li id="tjtY">content-box</li>
  </ul>
  <h4 id="1gnU">Примечание:</h4>
  <p id="jfDT">Мы не будем обсуждать <strong>padding-box</strong>, поскольку его поддерживает только Firefox, и он используется не очень часто.</p>
  <h2 id="kIAJ">В чем разница между content-box и border-box в CSS?</h2>
  <p id="DxwQ">И <strong>border-box</strong>, и <strong>content-box</strong> работают одинаково. Посмотрите на эти изображения: ​</p>
  <figure id="yJZ5" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/5a9/beb/e5c/5a9bebe5c3c39096f10d884886230774.png" width="664" />
    <figcaption>Блоки, использующие свойство border-box</figcaption>
  </figure>
  <figure id="0h4A" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/125/e0d/2a8/125e0d2a8e1942f1a5dfe91d9157a087.png" width="664" />
    <figcaption>Блоки, использующие свойство content-box</figcaption>
  </figure>
  <p id="hUeT">Итак, в чем здесь главное отличие? Разница заметна, когда мы добавляем поля, границу или отступы к нашим блокам.</p>
  <p id="rAl1">Когда мы используем <strong>box-sizing: content-box</strong>, который является значением по умолчанию, он <strong>добавит</strong> поля, отступы и границы <strong>за пределами поля</strong>, например: ​</p>
  <figure id="enf8" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/fac/420/31a/fac42031a3700a153631f6cd2d625c92.gif" width="904" />
    <figcaption>Заполнение применяется стандартно</figcaption>
  </figure>
  <p id="1wiQ">Вы также можете увидеть расчеты здесь: ​</p>
  <figure id="T9Ij" class="m_custom">
    <img src="https://habrastorage.org/r/w1560/getpro/habr/upload_files/1a9/8c6/0ea/1a98c60ea741994d42cd0af6b7c70a00.png" width="664" />
    <figcaption>Расчеты с content-box</figcaption>
  </figure>
  <p id="Ubxh">Это означает, что все может выйти из-под контроля, и вы можете получить неожиданный результат. Это означает, что при таком подходе, будет <strong>сложно создавать адаптивные веб-сайты. </strong>Вместо этого всегда используйте свойство <strong>box-sizing: border-box</strong>.</p>
  <p id="Ou3y">Но когда мы используем свойство <strong>box-sizing: border-box</strong>, оно <strong>добавит</strong> поля, отступы и границы <strong>вовнутрь блока</strong>, например: ​</p>
  <figure id="CJs5" class="m_custom">
    <img src="https://habrastorage.org/getpro/habr/upload_files/5c5/97c/68c/5c597c68cbc63f51d8ec9e41aec1e56d.gif" width="904" />
    <figcaption>Применение вовнутрь блока</figcaption>
  </figure>
  <p id="TAmr">В <strong>box-sizing: border-box</strong> абсолютно точные расчеты HTML - элементов, а это значит, что такой способ является идеальным для создания адаптивных веб-сайтов.</p>
  <p id="Sa2c">Вы также можете поэкспериментировать со значениями - просто используйте этот код: ​</p>
  <pre id="PuxN" data-lang="css">* {
  box-sizing: border-box;
}

/* Or, Write ​ */
* {
  box-sizing: content-box;
}</pre>
  <h2 id="M8uq">Заключение</h2>
  <p id="2DT5">Вот собственно и всё. Для желающих оставлю ссылку на видео-инструкцию к данному уроку от автора (Джоя Шахеба):</p>
  <figure id="610550a7920526a288c7e194" class="m_16x9">
    <iframe src="https://embedd.srv.habr.com/iframe/610550a7920526a288c7e194"></iframe>
  </figure>

]]></content:encoded></item></channel></rss>