Это первый пост из моей продолжающейся серии о Пришествии кода 2017. Я собираюсь описать свои решения, реализованные на JS (ES6+) и Node.js.

TL;DR: в этом посте мы увидим, как читать файлы в Node.js, как использовать цепные вызовы для преобразования данных (аналогично FP, но не без точки), а затем некоторые очень тривиальные алгоритм будет следовать. Проблема здесь очень проста, поэтому я объясню нюансы кода более подробно. В следующих сообщениях мы сосредоточимся только на наиболее интересных частях алгоритмов.

Без долгих вступлений давайте углубимся в первую проблему. Вы можете найти его здесь: http://adventofcode.com/2017/day/1.

Первая часть

Для разогрева участников предлагается очень простая задача: в первой части задачи нужно найти в строке пары одинаковых символов (цифр) и сложить эти цифры. Единственная проблема в том, что последний символ также следует сравнивать с первым. Вход головоломки находится здесь: http://adventofcode.com/2017/day/1/input.

Эта задача не требует особого планирования или разработки алгоритмов, но в последующие дни будут гораздо более сложные и интересные задачи.

Тем не менее, давайте проверим решение:



Сначала нам нужно прочитать ввод и проанализировать его:

const fs = require("fs");                                               const input = fs
  .readFileSync("./input", "utf-8")
  .trim()
  .split("")
  .map(d => parseInt(d, 10));

Обычно вы не будете использовать readFileSync в реальных программах (за некоторыми исключениями), потому что он блокирует единственный поток Node.js и предотвращает выполнение другого кода во время выполнения ввода-вывода. Но для наших задач в любом случае нет другого кода для запуска, так что все в порядке. Один нюанс заключается в том, что если вы хотите прочитать строку, а не буфер, вам нужно передать кодировку (“utf-8”) в качестве второго параметра.

Затем мы используем вызовы в стиле цепочки:

Теперь у нас есть массив, содержащий число (от 0 до 9) для каждой цифры во входном файле. Итак, теперь реальный алгоритм:

const l = input.length;
input.push(input[0]);

let sum = 0;
for (let i = 0; i < l; i++) {
  if (input[i] === input[i + 1]) {
    sum += input[i];
  }
}

console.log(sum);

Сначала я запоминаю длину исходного массива.

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

Итак, наконец, я выполняю императивный цикл над массивом, проверяю равенство и добавляю цифры к кумулятивной сумме, если совпадение найдено.

Наконец, эта сумма может быть записана на выходе.

Часть вторая

Вторая часть задачи немного интереснее.

Теперь нам нужно сопоставить цифры, между которыми находится половина всего (циклического) списка.

Там решение этой проблемы, а ниже объяснение.



Другая часть находится здесь:

const l = input.length;

const next = i => (i + l / 2) % l;

let sum = 0;
for (let i = 0; i < l; i++) {
  if (input[i] === input[next(i)]) {
    sum += input[i];
  }
}

console.log(sum);

На этот раз я не изменяю массив, но определяю вспомогательный метод с именем next. Он вычисляет индекс, который точно больше текущего индекса на l / 2 с учетом циклического характера списка. Для этого мы используем операцию по модулю, представленную оператором % в JavaScript. Это гарантирует, что мы правильно перенесем конец списка. Пример: длина списка 10. Текущий индекс 8. 8 + 10 / 2 = 13. Мы достигли конца списка на 3 элемента, поэтому новый индекс равен 3. Это то же самое, что остаток от 13 при делении на 10.

И затем мы используем эту функцию для построения индекса в массиве для сравнения с текущим значением. Остальной код тот же.

На этом завершаются решения AoC2017 Day 1. Как было сказано в начале, эти проблемы очень простые и могут быть не очень интересны опытным разработчикам, но некоторые из последующих проблем более сложны и приятны для решения. Так что надеюсь увидеть вас снова в следующем посте.

Бонус: Кложур

Те же решения, реализованные в Clojure, полностью повторяющие структуру исходных программ: