Как стать автором
Обновить
75.75
Тензор
Разработчик системы Saby

SQL HowTo: находим «елочку» с помощью центра масс (Advent of Code 2024, Day 14: Restroom Redoubt)

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров1.6K

В этой челлендж-серии статей попробуем использовать PostgreSQL как среду для решения задач Advent of Code 2024.

Возможно, SQL не самый подходящий для этого язык, зато мы рассмотрим его различные возможности, о которых вы могли и не подозревать.

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


Оригинальная постановка задачи и ее перевод:

Advent of Code 2024, Day 14: Restroom Redoubt

--- День 14: Туалетный редут ---

Одному из Историков нужно в туалет; к счастью, вы знаете, что рядом с не посещенным местом в их списке есть туалет, и поэтому вас всех быстро телепортируют прямо в вестибюль штаб-квартиры Пасхального Кролика.

К сожалению, EBHQ, похоже, снова "улучшил" безопасность туалета после вашего последнего визита. Территория за пределами ванной кишит роботами!

Чтобы Историку безопасно добраться до ванной, вам понадобится способ предсказать, где роботы будут в будущем. К счастью, все они, похоже, движутся по кафельному полу по предсказуемым прямым линиям.

Вы создаете список (ваш пазл-вход) всех текущих позиций роботов ( p) и скоростей ( v), по одному роботу в строке. Например:

p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3

Позиция каждого робота задается как , p=x,yгде xпредставляет собой количество плиток, на которые робот отстоит от левой стены, а yпредставляет собой количество плиток от верхней стены (если смотреть сверху). Таким образом, позиция p=0,0означает, что робот находится в верхнем левом углу.

Скорость каждого робота задается как , v=x,yгде xи yзадаются в плитках в секунду. Положительное xзначение означает, что робот движется вправо , а положительное yзначение означает, что робот движется вниз. Таким образом, скорость v=1,-2означает, что каждую секунду робот перемещается 1на плитку вправо и 2на плитку вверх.

Роботы снаружи ванной комнаты находятся в пространстве 101шириной и 103высотой плиток (если смотреть сверху). Однако, в этом примере роботы находятся в пространстве 11шириной и 7высотой.

Роботы хорошо перемещаются друг над другом/под другом (благодаря комбинации пружин, выдвижных ног и квадрокоптеров), поэтому они могут делить одну и ту же плитку и не взаимодействовать друг с другом. Визуально количество роботов на каждой плитке в этом примере выглядит следующим образом:

1.12.......
...........
...........
......11.11
1.1........
.........1.
.......1...

Эти роботы обладают уникальной функцией для максимальной безопасности ванной комнаты: они могут телепортироваться. Когда робот сталкивается с краем пространства, в котором он находится, он вместо этого телепортируется на другую сторону, эффективно огибая края. Вот что p=2,4 v=2,-3делает робот в течение первых нескольких секунд:

Исходное состояние:
...........
...........
...........
...........
..1........
...........
...........

После 1 секунды:
...........
....1......
...........
...........
...........
...........
...........

После 2 секунд:
...........
...........
...........
...........
...........
......1....
...........

После 3 секунд:
...........
...........
........1..
...........
...........
...........
...........

После 4 секунд:
...........
...........
...........
...........
...........
...........
..........1

После 5 секунд:
...........
...........
...........
.1.........
...........
...........
...........

Историк не может ждать долго, поэтому вам не придется долго моделировать роботов. Где будут роботы через 100несколько секунд?

В приведенном выше примере количество роботов на каждой плитке по истечении 100 секунд выглядит следующим образом:

......2..1.
...........
1..........
.11........
.....1.....
...12......
.1....1....

Чтобы определить самую безопасную зону, подсчитайте количество роботов в каждом квадранте через 100 секунд. Роботы, которые находятся точно посередине (по горизонтали или вертикали), не считаются находящимися ни в одном квадранте, поэтому единственные соответствующие роботы:

..... 2..1.
..... .....
1.... .....
           
..... .....
...12 .....
.1... 1....

