AoC 2020, Day 1
I'm trying to get into clojure these days. I'm not new to the lisp land; I maintain a pretty convoluted emacs config.
But I am still a beginner. Besides, clojure is not your typical lisp dialect.
Part One
I tried solving the challenge using Python's for loop. Initially I was
using itertools.combinations_with_replacement
but I felt that it was
unnecessary for something so simple.
def find_2020():
with open("../static/advent-2020-input-day-one.txt") as fi:
numbers = list(map(float, fi.readlines()))
for x in numbers:
for y in numbers:
if x + y == 2020:
return x * y
print(find_2020())
The result: 1016131.0
. The input file: advent-2020-input-day-one.txt
The goal, however, is to do it in Clojure.
So after about a dozen tries, this is what I came up with:
(def x-input [1895 1504 1660 1775 1743 1607 1267 1133 292
1646 1285 1808 1512 1839 1869 1578 1318 1385
1829 1800 1491 1600 1290 1856 1781 1881 1953
2008 1681 1472 1846 2010 1619 1584 1849 1876
1744 1980 1421 911 1308 1762 1398 1470 1974
1902 1985 2001 1926 1374 1678 1523 1894 1597
1778 1940 1362 1613 1629 1473 1633 1867 1838
1931 1850 1776 1689 1311 1947 1988 1779 1381
1683 1677 1675 1587 767 1401 1412 1544 1484
618 1755 1073 1970 1735 1770 1623 1665 1783
1400 1892 1921 1506 1978 1731 1739 1515 1354
1264 1394 1763 1569 1453 1539 2006 1586 1855
1609 1729 1624 506 1668 1803 1486 1767 1720
1753 1994 1718 1922 1314 1250 1516 1546 1625
1708 1286 1993 1785 491 1705 1924 1752 1888
1651 1604 1750 1547 1481 1704 1851 904 1920
1939 1277 1870 1934 1617 1833 1797 1817 1967
1935 1914 1621 1468 1859 1552 1640 1709 1121
1973 1343 1266 1806 1360 1299 1990 1356 1631
1555 1811 1323 1794 1550 1448 1848 1826 1723
1891 1302 1655 947 1580 1908 1641 1816 1701
1871 1588 1843 1643 1893 1866 1628 1417 1795
1995 1937])
(defn is-2020? [v]
(= 2020 (reduce + v)))
(defn find-2020 []
(first
(filter
is-2020?
(for [a x-input b x-input] [a b]))))
This is my solution. There are many like this but this one is mine.
Part Two
Part two revealed itself to let me know that the requirements changed.
I think now is the time to refactor both solutions from part one.
Here's what the python solution looks like now:
import operator as op
import itertools as it
import functools as ft
def find_2020(r):
with open("../static/advent-2020-input-day-one.txt") as fi:
numbers = list(map(float, fi.readlines()))
for items in it.combinations_with_replacement(numbers, r):
if sum(items) == 2020:
return ft.reduce(op.mul, items)
print("Part one: ", find_2020(2))
print("Part two: ", find_2020(3))
I went back to using the itertools
. I went a little bit further and
made the function generic.
Now, it'll be able to adapt similar change in requirements.
Time to redo the Clojure code. It looks like this now:
(ns advent-of-code.core
(:gen-class))
(def numbers [1895 1504 1660 1775 1743 1607 1267 1133 292
1646 1285 1808 1512 1839 1869 1578 1318 1385
1829 1800 1491 1600 1290 1856 1781 1881 1953
2008 1681 1472 1846 2010 1619 1584 1849 1876
1744 1980 1421 911 1308 1762 1398 1470 1974
1902 1985 2001 1926 1374 1678 1523 1894 1597
1778 1940 1362 1613 1629 1473 1633 1867 1838
1931 1850 1776 1689 1311 1947 1988 1779 1381
1683 1677 1675 1587 767 1401 1412 1544 1484
618 1755 1073 1970 1735 1770 1623 1665 1783
1400 1892 1921 1506 1978 1731 1739 1515 1354
1264 1394 1763 1569 1453 1539 2006 1586 1855
1609 1729 1624 506 1668 1803 1486 1767 1720
1753 1994 1718 1922 1314 1250 1516 1546 1625
1708 1286 1993 1785 491 1705 1924 1752 1888
1651 1604 1750 1547 1481 1704 1851 904 1920
1939 1277 1870 1934 1617 1833 1797 1817 1967
1935 1914 1621 1468 1859 1552 1640 1709 1121
1973 1343 1266 1806 1360 1299 1990 1356 1631
1555 1811 1323 1794 1550 1448 1848 1826 1723
1891 1302 1655 947 1580 1908 1641 1816 1701
1871 1588 1843 1643 1893 1866 1628 1417 1795
1995 1937])
(defn is-2020? [v]
(= 2020 (reduce + v)))
(defn product [v]
(reduce * v))
(defn find-value [list-compr]
(product
; re: first -- it is needed because there is a duplicate entry --
; maybe I'll be able to tackle this more cleverly in the future
(first
(filter is-2020? list-compr))))
(defn day1-part1 []
(find-value (for [a numbers b numbers] [a b])))
(defn day1-part2 []
(find-value (for [a numbers b numbers c numbers] [a b c])))
(defn day1 []
(println "Part 1: " (day1-part1)
"\nPart 2: " (day1-part2)))
(defn -main
"Advent of Code"
[& args]
(day1))
It works but I am not entirely satisfied. My clojure knowledge is limited; the standard library is still very unknown.
Having said that, I think this looks much readable than my solution from Part 1.
The github repo for the clojure solution is here.