2021 was me learning Ruby. 2022 is me getting back into Python.
- Python naming conventions
- Write unit tests
- For utility functions
- For the main functionality in parts 1 and 2
- Add coverage (run as, for example,
coverage run -m pytest 2022/test_day10.py
)
- Git
- Move input data to private sub-repo
- Combine years into one repo
- Have these examples and answers served by Django, VueJS, and SVG
- Dockerize
- Use a cloud VM rather than local
- Make maximum use of
- Functional programming style built in list etc. handling (e.g.
map
) - NumPy
- Pandas
- Functional programming style built in list etc. handling (e.g.
- Careful about the end of inputs, does the final
add
get triggered correctly - Pandas
nlargest
was useful and more performant than sorting. - Make sure the debugger is working
@classmethod
is handy to make things testable- Use
pytest
and write simple unit tests as I go along so I have confidence about the utility methods
- Other code niceties are
_private_methods
(a convention)@property
andfrom functools import cached_property
- Good tests really sped this up, but
- Edge conditions not present in test data floored me repeatedly. When I refactor it's important that tests catch new errors
- Are regexes simpler/better than raw indexes?
[::-1]
looked cryptic, but is just the[start:stop:step]
and reverses the list- I needn't have kept the crate's
[
&]
, that caused trouble printing - A mixture of proper debugging and printing was useful, would a to string function have been used in the debugger's output?
- Use
dirs = [] + self._sub_dirs
to avoid taking a second pointer toself._sub_dirs
. - I can use
if file_match := re.match('(\d+) (.*)', row)
instead offile_match = re.match('(\d+) (.*', row)
thenif file_match:
. - There are two edge cases that don't get exercised by the test data nor the real data. Almost everybody's solution fails the first one (mine included) and most fail the second. Should I be
basing things on the data more than the question itself?
$ cd /
should take you back to the root from wherever you currently are- Revisiting and
ls
in the same directory twice should not double its size!
- Careful reading, e.g. H, 1, … 9 is 10 knots, not 9.
- 100% coverage is satisfying
- Part 2 was not accessible for visually impaired programmers
- We should not be committing input files (reddit thread). That'll be a good excuse to look at sub-repositories
- Took the opportunity to combine my 2021 and 2022 repositories (following this SO answer using the allow-unrelated-histories).
- Used git's submodule feature to move all the copied AoC inputs (test and real) to a private repository.
- Calling
Monkey.bored_with
picks the instance method not the class method of the same name!
- Part 2 was hard. The breakthrough for me was
throw['item'] %= self.product
which was a result of me realising it was mathematical (from a comment on reddit).
- Remember in
or
to negate first when tacking second if needed - Passing logic tests and functions (e.g.
stop_test
andneighbours_func
) would have made refactoring straightforward, but may have been premature complexity. Anyway it was easy to fix. - If Eric had not made the Part 2 data take soooo long on the naive solution I would never have fixed it!
- Writing
logging.info
statements to reproduce Eric's explanatory test is a useful additional test if the algorithm passes on the test data but fails on the 'real' data (see reddit thread) - Lots of my time is wasted with sloppy writing, e.g.
[i for i in range(self.sorted_packets) if self.sorted_packets[i] in self.divider_packets.contains]
instead of[i + 1 for i in range(len(self.sorted_packets)) if self.sorted_packets[i] in self.divider_packets]
extend
instead ofappend
adds the items in the list. No need to worry about how to flatten.- To use the
capfd
fixture pass it into the test function, then callout, _ = capfd.readouterr()
to getstdout
after theprint
statements.
- Note to self — do not forget to uses square brackets for
loc
andiloc
in pandas, i.e.self.grid.loc[y].value_counts()['#']
notself.grid.loc(y).value_counts()['#']
- Cute way using double comprehension to get all pairs
[(s1, s2) for i, s1 in enumerate(self.sensors) for s2 in self.sensors[i + 1:]]
- I should have taken a geometric approach to the algorithms from the start. I may need to be more on
top of geometric algorithms for SVG work anyway. Some interesting solutions at:
- jakesco Part 1 (GitHub)
- JakubDotPy Part 2 (GitHub)
- RGodlike Comparison of different approaches (Reddit)
- appus3r Can't think of an approach (Reddit)
- Ayman4Eyes No search formula (reddit)
- Day 15 Solutions Megathread (reddit)
- mebeim's solutions are very useful since he includes a walkthrough of the code and his thinking