В этом примере квадранты содержат 134, и 1робот. Умножение их вместе дает общий коэффициент безопасности12 .

Предскажите движение роботов в вашем списке в пространстве 101шириной в плитки и 103высотой в плитки. Каким будет коэффициент безопасности после того, как пройдет ровно 100 секунд?

--- Часть вторая ---

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

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

Часть 1

Описанное в условии свойство "телепортации" робота описывает его поведение на поверхности тора.

Перемещение "по горизонтали" и "по вертикали" на поверхности тора
Перемещение "по горизонтали" и "по вертикали" на поверхности тора

В этом случае координаты каждого робота в любой момент времени легко вычисляются как "остаток от деления на" ширину/высоту площадки:

nx = x + (vx + w) * t) % w

ny = y + (vy + h) * t) % h

Поэтому самое сложное в нашем запросе - аккуратно вычислить количество роботов в каждом из квадрантов:

WITH arena AS (
  SELECT
    11 w
  , 7 h
  , 100 t
)
, bot AS (
  SELECT
    line[1]::bigint x
  , line[2]::bigint y
  , line[3]::bigint vx
  , line[4]::bigint vy
  FROM
    regexp_matches($$
p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3
$$
    , 'p=(\d+),(\d+) v=(-?\d+),(-?\d+)' -- не забываем про возможные отрицательные значения
    , 'g'
    ) line
)
SELECT -- количество роботов в каждом из квадрантов
  count(*) FILTER(WHERE nx < w / 2 AND ny < h / 2) *
  count(*) FILTER(WHERE nx < w / 2 AND ny > h / 2) *
  count(*) FILTER(WHERE nx > w / 2 AND ny < h / 2) *
  count(*) FILTER(WHERE nx > w / 2 AND ny > h / 2)
FROM
  (
    SELECT -- положения роботов в момент времени t
      *
    , (x + (vx + w) * t) % w nx
    , (y + (vy + h) * t) % h ny
    FROM
      bot
    , arena
  ) T;

По условию, ширина и высота площадки нечетны, поэтому w / 2 дает в PostgreSQL результат деления нацело, и для w = 101 вернет результат 50, что как раз и является координатой разделяющей квадранты "средней линии".

Часть 2

Во второй части нас просят найти минимальный номер шага, на котором роботы выстраиваются в изображение-"пасхалку". Минимального, потому что из правил вычисления координат очевидно, что через каждые w * h шагов состояния заведомо повторяются.

Точнее, конечно, через НОК(w, h), но в нашем примере они заранее известны (101 и 103), и взаимно просты, поэтому - произведение.

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

Формула вычисления центра масс
Формула вычисления центра масс

При равных "массах", как в нашем случае, и так не слишком сложная формула становится еще немного попроще.

Переберем все w * h возможных состояний и найдем шаг, на котором достигается минимум "веса" (вычислением квадратного корня для расстояния можно пренебречь):

WITH arena AS (
  SELECT
    11 w
  , 7 h
)
, bot AS (
  SELECT
    line[1]::bigint x
  , line[2]::bigint y
  , line[3]::bigint vx
  , line[4]::bigint vy
  FROM
    regexp_matches($$
p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3
$$
    , 'p=(\d+),(\d+) v=(-?\d+),(-?\d+)'
    , 'g'
    ) line
)
, iter AS (
  SELECT
    t
  , (
      WITH state AS ( -- состояние роботов на момент t
        SELECT
          (x + (vx + w) * t) % w nx
        , (y + (vy + h) * t) % h ny
        FROM
          bot
        , arena
      )
      , center AS ( -- центр масс состояния
        SELECT
          avg(nx) cx
        , avg(ny) cy
        FROM
          state
      )
      SELECT
        sum((nx - cx) ^ 2 + (ny - cy) ^ 2) m -- общая масса системы
      FROM
        state
      , center
    )
  FROM
    arena
  , generate_series(0, w * h - 1) t -- через w * h состояния заведомо повторяются
)
SELECT
  t -- искомый момент
FROM
  iter
ORDER BY
  m -- минимальная масса системы среди всех итераций
LIMIT 1;

На реальных данных, где роботов 500, а возможных состояний 101 * 103 = 10403, моделирование занимает чуть меньше 11 секунд:

Итак, мы получили некоторое значение t - давайте убедимся, что именно оно и дает искомую "пасхалку", подставив его в первый запрос и добавив визуализацию состояния:

...
SELECT
  string_agg(
    CASE WHEN state IS DISTINCT FROM NULL THEN '*' ELSE ' ' END, ''
    ORDER BY x
  ) собираем строку из упорядоченных по x символов
FROM
  ( -- генерируем все клетки
    SELECT
      x
    , y
    FROM
      arena
    , generate_series(0, w - 1) x
    , generate_series(0, h - 1) y
  ) map
LEFT JOIN
  state
    ON (nx, ny) = (x, y)
GROUP BY
  y
ORDER BY
  y; -- выводим строки по порядку

Если мы все сделали правильно, то результат будет примерно таким:

                                              *                                                      
 *    *      *                                    *                                                  
                                                           *                                         
                                                                                                     
                                                                             *                       
                                                                                                     
                                                      *                                              
                      *                                                                              
                                               *                                                     
                     *                                                                   *           
                                                                                                     
    *               *                                                                                
                                                                                                     
             *                                                   *                                 * 
    *     *                                                                   *                      
            *                                                      *                                 
                         *                                                          *                
                              *                                             *                        
                     *                                                                               
                               *                                     *                               
                        *                           *                                                
                                                                                           *         
               *                                 *             *          *                        * 
                                          *                                                         *
                                                  *                                                  
                                                                  *                     *            
                     *                      *                *                            *          
                                                                                                     
                         **           *          *                                                   
*                     *                  *            *                                          *   
                                                    *                                            *   
              *                                                  *                                   
  *                                                                                                  
                                                                                                     
                                                                                                     
                *                                                                                    
            *          *******************************                                               
                       *                             *                                               
                       *                             *                                               
                       *                             *                                               
                       *                             *                                               
                       *              *              *                               *               
                 *     *             ***             *                   *                           
                       *            *****            *                                               
                       *           *******           *                                               
                       *          *********          *                              *   *            
                       *            *****            *                       *                       
                       *           *******           *                                               
                       *          *********          *                                          *    
                       *         ***********         *                     *                         
                       *        *************        *                                               
                       *          *********          *                                               
                       *         ***********         *                    *        *               * 
  *                    *        *************        *                                               
                       *       ***************       *                                               
                       *      *****************      *          *                                    
                       *        *************        *              *                *   *           
                       *       ***************       *   *      *                                    
        *        *     *      *****************      *                                               
             **        *     *******************     *                                               
                       *    *********************    *                                        *      
                       *             ***             *                    *                          
                       *             ***             *                            *                  
                       *             ***             *                                               
          *            *                             *                                               
                       *                             *                                               
                       *                             *                   *            *              
   *                   *                             *                                               
                       *******************************                         *            *        
                                                                                    *                
                                                                        *                           *
                                   *                *                          *                     
                                                                                              *      
                *                                                   *                          **    
    *                                                                             *                  
                                                                         *                           
      * *                                                                                            
*                                                                                                    
                                                                                     *               
                                                               *                           *         
                                                                                   *   *             
                                                                                                     
*                                                                                                    
                                                                      *                              
         *                                                                                           
          *                                                                                          
                *                   *   *                                         *                  
                                                     *                                               
          *                                                                                          
                                                                                                     
        *                                                  *                               *         
                                                                                                     
                                *                                                                    
                        *                                           *                                
                                                                   *                        *        
                                     *                           *                                   
                      *   *                                                                       *  
                                                             *        * *                            
                                                          *                                          
         *                                                                      *                    
                                                                               *                     
                                                                                                     
          *                            *                                                             
Теги:
Хабы:
Всего голосов 13: ↑13 и ↓0+17
Комментарии5

Публикации

Информация

Сайт
saby.ru
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия