This commit is contained in:
2022-12-06 07:14:27 +01:00
commit 97aa78cd76
36 changed files with 7669 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.egg-info
*.pyc
/env
/__pycache__
.env

2
Makefile Normal file
View File

@@ -0,0 +1,2 @@
n:
python3 make_new_day.py && cd "$(\ls -1dt ./*/ | head -n 1)"

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
This was a fork of Anthony Sottile's excellent [2015 AoC repo](https://github.com/anthonywritescode/aoc2015), which I've repurposed for my own workflow.
Note that between day06 and day07 I ripped out `support.py`, so only on day07 will it work with the included items.
These are my submissions to Advent of Code 2022, done in Python. This is the first year I'm trying to do it every day.

0
day01/__init__.py Normal file
View File

2250
day01/input.txt Normal file

File diff suppressed because it is too large Load Diff

62
day01/part1.py Normal file
View File

@@ -0,0 +1,62 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str) -> int:
n = 0
largest = 0
curr = 0
for c in s.split('\n'):
if c.strip() == "":
if curr > largest:
largest = curr
curr = 0
else:
curr += int(c)
return largest
INPUT_S = '''\
1000
2000
5000
1000
4001
'''
EXPECTED = 5001
@pytest.mark.parametrize(
('input_s', 'expected'),
(
(INPUT_S, EXPECTED),
),
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

61
day01/part2.py Normal file
View File

@@ -0,0 +1,61 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str) -> int:
elves_totals = []
curr = 0
for c in s.split('\n'):
if c.strip() == "":
elves_totals.append(curr)
curr = 0
else:
curr += int(c)
sor = sorted(elves_totals)
return sor[-3] + sor[-2] + sor[-1]
INPUT_S = '''\
1000
2000
5000
1000
4001
'''
EXPECTED = 5001
@pytest.mark.parametrize(
('input_s', 'expected'),
(
(INPUT_S, EXPECTED),
),
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

4
day02/Makefile Normal file
View File

@@ -0,0 +1,4 @@
s1:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1
s2:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2

0
day02/__init__.py Normal file
View File

2500
day02/input.txt Normal file

File diff suppressed because it is too large Load Diff

79
day02/part1.py Normal file
View File

@@ -0,0 +1,79 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str) -> int:
"""
A for Rock, B for Paper, and C for Scissors. The second column--" Suddenly, the Elf is called away to help with someone's tent.
The second column, you reason, must be what you should play in response: X for Rock, Y for Paper, and Z for Scissors.
The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round (0 if you lost, 3 if the round was a draw, and 6 if you won).
"""
score = 0
me_lu = {"X": 1, "Y": 2, "Z": 3}
lu = {"A": 1, "B": 2, "C": 3}
# 2 > 1
# 3 > 2
# 1 > 3
for line in s.split('\n'):
if line.strip() == "":
continue
elf, _, me = line
score += me_lu[me]
if me_lu[me] == lu[elf]:
score += 3
if me_lu[me] == 1 and lu[elf] == 3:
score += 6
elif me_lu[me] == 3 and lu[elf] == 1:
score += 0
elif me_lu[me] > lu[elf]:
score += 6
return score
INPUT_S = '''\
1000
2000
5000
1000
4001
'''
EXPECTED = 5001
@pytest.mark.parametrize(
('input_s', 'expected'),
(
(INPUT_S, EXPECTED),
),
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

82
day02/part2.py Normal file
View File

@@ -0,0 +1,82 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str) -> int:
"""
A for Rock, B for Paper, and C for Scissors. The second column--" Suddenly, the Elf is called away to help with someone's tent.
The second column, you reason, must be what you should play in response: X for Rock, Y for Paper, and Z for Scissors.
The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round (0 if you lost, 3 if the round was a draw, and 6 if you won).
"""
score = 0
me_lu = {"X": "lose", "Y": "draw", "Z": "win"}
lu = {"A": 1, "B": 2, "C": 3}
# 2 > 1
# 3 > 2
# 1 > 3
for line in s.split('\n'):
if line.strip() == "":
continue
elf, _, me = line
goal = me_lu[me]
if goal == "draw":
score += lu[elf] + 3
elif goal == "lose":
if lu[elf] == 1:
score += 3
else:
score += lu[elf] - 1
else:
if lu[elf] == 3:
score += 6 + 1
else:
score += 6 + lu[elf] + 1
return score
INPUT_S = '''\
1000
2000
5000
1000
4001
'''
EXPECTED = 5001
@pytest.mark.parametrize(
('input_s', 'expected'),
(
(INPUT_S, EXPECTED),
),
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

6
day03/Makefile Normal file
View File

@@ -0,0 +1,6 @@
s1:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1
s2:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2
d:
aoc-download-input

0
day03/__init__.py Normal file
View File

300
day03/input.txt Normal file
View File

@@ -0,0 +1,300 @@
PcPlnShmrLmBnmcwBhrmcmbHNGFGpwdFFwGNjNbGqNHH
tzQfRJfWZZztWzVtCTfRzFZjpFjNZjGLHbdHLDdjpb
CCQTzRLzvQVVfRzJfMPsnBlglgPmBgPmvSrl
RMfvbbszHTsssFPzDQPggpQJPQ
NSNcqVtLVGgDlpQBClVB
hmStGNNLhjNrpWLGSjWrZssbZTMMvTfMnThbRRTs
fTrTPGTbfftWBBmLjrJL
DqHwVMqVplDslmlZmpHVwNnShWZFdBBdjWBtWtdtWJSSLS
MNslpDvVHlwsmpQRgQgCfTTcvcRQ
pBBhRgDsMsswprBhvgRglZtFGFFRqZtZmRtNqtZPPN
TdmmzzmdZdqdGFtF
nmSccCVmSCpDCswMwl
NptqDsQtDTQzCvlzCpRlRp
jmZcndmjbZcjrmDvFMFFlwCvzFnF
jjgLVLrGcdDBNhWQTgHg
mLVhhfSMSTmMwClHGdpjDHjGdV
zPrZgJCgbsnrPtZzsCsbpRDjBRHnjGDRldRHppcG
JJrbsFrZqrgWbbqbrgWzJPNTwhTNCmmvfWCShhhmwwfm
ftgfljvgfgBTNvtggFDDGLGRDnMDzcQzncGt
VdbpbVdZwdwrsVVLRrMrDLDBGnBGcM
wmpWwWsHWBCCCPPvjvmSqlfTTmSNgN
jSqmzmmSSDRjLMLDwqjNcMMLTTflffWCCsRsTHnHVrfHWTsr
tdbgZpgBPdgGZGGFTHVpCsCVfVsJpnWl
FnPQFvbvhFFFbvBwScjhzcqSLLSzSN
bWdgrWwwFWbgzFWzrmNbdPqttChMSRnmqSPSnqtMRM
lcPJLDDPPfpMBCRJBtQtMh
lGDGjTGLLDHPPGjlPTsswsbHNFsNrFNFsrzr
VmtHfVhBLHVtlhphjZMdnQQZZqZmQDdzQQ
CPFwPWrvWgrfNgFPCMqZzMDDbznFTqqzDQ
NNPsfffPCsBLjpVltV
ssdBBJqJhlTJLsjTJqFFmnmmnnrcmpprmmmPcRlf
gqtqzSgWQWqmnRPPcNmmQM
GqbSVtGzvgvgWbZjjBhTdhBsTZBJBZ
jhNBsPDzLjsVhLSNzgvcvbcwbBWFcgtWCc
ZQQTTHHnGpMtnpdHpQJfMgrvWWFqbcWWGgrgwCCwwF
nHpmMnQQMmHpRnHRmMJnnTShPzljzjSNmSDhLsNSPtSh
GdqnBGFdlqzFnwdSCQZjZLLDZjZRvZLDVvgQ
PsptsTcftMfcTfhTghVDvvjnRNjVZnvV
WtPfJTfftJcMTrMnpccFwlCSCGFGCbCwJSbqBl
GjFLGhjRwFjNSjSdJCBBdQJddbBc
MVvMMHRzVtHlvlcQBQJHqdpQqCBC
vDgVztvvmrgrVRrMmsrsmZzZnWhGnNhGWTLfnLwTLhLTjngL
VljjQJSsrjjrCglsCjsgjVVfDLdZGMdvvGdQMzmvzcDQMc
HqPBtcpRWwtHbbFwBHZfmfpDfvffDfMfmGvM
PwHNbcwtqFqnwtNNqPNPPWBTThjhhVTCSJTThssVnSlJJV
GCccNCrrnCrpnzrnCDPcDDrvHHTBqTPhswqhPTBTTwBhTj
VfNmRtZgWWHdBdswdjZv
SmtQfgNmVFgVLVLVmrnMpcDLGCGLGDMpCp
CrdZdZmPPjrQdRPRDqDLBqBLBSWgWgLDzF
sQhTNphsVbhhhMJfhNVGqltVSzSllBzStlzFFFWB
hsMpwQhNMZmPmrwHRj
cNVpSVRpLHRLsVWWfnfsCshW
jvqjTgqZPlJZmbPPfbpswsPb
vlqdTZdtJvqdZjgqZrtRpQFtLFRQczHGzt
JJQndVQnQgTfNvGf
ljpbWbmNbDlGTvggGvZf
mpmRbMmmNDFDmScpzCsdzrnJrsCzrrnM
tNFtNFFzzjjzjBtVNZVbjZGlpSvTllpWwvnBlWGGBGCC
fPdcrrgPHrHMMMWlppGJSPwGSnGv
fmrqrhhfhdRddHrhQqQrfnLZjLtNttZjjRtzjFtRNj
sphRcpQRhfmnmfpptg
WVPlGLlSjCjSlGSHJJWZdmbmfvPmmnftbbgDdt
LJjjqVNjlnCTRcRhhsNcFF
vwwqttFjwgClRNCCvGNmZZMmJsPJjJpTdMpsZd
fBLVHHHrFnhHhnrVSTmfdPdPccTTPsMfsJ
QzVWzznzFbWNGNlt
vjMddVVmnWpdMndjvhhWfNLpfBsfLLZLBBSqqTZq
RFlrzQJPSRGzzzzgBZNsgBZTBflfgf
cQFDRHFDDGCJShCnvwVnnhCn
hgjlpRRLlPJJhTLJMDnwBndSPBNvMqnN
FGWVfZsmCbmVzrvtwCSMtMdnDMCw
VsVmVZfVQDmVFrrmzmGrHHTJgJjhHJcllglLQJRL
rrTVcTBgsjTffmfWHZTv
JLdnDlpGlGSLlpwJpHZfFvRZnWzWrHWqFH
wQDpDrdSlSCblCdwdSLlwQGBthPMsghNsVNVtCNNhNPjhs
CtCMvNhDMHfDDdffqtDtCflpJlBpvmWWJWwlpwFFvjwB
rGSbVGZrSsFJjlmBFZWp
rbbQgzVGrFVSPPGqfhftfqztNtqHtt
lMGZCGphllZDNshNNmHHND
PLwjVwJVsHmRrZZw
ffSdzjfZSjtjSjLtLLFFFGqFzznCpCnCBblQ
CqRnlzHCRWTlHPTZVQrcQtFsQFTcrQ
DfJcdBDBcftQjsrsBtjZ
JDfdGhSvNGhNfffGSfRznPvcRWcqCqmlvlcn
JPhBBBQCnCJCMhnhMZRrRZgbDgrWrNbglDgR
jLtSTwtsShwRNpRWrh
FLLSHsjGLGczvfPfJdfhddnHPC
BjHBNrWmTjFgJngbJhWd
vsGttMDtwCMQCJnqqqFJsggqdg
GFtDSwwMpTrzSSfcfm
rnWDQvpwWpDDcPjFPPHZjVDZ
CTJCRmCJcZZZHCCQ
LdlmdQJNpnLWbrfL
VdTdcVTZwCRGVGGMVmttlF
gnrsbngfgQSpBfpMBBBpSgMNNJbmGmlqGDqDNlFFJlGNFz
gprgQhgpMMMPsrRTCdPZwCwZZCRH
cHlCVGbbWHWqRNThhcNcmh
MwQDzpwdJwpBpPDQvrhShfLTTRLfLdjfNRqS
JwMBBrPsPDwQMDPPBPQJwMrvWHFbHHlgbsGnnWHnFnRGlblF
PQPjPDjRRQSFLSlgSmLlfh
zpLdBddbNCdqGbWJGWpJWWlsFsmmFpwfflFgfHwFhgmh
nJLdLVnzqqbjRctcPDQVTP
JdztScztPdSWLJLtgMbCjhvlbPRbjbMvCh
VZrqfQcFQwGVVFqfrTFTNqhljRHDMvMMGhRDRRHGbDhG
NZQNVQQpQmrZFQQFwQQVVZgBszJJgznstnmtcztdBSgs
nFHLNJzFbLJGGLMlTTRZbZRhWRTr
wVmgBBmtmwlqlWTwTM
sdvmgcPsCPPQQSMz
SccCqmQmgBmppLQmpSMjjlJzzsNPMDRbPNPlJM
VHZvwtZwhZHtdTwrVbNsljlRDlJPDhzsbN
dZwftVRftmcgpBCmBf
NTTlVlgNSflqbphFFhNbFp
wmmLmjwzwbWGLjRmtZZdhZLFtQQLQBFh
RvjbMjjvMzMWbDWwvzPjvmWSfVfsTlVVPVgTgPfVsnnnsJ
BsBsZHZNdWwsNdrzgCrMMqsjzzMC
flfhVWFmLrhQzCCh
fVbmFSpnSSmtnPZvdWbwvdvdHZ
NsZWWWWLsBZPhfsLmPhcFCCHCMMrqfqcvHMfHH
nThSllnplGlMpvFRcCqrrr
DnTwSztgzlDnVGTwztmdZhmLdJdNDshBdsWs
RBBGTFZGglMHvrtcgSdnNgjg
DmVcbmbJmwJDJzVVwzJfmfstnztvjnNjvNSpdptvzCnpjj
DsLcfLmbhVQssQJQscWRPBZZMMRLHFHZBGMG
FVvhVnhFnFhmvFhVcMBHLgcPClrqqrtqCppldrRRTppldg
QLWfDNwsQLtlrrCtDdpq
sJwZwLsGJWGGwzzWZNbWNLjQHSVhvHSnhcMFcbVmnvcchSBS
jTMNMrHBJWWDffRqfDBqfD
QmSFphtQqQmVmqVnPnPlpwgfnRnDPl
VqFmLFbLhmZhGFGmCmGtZLtJWzWHcJrNrHMccjMscMHzMZ
hGPGmbfPzbPfgdMdWGqBGQcqpp
nvFTvDrTdNZZlrjnMHHHpBBcppqq
rNlZZNLvRdRCRFFwZwhgbmSJPSmPfhfwhS
vjdbFWTtFRRvtvZZvdWJWbGjLhCcnrrrNqLNCPqchShNqc
QHQVlDsMfmmDMHDBdLdCSLnhNLNNfqCd
VQHsMDpHlzMBBwlsmMzmmlVwptvTWdvJdbvJtRTWgGFJJGtR
nSScBcnbbFSQVdBFBtWpwtvtPbTZthtTvT
pRzHpGjCDGzHGCGsThqqwZwPhCtvhTqZ
NzlzjDDpNldBFrlfFQ
qJlDlPPWppgppqPlplpfdvgnbMfGbdgCghMdCM
QWTWZcSsWbvVvTnhfC
tRFLwZrcrWzzlJmtBqlm
HMNMvvzzNcmfNmfbhs
qVcwCgjCLtWRSLsTPbmPfmTh
RtWCJgddWRtCJdWWgdBjwWWwpzMFpHGprcBGFFnGHQZHQGpF
gZgBDgDVGDGjmDZRtgjvVvtQdnLrcRcrdfdfCcnlscsJsn
WTqzqHqNzpHpwzNhMHNwWPbQCQcCLsnCrLLfcrffNflcNn
zHTwwpTPzTTwlFTFzwqzPbwZGgGZZBtmGGvGmBGZVFStFZ
znlSSzfzTcmmfcCt
PHWWGpqgPShPMwGwqJFTVtwtCVTCmTJcFc
qHqqSggLrRLBbvDDdndzRQ
WBddBQWZWWQqqQFMWfmrWsJnmVJJNDDVJGsLmHmLDN
PTgCjvCCPPPzSZGJVLsVZCHHnH
pzwtPTvzTjRTPtwSjPSzRgBbWMBfMwwZfbWrMrZFqFFM
BqDwVqdqlDlblQMf
ZcCWWcWzvJZjcPjZZZfTHfQJQHThqpMbQQJf
LPCcZcczZLgCjvPWgvstjsjmRRBdmGrdGdmSFGnFrtGmqr
CBvgQssVzfCBQSgvvvfmrlGrCtMGwthJlJtbrh
TpLqLRFpqdRpRTfNPtRmrMMtMlMMmlMJlt
PZTjqFFTHZZNZpqcVWzVvgzcWnSWfBDD
SVSTpgpVpdNbpcVdfjcNfbcJnqsltcJPvRJqRwQqlQsJls
zhWzDLmFHhmrWZmmzHJJQlnswqsvttrstQqs
zGtZFGGCmZmGGFhLBWBGGFdgVjgppMTSTgMfCNfVVSdj
CzjNJGcnzQJltPHttcPHTP
bLVsqLbLmSSVrqmdhVSmsVFFprfrFWrwTTWWWZpFPtlP
ssDsMqLqhvmvhdmdvzRCnQgRzzBjgnlNCM
TzTLzzSGRlRSjWzlWRzHGTpNhPhJPmdnNPPbhlbPbdhfPh
mBCDBVrCqVQvQMBcVcqBrBDsbtJfnZNbJndNNhthZNJfPZPs
wMCrqVvBzmzHTGLw
NbfwfZPPdVNPdBdQBcmQzrQz
nnWqHLWGFMDFDLDjsqnHLsrQGzmJczmQrgJmJGZmQrgJ
FFWRsHMHCZCWFwRwphpvlfTTpp
PclPlVZvLDNvVZSLSMvvDttmtfzFtzHqtqtzzccCFc
jrggQGhjQsTDbrbJjJQqzzCsdtzzFCdHqmBBHz
WGDgngwrQggZMNvMWPMRRV
wNgpMdMMcdSscccNcLLTbtQJtQJQltJwFtlBlzBt
HHGhrLrCvHWHCPhrWDtnBllnQbfQftGnfnBF
HvLjWCLHPZvHHHZjjrqVTTZVcppMgNNNNSpS
QQrwQmvWQjgTfvBjfffrSDcrqSqDDVLctqqcVd
GnHFnGhGplGMlHMNhzBzlLPLVcVNCPDqVNdcqLdqtV
GnMGpslMhGsRzzHzGsZFZQJTTmWfBbvfgfgJRfbwbW
MRCtSwMhvjCGtvMZDVWpVZJlVccNDlpb
gdLQFFwwLfHJWnQlcJJbWc
rdqdmqHLTLmsswsFHLFtMPRMCSSRtSjTPMPSCR
jmCCnLCLZjZjRjQTLZQhGPGhhzHhDRGRDzwzwh
stlJlrlJJcSSfSMMzPfhhGhzpwhpNwhD
rbrbBcSlWmdZWjDnTm
PNBRNnnqQRNfVfRtVVzgFLLttpSwgzzzmFFF
fcWlcbvvCFzLbwLw
rlrMrhTJhDcTTfhRNqHRQPQRQNQB
TrprpprRVVfpRpVqTVpzDdvmvbbCchhcttqcthSMdd
JlnZnFlsMBZnJHlsLsCLbSNtbNhdbbShCScm
FlZjjsHHsnQFQwTDzMRRpGRR
wHWzwCTTqJhzzvJhWHWhqJWrFsFQrrrFCfFfgjjgjprfsp
DBRmZRtZLbnRBGSBmtGSLpjBrrsfrgsTQVrVrrPrgr
DLnbcbtLtmNNmbRcGbcGmHzlThNNhqJTHdvqvWlHJh
GSNqjRcqflNLnCTTWrWn
BmwQtmtJwPwmzMwQtHtVssvrnpWTTnsTTgpVCLCs
DBBQHJJrzhzQDDfSljRfhccfcdZf
wtgtChCwzqgLzjggqtHtjFHHFcnPfdRDfZZVcPfVZZfGnfdm
vBTrRTTWGGmcTDVD
SJMbbpWslJblSSNzNsztRChzqRCj
gBHHCtVCSHMQlfFTQqCfmq
WrpdwjbwbwQGlPqSqblP
wWDncWrDDNdWNRjScScjpzvHZtBMZtJsvLVgvzssBsvs
VppWpVfmZPBlnmrGBzhttMzMpctLLcChSh
FwgLJvRdHcwMzSzjzc
QvbgdQLQgDvsqvqRHRDdDQDBWmBGBflnVbZmZmmnBBWrmW
SqShwLFCQGpDHCtZCWpW
bdHPHjTbJdsMnPHPbdjgtnBlVlBnVgtZpDBpWV
bdmPcjbjMNMvvHbTcQRNfRwRwLffwwqwNF
zdRHTpQTQHQnpnnQRHTsNNlJSJWmzJmJllNmSG
FBbRvLbFRwLqbbVgBVqqLFqJtJNcltsSGmgmGtNtgWmstm
FLhhfvvVwvjqfLRBqLVqbwqZQrTTpHMHjdrpnnDPDQCdCrpC
JgjzvbJCWgbjgGbJWjRhgNPGHHBMtqBStZZsHMSsBqtD
cfQdwQFdQQppnVVnlFLLBsBZMhqPlPMMqBSHDtHM
wnQhcnVddmdWgjvjmvRjjJ
QpcRtndvsLcVJtRSzWSlWjzSbjjWBv
qGZPqCTmGPqgGTCqHgCqZCPFWbbBNBMNBbdBMlWWrbjlMbFl
qhHDGhCmPhZHgDmDVQthttRchLwLdwcc
srpPMwlMmsrGFGswvDRhRWRDJJJchJ
fSgBbCBNnBTTgCNLTCRJhRJVWhTcVVVFFJdR
SbBnnLNZCLFQCZjnCnZFjPrzqmlMmmsrpzrlsmtt
BBsfDfsBDSWRwlLqmWCpWcllrl
nQMgMnnnhdntgMBrCdpNNLNlNqLqLl
FnQFHzPQJjJGRBGvfR
lRnVRFFlgMCRVwLgFZRnZQHWdcftHdmcJHmmMdzzfz
DGBqGQbhhBDbSBpGDBzqdNHJdtmcWdqdmtcm
bjbsBvjhSlVsPRgLQl
dDLbRdTMRJMbFRzZBfzNSjtNBzBD
PmgspqqVrppTVrvrsPhhfQwZBwNjNtNffzqqfwwN
mCcmsngrPvpVTssCVsvsPLRRJllGFlnRGbMJMWWlJJ
fGlGZHRRbwgPbZRRNCdcSWpncnQtQWlWcWpW
JrTLJgVvVLQQvtSvQncQ
JrrrmMTBVTmjBMrVjrshmJzgCfzRPCRZPGHfbwNPzbZHNH
qqqlDDZzVVnNqHDDFFFNlQpzjrTvsvzTbgJQQggjJp
cWPWcCmMfCMWdtPMhMbQQQjGGjpdvjTbjgjr
WtMSBCtCwchChMfBWtcPnNVNqZZLDRNqTRnnlwHn
mvQQnhBvhmvBmncmZBclTZTQccRFNFFdqFFgVqSRrgFrppNR
MjzJPzGPfffMCjVVjfPHLCFRNFStqrdRSdqdNGRqNptq
HDJHPjDJLfjbzfwPjCzCWWTwlmQhBnsWBvVsvBvZ
RVjcshhscQhrVjhvzjVfDNnzGtftmDHFttFGGf
qLcBCCMBJJbTdBDnNtdfnmDG
WpZgLLclTclRwgjgsrwsvj
shhhltNPcDtlNcNMcsctNtppLZvWWFLTFFZpTZDQgFLT
dRgJVzRHbqnLpTWQvLLJfp
mCVCdzqHndbqHCrVqRrmbwtNBsmPwNmScPgtPhBclw
bDDZMDrFPsrsMcsrbJZJdMMGpSzpSbwRSSRGpCHCGzlhCC
BWWNQjBLQVHhlGpSCmwj
ffwnNwfgtnNgVVwfNWBWnFsMJTJTcPFJcTFDsrJstJ
vQbQLQBpBvbvpHplHNTHWGZDngntZCQGgZhGhtjG
rqccPPmcrffRmsmCjVgnrGChChDjgW
fqRJsJMSlSzSWTbT
brsjjJPJwrJJsrRRlllNQGWQpwppCtfGGtWzGGMQ
ncBqqLTDnmLgVDZVnBDmdtVVtMzWWdMCQdpQWdVz
hDZgTSSnTzNPNFSFPF
VZVJJtWTsfTVVWsJhPWrCjzSBJlHSmjJCRlNSSlz
CqMpwccgvvgLnvLbMMRRjBNHzjmGmwNHlmlN
gLqqvpCDfVDrTfVW
CNMDGNPPNJCGbLnTffsTLT
tcBBRlrBdQrtmtWFjjbnrTjjFbjr
cTQQhcmvcBRcwDMVDZZPPCJh
mBCdgPLgZmLfGmfvGhtRQJWjtjQGQhtN
pMwrVwbwHMsqcTWQhQWzggTTWp
nnSMwrlrsmSZgvvmDd
WNSzpCzNzqzNdmqrRHrrLHFrJH
MtPfvnGMPnMcbnRtDHTRFFDrmJRQ
PcBsfPPHPGGfcSzZjNjpNZZdCs
mDCZVLDhWVSDCRvGtsGgGRHl
JjPwPNdcPnjPdcwNltHzzGmgGJzQJJRQ
dqfjnNmwmbmWrZMbMrThhB
qtBpNZFpBGFNfZNPmZPmQmHrmPPPTz
LLwJLvDvlWWLHdwDrVcCRcDVzzVVcV
sMMwvgjnMvjvnlsvNFBqfGHFqHGjtSpS
MmZZsFgwJTdTMdgmZdZRgFhDHhPQPPnRPhCrHhnnrPDD
fBcLlNNpQCDLDJJC
jSbWWlWpBpclWlWpNWlVBbWVdgwswFJmFJsGtdMggZFGbZwd
CMVQVMLLMFGRCMWQttnqqwQwhqsm
pJzlczSpPpPgmsqNhmPGDstq
gZgTccZGGpzdpjclGRVMVRFRMFvHRLRdLf
FMWMSBtStZqZWQtFtScWWSZmHPVJJVHwwlTgmgbzQwbwTJ
jhGLhdjNjsLvLsshzHJPVdVmmbzHzdHJ
jvDRNjnDNGRCzjLzZZpqnrFBSccWrMcB
zggmthDDghHvtrdgrVWfSBRwTHLWHwsBWw
PGGjpCjQnJQGJcJnnQpjFWVSsZWVLRZLBcsWSZBRWS
FGQlpnJCbqqGGRCjjnlCqGMtdNmmmvdNmmmzvhbrmgMz
TstvBTdgBhqTsdTcPlfCSrNMrNnrCNNSNNgp
HwLQwQDZzDjnDbmMhNSnmm
FZLVzLLQHRRzwWHjdPlJctlJtlsllhRs
fBtPsMDDswHvBmmVdBlSBRcGGnhVhg
LWJbrpFqpTLTTjqqNWlhnRGGSnhrcSdlRlsh
JWNbbpjJzTbNNNJNJMvmvfZHvzDsHDCsZw
LPGnPNLtwGhFFnJPfsqpVVszzpsP
TcWdvlrcWddggrDBDDdDMmWzRJqfVQZqmsfZsRQzZfZzQJ
TldWrMrDdlDCDdMTcwSLVCSShLNSwHjhGF
JGsWWWQsJmPwQWbBPmccbcbqFfMMpFDVCDFVFVCDqqfFwD
ZtLnlvLnNtvLndnCmfMVSmVCClfpVp
zTzZtjnZNLNmZvdtznntHHZJbBRGBRQWcJGbGsbsJRPQWT
MLmlMTPtQtMNlhbqbbqhflBB
rcrvjpSvScbRbBvbDBPG
ZZJzSHpzPrJzHFmMVMFmHCLNtV

60
day03/part1.py Normal file
View File

@@ -0,0 +1,60 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
from string import ascii_letters
def compute(s: str) -> int:
total_priorities = 0
for line in s.split('\n'):
print(line)
c1, c2 = line[:int(len(line) / 2)], line[int(len(line)/2):]
common = None
for char in c1:
if char in c2:
common = char
break
if common is None:
continue
total_priorities += ascii_letters.find(common) + 1
return total_priorities
@pytest.mark.parametrize(
('input_s', 'expected'),
(
('vJrwpWtwJgWrhcsFMMfFFhFp', ascii_letters.find('p') + 1),
('jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL', ascii_letters.find('L') + 1),
('PmmdzqPrVvPwwTWBwg', ascii_letters.find('P') + 1),
('wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn', ascii_letters.find('v') + 1),
('ttgJtRGJQctTZtZT', ascii_letters.find('t') + 1),
('CrZsJsPPZsGzwwsLwLmpwMDw', ascii_letters.find('s') + 1),
)
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

63
day03/part2.py Normal file
View File

@@ -0,0 +1,63 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
from string import ascii_letters
def compute(s: str) -> int:
total_priorities = 0
lines = s.split('\n')
common = None
for idx in range(len(lines) + 1):
if (idx + 1) % 3 == 0:
l1, l2, l3 = lines[idx], lines[idx - 1], lines[idx - 2]
else:
continue
for char in l1:
if char in l2 and char in l3:
common = char
break
if common is None:
continue
total_priorities += ascii_letters.find(common) + 1
return total_priorities
@pytest.mark.parametrize(
('input_s', 'expected'),
(
('vJrwpWtwJgWrhcsFMMfFFhFp', 'p'),
('jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL', 'L'),
('PmmdzqPrVvPwwTWBwg', 'P'),
('wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn', 'v'),
('ttgJtRGJQctTZtZT', 't'),
('CrZsJsPPZsGzwwsLwLmpwMDw', 's'),
)
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

10
day04/Makefile Normal file
View File

@@ -0,0 +1,10 @@
s1:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1
s2:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2
d:
aoc-download-input
t1:
pytest part1.py
t2:
pytest part2.py

9
day04/README.md Normal file
View File

@@ -0,0 +1,9 @@
I went for a fast solution in part 1, which in retrospect I regret since the `range` and `in` approach of part2.py is easier to reason about and works for both parts.
Another regret: I used AoC for testing instead of writing actual tests. This cost me a five-minute timeout after I made too many submissions.
Something to research: There's probably something in Python builtins or stdlib which can make this one a really fast calculation.
Some optimizations I added to the Makefile today, it ultimately didn't contribute much performance though:
`make t1` and `make t2` to run tests for part 1 or 2, respectively.

31
day04/TODO.md Normal file
View File

@@ -0,0 +1,31 @@
# How it Should Work
```console
> today
created directory `day04`, we're ready to go!
downloaded input
opening `day04/part1.py`...
> done
testing part1.py...
sorry, the tests failed with output '...'
> done
there aren't any tests, submitting to AoC...
sorry, but 'you gave an answer too recently...'
> done
testing part1.py...
passed!
submitting to AoC
sorry, but 'your answer is incorrect.'
> done
testing part1.py
passed!
submitting to AoC
your answer is correct!
copying part1.py to part2.py
opening `day04/part2.py`
```
# TODO
- [ ] possibly scrape the problem too:
- [tesseract in browser](https://towardsdatascience.com/image-to-text-ocr-with-tesseract-js-3540b420e0e7)

0
day04/__init__.py Normal file
View File

1000
day04/input.txt Normal file

File diff suppressed because it is too large Load Diff

78
day04/part1.py Normal file
View File

@@ -0,0 +1,78 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
from string import ascii_letters
def compute(s: str):
counter = 0
for line in s.split('\n'):
try:
first, second = line.split(',')
except ValueError:
continue
start, end = first.split('-')
enc_start, enc_end = second.split('-')
start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end)
rg = range(start, end + 1)
enc_rg = list(range(enc_start, enc_end + 1))
for i in rg:
if i in enc_rg:
counter += 1
break
return counter
def _compute(s: str):
"""
actual submission, I pasted `compute()` from part2.py to see if it
works here, and it does.
"""
counter = 0
for line in s.split('\n'):
try:
first, second = line.split(',')
except ValueError:
continue
start, end = first.split('-')
enc_start, enc_end = second.split('-')
start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end)
if (
(start >= enc_start and end <= enc_end)
or (enc_start >= start and enc_end <= end)
):
counter += 1
return counter
@pytest.mark.parametrize(
('input_s', 'expected'),
(
('2-8,3-7', 1),
)
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

58
day04/part2.py Normal file
View File

@@ -0,0 +1,58 @@
from __future__ import annotations
import argparse
import os.path
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
from string import ascii_letters
def compute(s: str):
counter = 0
for line in s.split('\n'):
try:
first, second = line.split(',')
except ValueError:
continue
start, end = first.split('-')
enc_start, enc_end = second.split('-')
start, end, enc_start, enc_end = int(start), int(end), int(enc_start), int(enc_end)
rg = range(start, end + 1)
enc_rg = list(range(enc_start, enc_end + 1))
for i in rg:
if i in enc_rg:
counter += 1
break
return counter
@pytest.mark.parametrize(
('input_s', 'expected'),
(
('2-8,3-7', 1),
('2-6,4-8\n2-8,3-7', 2),
)
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

10
day05/Makefile Normal file
View File

@@ -0,0 +1,10 @@
s1:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part1.py input.txt | aoc-submit --part 1
s2:
/Users/zev/Documents/repos/advent/2015/env/bin/python3.10 part2.py input.txt | aoc-submit --part 2
d:
aoc-download-input
t1:
pytest part1.py
t2:
pytest part2.py

9
day05/README.md Normal file
View File

@@ -0,0 +1,9 @@
I went for a fast solution in part 1, which in retrospect I regret since the `range` and `in` approach of part2.py is easier to reason about and works for both parts.
Another regret: I used AoC for testing instead of writing actual tests. This cost me a five-minute timeout after I made too many submissions.
Something to research: There's probably something in Python builtins or stdlib which can make this one a really fast calculation.
Some optimizations I added to the Makefile today, it ultimately didn't contribute much performance though:
`make t1` and `make t2` to run tests for part 1 or 2, respectively.

31
day05/TODO.md Normal file
View File

@@ -0,0 +1,31 @@
# How it Should Work
```console
> today
created directory `day04`, we're ready to go!
downloaded input
opening `day04/part1.py`...
> done
testing part1.py...
sorry, the tests failed with output '...'
> done
there aren't any tests, submitting to AoC...
sorry, but 'you gave an answer too recently...'
> done
testing part1.py...
passed!
submitting to AoC
sorry, but 'your answer is incorrect.'
> done
testing part1.py
passed!
submitting to AoC
your answer is correct!
copying part1.py to part2.py
opening `day04/part2.py`
```
# TODO
- [ ] possibly scrape the problem too:
- [tesseract in browser](https://towardsdatascience.com/image-to-text-ocr-with-tesseract-js-3540b420e0e7)

0
day05/__init__.py Normal file
View File

511
day05/input.txt Normal file
View File

@@ -0,0 +1,511 @@
[J] [B] [W]
[T] [W] [F] [R] [Z]
[Q] [M] [J] [R] [W] [H]
[F] [L] [P] [R] [N] [Z] [G]
[F] [M] [S] [Q] [M] [P] [S] [C]
[L] [V] [R] [V] [W] [P] [C] [P] [J]
[M] [Z] [V] [S] [S] [V] [Q] [H] [M]
[W] [B] [H] [F] [L] [F] [J] [V] [B]
1 2 3 4 5 6 7 8 9
move 3 from 5 to 7
move 2 from 8 to 9
move 4 from 3 to 5
move 2 from 1 to 7
move 1 from 3 to 6
move 2 from 1 to 7
move 1 from 8 to 7
move 4 from 2 to 8
move 10 from 9 to 1
move 6 from 6 to 2
move 1 from 6 to 7
move 9 from 8 to 6
move 4 from 2 to 4
move 2 from 4 to 1
move 6 from 1 to 6
move 1 from 3 to 2
move 2 from 1 to 4
move 2 from 4 to 3
move 2 from 1 to 3
move 4 from 3 to 1
move 15 from 7 to 9
move 4 from 5 to 9
move 13 from 9 to 4
move 10 from 4 to 8
move 1 from 7 to 4
move 6 from 9 to 5
move 11 from 6 to 7
move 4 from 5 to 7
move 3 from 8 to 7
move 4 from 2 to 4
move 1 from 5 to 1
move 5 from 8 to 4
move 1 from 5 to 4
move 10 from 7 to 1
move 8 from 7 to 9
move 12 from 1 to 9
move 8 from 9 to 1
move 2 from 6 to 9
move 2 from 8 to 4
move 1 from 6 to 9
move 13 from 4 to 2
move 13 from 4 to 2
move 1 from 6 to 1
move 1 from 6 to 4
move 1 from 4 to 5
move 14 from 1 to 8
move 1 from 5 to 4
move 13 from 9 to 5
move 9 from 8 to 2
move 8 from 2 to 1
move 5 from 8 to 2
move 5 from 1 to 6
move 3 from 1 to 3
move 1 from 4 to 8
move 9 from 5 to 9
move 18 from 2 to 8
move 3 from 3 to 5
move 2 from 6 to 4
move 14 from 2 to 7
move 1 from 4 to 2
move 1 from 6 to 9
move 1 from 2 to 5
move 1 from 6 to 2
move 1 from 4 to 6
move 6 from 8 to 1
move 2 from 6 to 9
move 5 from 5 to 3
move 1 from 7 to 8
move 10 from 9 to 7
move 13 from 8 to 5
move 5 from 5 to 2
move 6 from 5 to 7
move 1 from 8 to 5
move 5 from 5 to 9
move 5 from 9 to 7
move 4 from 3 to 8
move 6 from 1 to 6
move 4 from 2 to 4
move 3 from 7 to 5
move 2 from 2 to 9
move 1 from 3 to 7
move 29 from 7 to 9
move 4 from 5 to 2
move 5 from 6 to 4
move 3 from 7 to 9
move 3 from 8 to 6
move 1 from 2 to 6
move 3 from 2 to 5
move 1 from 8 to 4
move 1 from 5 to 9
move 8 from 4 to 9
move 15 from 9 to 2
move 1 from 5 to 1
move 10 from 9 to 4
move 5 from 4 to 5
move 5 from 5 to 4
move 1 from 1 to 9
move 1 from 4 to 3
move 8 from 2 to 4
move 7 from 2 to 7
move 1 from 3 to 8
move 1 from 5 to 6
move 4 from 7 to 3
move 1 from 8 to 2
move 7 from 4 to 7
move 11 from 9 to 7
move 5 from 4 to 2
move 3 from 9 to 6
move 3 from 3 to 8
move 4 from 2 to 4
move 5 from 9 to 5
move 1 from 2 to 1
move 3 from 8 to 5
move 2 from 9 to 1
move 1 from 2 to 5
move 2 from 9 to 6
move 3 from 7 to 5
move 7 from 4 to 1
move 4 from 4 to 9
move 3 from 7 to 2
move 3 from 1 to 9
move 1 from 2 to 3
move 2 from 7 to 9
move 6 from 5 to 4
move 6 from 4 to 3
move 5 from 5 to 1
move 6 from 7 to 8
move 1 from 5 to 1
move 2 from 9 to 4
move 1 from 4 to 3
move 10 from 6 to 4
move 2 from 2 to 1
move 6 from 4 to 1
move 5 from 8 to 3
move 1 from 8 to 2
move 7 from 3 to 9
move 1 from 6 to 9
move 2 from 7 to 3
move 20 from 1 to 6
move 7 from 3 to 8
move 2 from 9 to 6
move 1 from 2 to 3
move 2 from 3 to 6
move 1 from 1 to 4
move 6 from 4 to 7
move 5 from 8 to 3
move 22 from 6 to 4
move 2 from 9 to 7
move 3 from 3 to 4
move 6 from 4 to 2
move 11 from 9 to 3
move 9 from 3 to 7
move 5 from 4 to 2
move 5 from 7 to 2
move 5 from 7 to 6
move 10 from 2 to 4
move 3 from 2 to 1
move 1 from 6 to 3
move 1 from 1 to 7
move 17 from 4 to 1
move 1 from 8 to 4
move 2 from 7 to 5
move 3 from 2 to 5
move 3 from 3 to 8
move 4 from 5 to 1
move 3 from 3 to 7
move 1 from 4 to 5
move 21 from 1 to 5
move 3 from 8 to 3
move 4 from 7 to 5
move 1 from 1 to 7
move 1 from 6 to 3
move 4 from 4 to 1
move 1 from 8 to 1
move 3 from 4 to 9
move 5 from 1 to 8
move 3 from 9 to 3
move 5 from 6 to 1
move 5 from 1 to 4
move 6 from 3 to 2
move 1 from 3 to 2
move 3 from 8 to 1
move 7 from 2 to 1
move 10 from 5 to 2
move 12 from 5 to 7
move 2 from 8 to 3
move 5 from 5 to 8
move 8 from 1 to 6
move 5 from 4 to 5
move 3 from 8 to 6
move 1 from 8 to 3
move 6 from 6 to 7
move 2 from 3 to 8
move 3 from 2 to 1
move 6 from 2 to 9
move 2 from 8 to 4
move 1 from 3 to 9
move 1 from 8 to 6
move 1 from 6 to 9
move 7 from 9 to 5
move 1 from 9 to 7
move 1 from 4 to 6
move 2 from 6 to 5
move 1 from 4 to 1
move 1 from 2 to 7
move 5 from 1 to 2
move 10 from 7 to 4
move 12 from 5 to 7
move 6 from 4 to 8
move 2 from 5 to 6
move 1 from 8 to 9
move 1 from 9 to 5
move 30 from 7 to 9
move 4 from 8 to 4
move 1 from 8 to 7
move 2 from 1 to 4
move 6 from 6 to 3
move 1 from 4 to 1
move 1 from 1 to 2
move 8 from 4 to 8
move 1 from 4 to 5
move 2 from 5 to 6
move 2 from 9 to 8
move 3 from 2 to 1
move 4 from 3 to 2
move 1 from 6 to 4
move 1 from 7 to 1
move 2 from 8 to 2
move 1 from 9 to 2
move 2 from 3 to 2
move 1 from 4 to 2
move 4 from 9 to 6
move 3 from 6 to 4
move 21 from 9 to 8
move 13 from 2 to 7
move 9 from 8 to 5
move 3 from 1 to 4
move 14 from 7 to 2
move 5 from 8 to 9
move 1 from 1 to 2
move 7 from 8 to 6
move 2 from 8 to 2
move 8 from 6 to 9
move 1 from 4 to 5
move 5 from 8 to 2
move 4 from 5 to 9
move 9 from 9 to 6
move 2 from 7 to 6
move 1 from 8 to 7
move 9 from 6 to 4
move 1 from 6 to 5
move 1 from 7 to 3
move 1 from 4 to 7
move 1 from 7 to 2
move 9 from 2 to 3
move 8 from 4 to 1
move 8 from 9 to 2
move 2 from 6 to 5
move 4 from 5 to 2
move 2 from 9 to 5
move 1 from 4 to 9
move 10 from 3 to 7
move 1 from 9 to 2
move 1 from 5 to 3
move 7 from 2 to 8
move 7 from 1 to 5
move 1 from 1 to 2
move 2 from 8 to 2
move 1 from 3 to 5
move 2 from 8 to 6
move 2 from 8 to 9
move 2 from 4 to 6
move 3 from 2 to 8
move 3 from 6 to 7
move 7 from 5 to 8
move 7 from 2 to 7
move 1 from 6 to 8
move 5 from 2 to 7
move 6 from 8 to 3
move 2 from 7 to 1
move 7 from 2 to 5
move 1 from 3 to 5
move 1 from 1 to 5
move 2 from 9 to 7
move 4 from 3 to 7
move 2 from 4 to 6
move 1 from 1 to 6
move 1 from 2 to 4
move 16 from 5 to 6
move 1 from 4 to 9
move 19 from 6 to 1
move 1 from 3 to 5
move 1 from 9 to 1
move 1 from 8 to 5
move 5 from 8 to 3
move 5 from 7 to 2
move 3 from 2 to 9
move 5 from 1 to 7
move 2 from 5 to 1
move 3 from 9 to 4
move 4 from 1 to 9
move 2 from 2 to 8
move 2 from 8 to 6
move 1 from 6 to 9
move 4 from 3 to 8
move 4 from 8 to 3
move 2 from 3 to 8
move 1 from 8 to 2
move 1 from 9 to 7
move 10 from 1 to 7
move 26 from 7 to 6
move 3 from 9 to 3
move 1 from 4 to 6
move 2 from 1 to 4
move 1 from 1 to 6
move 1 from 9 to 3
move 1 from 2 to 3
move 4 from 4 to 9
move 10 from 7 to 8
move 3 from 7 to 4
move 4 from 9 to 4
move 4 from 4 to 7
move 4 from 3 to 9
move 5 from 7 to 5
move 3 from 5 to 1
move 3 from 9 to 8
move 3 from 1 to 5
move 2 from 3 to 5
move 7 from 8 to 1
move 7 from 8 to 9
move 4 from 6 to 3
move 3 from 3 to 6
move 1 from 3 to 4
move 2 from 4 to 1
move 1 from 9 to 6
move 4 from 1 to 3
move 3 from 5 to 1
move 1 from 5 to 2
move 6 from 1 to 2
move 6 from 2 to 7
move 2 from 7 to 4
move 1 from 2 to 6
move 1 from 1 to 4
move 3 from 5 to 7
move 6 from 7 to 4
move 1 from 9 to 3
move 1 from 3 to 6
move 4 from 4 to 3
move 9 from 6 to 1
move 10 from 1 to 6
move 7 from 4 to 5
move 28 from 6 to 4
move 3 from 6 to 7
move 3 from 3 to 8
move 4 from 5 to 7
move 1 from 8 to 4
move 18 from 4 to 7
move 8 from 7 to 6
move 6 from 4 to 1
move 2 from 5 to 4
move 8 from 6 to 1
move 2 from 8 to 9
move 1 from 5 to 3
move 1 from 9 to 1
move 5 from 9 to 2
move 2 from 9 to 3
move 1 from 2 to 5
move 2 from 1 to 5
move 6 from 7 to 5
move 1 from 6 to 4
move 6 from 5 to 9
move 2 from 4 to 1
move 8 from 1 to 8
move 4 from 9 to 7
move 1 from 5 to 6
move 1 from 1 to 6
move 2 from 1 to 2
move 1 from 9 to 7
move 3 from 2 to 4
move 2 from 8 to 3
move 5 from 8 to 2
move 4 from 2 to 5
move 1 from 8 to 9
move 12 from 3 to 2
move 2 from 6 to 2
move 12 from 2 to 4
move 6 from 2 to 3
move 4 from 1 to 9
move 8 from 4 to 7
move 3 from 3 to 4
move 1 from 5 to 4
move 5 from 9 to 6
move 3 from 5 to 8
move 1 from 9 to 1
move 2 from 8 to 5
move 3 from 5 to 6
move 1 from 8 to 4
move 4 from 7 to 8
move 1 from 1 to 3
move 2 from 8 to 3
move 7 from 6 to 7
move 1 from 3 to 7
move 2 from 8 to 6
move 22 from 7 to 8
move 6 from 4 to 8
move 5 from 8 to 6
move 5 from 6 to 2
move 4 from 2 to 3
move 6 from 8 to 5
move 4 from 4 to 7
move 1 from 3 to 7
move 4 from 4 to 5
move 1 from 5 to 4
move 2 from 6 to 5
move 9 from 5 to 6
move 10 from 6 to 7
move 1 from 2 to 1
move 3 from 4 to 8
move 16 from 7 to 9
move 1 from 7 to 8
move 1 from 1 to 8
move 1 from 8 to 3
move 2 from 7 to 4
move 15 from 8 to 1
move 1 from 8 to 1
move 4 from 8 to 4
move 7 from 9 to 7
move 3 from 5 to 9
move 10 from 9 to 6
move 2 from 9 to 2
move 7 from 7 to 4
move 9 from 3 to 2
move 8 from 2 to 7
move 1 from 8 to 4
move 3 from 2 to 1
move 9 from 7 to 1
move 9 from 4 to 1
move 2 from 7 to 5
move 1 from 5 to 4
move 1 from 5 to 2
move 6 from 1 to 3
move 16 from 1 to 2
move 9 from 2 to 1
move 5 from 6 to 9
move 2 from 1 to 9
move 1 from 2 to 5
move 4 from 4 to 8
move 2 from 8 to 2
move 2 from 2 to 3
move 17 from 1 to 2
move 2 from 1 to 9
move 13 from 2 to 8
move 1 from 2 to 4
move 11 from 8 to 3
move 3 from 3 to 4
move 3 from 9 to 2
move 1 from 5 to 2
move 1 from 9 to 3
move 3 from 4 to 3
move 1 from 4 to 9
move 3 from 3 to 4
move 1 from 8 to 7
move 7 from 2 to 9
move 3 from 1 to 7
move 3 from 2 to 8
move 3 from 7 to 9
move 10 from 3 to 5
move 3 from 6 to 9
move 8 from 9 to 4
move 1 from 2 to 1
move 1 from 7 to 9
move 2 from 2 to 3
move 4 from 4 to 8
move 1 from 6 to 2
move 7 from 5 to 3
move 1 from 5 to 2
move 9 from 8 to 9
move 12 from 3 to 8
move 1 from 1 to 9
move 9 from 8 to 6
move 1 from 5 to 7
move 1 from 5 to 4
move 2 from 2 to 9
move 1 from 2 to 6
move 2 from 4 to 3
move 9 from 4 to 8
move 6 from 3 to 6
move 12 from 6 to 2
move 2 from 6 to 7
move 8 from 8 to 3
move 5 from 8 to 7
move 3 from 6 to 5
move 6 from 3 to 7
move 6 from 7 to 6
move 1 from 4 to 9
move 4 from 6 to 5
move 20 from 9 to 6
move 4 from 9 to 8
move 2 from 8 to 7
move 4 from 6 to 4
move 10 from 6 to 1

92
day05/part1.py Normal file
View File

@@ -0,0 +1,92 @@
from __future__ import annotations
import argparse
import os.path
import re
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str):
_stacks = []
for _ in range(9):
_stacks.append([])
stopped_at_idx = None
for i, line in enumerate(s.split('\n')):
if not line.strip().startswith("["):
stopped_at_idx = i
break
for idx, char in enumerate(line):
if char in "[]":
continue
elif char != " ":
if idx == 1:
stack_idx = 0
else:
stack_idx = ((idx - 1) // 4)
_stacks[stack_idx].append(char)
stacks = []
for st in _stacks:
stacks.append(list(reversed(st)))
if stopped_at_idx is None:
raise Exception
for line in s.split('\n'):
if not line.strip().startswith("move"):
print(line)
continue
match = re.match(r".* ([0-9]+).*([0-9]+).*([0-9]+)", line)
quantity, fr, t = match[1], match[2], match[3] # type: ignore
print(quantity, fr, t)
fr = int(fr) - 1
t = int(t) - 1
print(stacks[fr], stacks[t])
for _ in range(int(quantity)):
if not stacks[fr]:
break
stacks[t].append(stacks[fr].pop())
print(stacks[fr], stacks[t])
answer = ''
for stack in stacks:
if stack:
answer += stack[-1]
else:
print('appending a blank')
answer += " "
return answer
@pytest.mark.parametrize(
('input_s', 'expected'),
((""" [D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2""", "CMZ"),
))
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

100
day05/part2.py Normal file
View File

@@ -0,0 +1,100 @@
from __future__ import annotations
import argparse
import os.path
import re
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str):
_stacks = []
for _ in range(9):
_stacks.append([])
stopped_at_idx = None
for i, line in enumerate(s.split('\n')):
if not line.strip().startswith("["):
stopped_at_idx = i
break
for idx, char in enumerate(line):
if char in "[]":
continue
elif char != " ":
if idx == 1:
stack_idx = 0
else:
stack_idx = ((idx - 1) // 4)
_stacks[stack_idx].append(char)
stacks = []
for st in _stacks:
stacks.append(list(reversed(st)))
if stopped_at_idx is None:
raise Exception
for line in s.split('\n'):
if not line.strip().startswith("move"):
print(line)
continue
match = re.match(r".* ([0-9]+).*([0-9]+).*([0-9]+)", line)
quantity, fr, t = match[1], match[2], match[3] # type: ignore
print(quantity, fr, t)
fr = int(fr) - 1
t = int(t) - 1
q = int(quantity)
print(stacks[fr], stacks[t])
if len(stacks[fr]) < q:
to_move = stacks[fr]
stacks[t] += to_move
stacks[fr] = []
else:
to_move = stacks[fr][-q:]
stacks[t] += to_move
stacks[fr] = stacks[fr][:-q]
print(stacks[fr], stacks[t])
answer = ''
for stack in stacks:
if stack:
answer += stack[-1]
else:
print('appending a blank')
answer += " "
print('answer:', answer)
return answer
@pytest.mark.parametrize(
('input_s', 'expected'),
((""" [D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2""", "CMZ"),
))
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

10
day06/Makefile Normal file
View File

@@ -0,0 +1,10 @@
s1:
python3 part1.py submit
s2:
python3 part2.py submit
d:
python3 part1.py get_input
t1:
pytest part1.py
t2:
pytest part2.py

1
day06/input.txt Normal file
View File

@@ -0,0 +1 @@
bhzhtzzsczszsjjjzddfzdfzfjfzfbbnntnzznwzzvfvrrqmrmmdzzfqfhqhsqqpwpgwpppbtbnnstthmhrrsmmvsmmhjmjfmfsfjfnfnjjvcjjszjszjsszbznzbnzndzzmlldsdgdcddmqmfqqlcllbvllztzctzczdzttlmtlthtmhtmhmmszsllvzvdzzzsqzqbqccvfvcffzsfslfsllcglclwlvwvzzdsslggtzzgzdzmzddjljvvztttsgscsstztjztjztzvzwwthtftppnmpmmcpmmjlmjjjsfjsjppgcgwcggzffzwzbbmbrbprpqqpccfncfnffvcffsqqtzqzqwzwvzwwwbjbfbcbfblltnlnhhcthtvvzzfcfgfddlggbbshsggplglqqbrbggsvvzdvvlfvlvpvhhmggbrrnppjfjhffttfpffbdfbfvfqvvtcvvbvnnhbhhglgjgzzghhwrrtntrtwwfdfdmmcmtctftpptllzqllzflfrrgqgvgdvdfdbddprrrgccqvqnnmtmvmffpzzqggfbfnfwwqdqldqqlnqnttnbttrffnmmzwzjjtrjtrtmmqsmqmffqmfqfhhbthbhdhvdhvdvmvdmdhdshsqslldzztvvmzzdcccmbbhfhshrrrpsrrqqmdmmgdmmwdmdjdqqmcmttpgtgwgpwpprbrprhrsrllhsllprlplhppfzpffbhbccwdwbbrpbpvpqqmsspjssmbbmfmrmnrnwwgbwwbpwpjwwhqqgcqcvqccgffzpfftcffqlqjjznnlflhhlcczhzvhzhmzhmhfhnnqznntstwtggqjgjhggsvslltjlttfjjgffjzjwzzqzrrhlhzhbhphmhlmlzmzsmzmccvllgrrpbrbfbjfjttqjttdrdhhggqgddppqgpqgpgtptjptpllwccmwcmcpmcppdrrtstqqczqzvvlsltlddnvdvggcqqblqqsjqjttzhtzzszllqsqfqddqdbqddwqddfzzlczcscfsfpfdpdrpddsggcqchcfcpcssstwstwtggghvhqhzzqssjddwjwbjjsnjnfnwwglwwfnfhnnscsggzgjzzhzmmqfqsqwqrwqqqdtdcttzvvnbngbbcdbdggddnmddgzghhzgghwwbjbttlwlcctlccwwdhhrqrvrjjlglssgttpllwclwwtptwptwtvthtbhbzhbzhhrsrwwwnrwrfwfnwnhhnqqdjqjpqqwdwttzhttcdttvztzltzlzmzddrsdsfdsfftdfffmwffrjrffqrfqfsfqqqgqjggwzzrnnqfnqffdbfbtbbrpbrpbptpwttjmjjzrrhhqppdzdtdjttqwwtddjdzzmgzzhwwwdsdgssprsrgsgbbphhdpdwppnfppdqqwzzpbzzqwqpqsqhqdhqqtwwjnnmvmwvmmwwgjgzjjvcjcvcjcnjcncmmphmmvmwmwpwbbtbffhnhshgssgvgvrrbwbtbddqmqfqvvfqvqdvvdbvdbdcdfdlflmffrwwgmmttrztrrfrqrpqrrzjrjpjdpjprrnhhbhcbbcwwqlwwcssbddfrfjrfjfrjfjvvdmdtdzzlvzlzhzmhmhphchnnfqnffvccfpfbfpfqpprrmttzrzzjzmjmzjmmfvmmrzrqqdllgjlglcchssgllsbllrbrlrjlrrhhfwwsqwsstpssznzcznzqzssvtvtrrqwqvvtssgfsfhssljjnwjnjddjdggclcrrfsfhsstgtdtctfttvvsbvvbtbttcgcssjlslhlpljpppwzwnwdnngmgjjbzznwwdllrrfppshhvdhhldhdbbdbjbdjjrnjjzhzfhhsqqbqgmsbvnjsptlrsszlqfmgprvscphmqztbgtlrqvcgdzcptcqjncrdtfqnghnbmwwmcjgtjlbvqqzslgbbntrdfnvfjvfgcgngndjcspgwmpnsrqzzvzljbzlzzrwflrqqqmhsvqwbmdftnhwwzgqrlhddbbtwvbphljmstcjzvpjqwcnhlvpqvqdgvntgqzqwrlwbwvngwtqgrhznlzcvbwqmwncccjctrdzrmzjsvrmcfpjjcczhbvdfwhqvczggfmrspvprvvthvtqnsphpcsdmbrtbdqljvssdrhwjsrrlzprstpgqcbpmnpdgzgjttwcfrgjnsghmszlclgvmlsjrqfvflbnhwwphtvrnrbhdvdglcvgpzfsjpwwhtlvvdzthsrldfzhnlrblzsjjnwclqsqzgdbflhvpwcrtfbfbjcjttbjpvfgvfcswnqqwshbmqlscdzzwshfqwsvwnwzltbnrmzzhzvtwpzqcgwshpvzgtcmwrtrwctnpzbznnwqphnrgwljtrcwlqmvlndwrdrctztnmswslqmbjcmtlrmcpjvzccqszrnflqnqzttbhqlrhbmqdpscqvfgtdbnwjdcljwcbgbgjfzgrgpwqzqgbnrtpntfthhdbqmswvhnmwmszpghgjjzrbnbbfjblpstdfslmmmqfdcrhblqjqfphnldrvvfpnfrcvprjnqbzbspfpjtgqhnjbhnrwzcjvdbshhqpgrmzqpmjfmqwqvvdbddbsldwzzsrhnhsjjnvljrbwcnjrnjpmrrvfthftgptgtlpbgqffthflgftwcrqcqwqwrmrcmfrcqgmrnqjbscdcgrqlhjzthvzdgjbvpswflqcgsnlmgmvcsttsgmnqdtvwdvrndvfdcvrcwmqlmlhtrvthsndsrmnsfmdmfnpfmfhzjqmtcjzcrnsjdztztvgdtlrmbdmmstbfgpmmzthcslpvgrpgfljfgqlqhldfwvvvdvbzjtdtppbtrnqwsqztjrsjhtfrgmvsdngvsdzjgpwrldqpzdpvhljzpjvttwltdwcrhcbrgrvdrmpwvdwjchqsjfprbgtjtzggvgrgmlvvwqrjfprbbgjjqrtdfnrdffwbswbvqtqtfsrhsgrjhftqldhmcnmsnfflmdrzqdjmbqqgqsttdmtrrvfsjnccnhcpcvqtrzdjzrpwswmjvvgsgwvnmdgqwlctrlhqnsmczbwsjhmtgvdcgsndzlstcwchcztqqbtdwfvlljdvdlzljslgnzpmqvzfcvqhdzvgchffqgfwrnmwqzwgbzblpmvddlvnhglrhdnwzqwztzgjczjpwcjwmpnrnrhncfjfggrbphrjztwtfqmfjlwfhnqfftfghbnvtwgtmdzzrdrtmfrwhrrbhzmcllsgqzwzzqtgdggvzptvtdcpzmtmsfcfbjtzlbdrwhdbtdhhrgggmddnzsvjwgcdcqfppqwphfvlhmgqsznlhmgpnjvcvrwwppnphchgsrhjwjcpjggsrcwrvnllfgrmjltfzwhmbqwpwwzmrtlqcprrqztcgnghcbvzrbfptjmhtdcfhhffdbrswqpnpppnpqwtflrrmqgjzctmmvvvwzllbsfdvpqjtmvpjcpmjztscsgbdznfgcmtjzdqzwqrsvstnnvddcstzqjtnbsnlptpmbmfqmhppgnjrffqrtchgptbmwlwbwbcqqfngpbwtwdmlmdstmqwcwjtbwbbbhghgptmvhfmvqfvpwqzwnbjdhpwlgjgvprdjbnlzhnllssbpvzfzspwsscfpqtpdvtzvqncfrfrgddsdglqvpblmpcczlqfdmwzmgvrljhqtcglcvfhbdwhbttqqrjbqwhsrhrbjwmtqwqddvdggdwfsmnpbpvvgsqnvvrqntwmbzdnqpmmqtbnlsbmslpfmqjtgvbddhwvlvjtlrhqdpfnjwtbhwjwdrpgctbbrdqvbbnvgqwngrhqfvwzmlqtmhfqphnmczlbdpnbmpvwrsjbcnjnvcfgnsvlhpzdgdzgvfbgwdcrswznrggnghzssdwqvvlwftqhbnwdvghhvjlqqmcnqmvbwhrrnsswlwmwbsmpcpdzzgmcmqnzpvjpzqbwcsgdhqtqhcpbtqftvscmntsbdcbrndvlfhprpblzbjcpqhfljtvnvtgvrcgqbsgl

165
day06/part1.py Normal file
View File

@@ -0,0 +1,165 @@
from __future__ import annotations
from collections import deque
import os.path
import pathlib as pl
import re
import sys
import time
import typing as t
import urllib.error
import urllib.parse
import urllib.request
import pytest
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str):
four_window = deque(maxlen=4)
for idx, char in enumerate(s):
if char in four_window:
four_window.clear()
elif len(four_window) == 3:
return idx
four_window.append(char)
raise Exception('no answer')
@pytest.mark.parametrize(
('input_s', 'expected'),
(("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7))
)
#### HELPERS
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> None:
print(compute(pl.Path("input.txt").read_text()))
HERE = os.path.dirname(os.path.abspath(__file__))
def _get_cookie_headers() -> dict[str, str]:
with open(os.path.join(HERE, '../.env')) as f:
contents = f.read().strip()
return {'Cookie': contents}
def get_input(year: int, day: int) -> str:
url = f'https://adventofcode.com/{year}/day/{day}/input'
req = urllib.request.Request(url, headers=_get_cookie_headers())
return urllib.request.urlopen(req).read().decode()
def get_year_day() -> tuple[int, int]:
cwd = os.getcwd() # type: ignore
day_s = os.path.basename(cwd)
year_s = os.path.basename(os.path.dirname(cwd))
if not day_s.startswith('day') or not year_s.startswith('20'):
raise AssertionError(f'unexpected working dir: {cwd}')
return int(year_s), int(day_s[len('day'):])
def download_input() -> int:
year, day = get_year_day()
for _ in range(5):
try:
s = get_input(year, day)
except urllib.error.URLError as e:
print(f'zzz: not ready yet: {e}')
time.sleep(1)
else:
break
else:
raise SystemExit('timed out after attempting many times')
with open('input.txt', 'w') as f:
f.write(s)
inputs = s
if '\n' in inputs.strip():
print('splitting')
inputs = inputs.split('\n')
print(inputs[0])
if inputs[0].isnumeric():
print('ints')
inputs = list(map(int, inputs))
inputs = str(inputs).replace("'", '"')
lines = s.splitlines()
if len(lines) > 10:
for line in lines[:10]:
print(line)
print('...')
else:
print(lines[0][:80])
print('...')
return 0
TOO_QUICK = re.compile('You gave an answer too recently.*to wait.')
WRONG = re.compile(r"That's not the right answer.*?\.")
RIGHT = "That's the right answer!"
ALREADY_DONE = re.compile(r"You don't seem to be solving.*\?")
def _post_answer(year: int, day: int, part: int, answer: int) -> str:
params = urllib.parse.urlencode({'level': part, 'answer': answer})
req = urllib.request.Request(
f'https://adventofcode.com/{year}/day/{day}/answer',
method='POST',
data=params.encode(),
headers=_get_cookie_headers(),
)
resp = urllib.request.urlopen(req)
return resp.read().decode()
def submit_solution() -> int:
year, day = get_year_day()
part = get_part()
answer = compute(pl.Path("input.txt").read_text())
print(f'answer: {answer}')
contents = _post_answer(year=year, day=day, part=part, answer=answer)
for error_regex in (WRONG, TOO_QUICK, ALREADY_DONE):
error_match = error_regex.search(contents)
if error_match:
print(f'\033[41m{error_match[0]}\033[m')
return 1
if RIGHT in contents:
print(RIGHT)
return 0
else:
# unexpected output?
print(contents)
return 1
def get_part() -> t.Literal[1, 2]:
if __file__.endswith("2.py"):
return 2
return 1
if __name__ == '__main__':
if sys.argv[1] == "get_input":
print('getting input data...')
download_input()
elif sys.argv[1] == "submit":
submit_solution()
raise SystemExit(main())

47
day06/part2.py Normal file
View File

@@ -0,0 +1,47 @@
from __future__ import annotations
import argparse
import os.path
from collections import deque
import pytest
import support
INPUT_TXT = os.path.join(os.path.dirname(__file__), 'input.txt')
def compute(s: str):
four_window = deque(maxlen=14)
for idx, char in enumerate(s):
if char in four_window:
four_window.clear()
elif len(four_window) == 13:
return idx
four_window.append(char)
raise Exception('no answer')
@pytest.mark.parametrize(
('input_s', 'expected'),
(("mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7))
)
def test(input_s: str, expected: int) -> None:
assert compute(input_s) == expected
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('data_file', nargs='?', default=INPUT_TXT)
args = parser.parse_args()
with open(args.data_file) as f, support.timing():
print(compute(f.read()))
return 0
if __name__ == '__main__':
raise SystemExit(main())

28
make_new_day.py Normal file
View File

@@ -0,0 +1,28 @@
import pathlib as pl
import subprocess as sp
def main():
most_recent_day = get_most_recent_day()
sp.call(shell=True, args=f"cp -r day{most_recent_day:02} day{most_recent_day + 1:02}")
sp.call(shell=True, args=f"rm day{most_recent_day + 1:02}/part2.py")
sp.call(shell=True, args=f"cd day{most_recent_day + 1:02}/ && make d")
def get_most_recent_day() -> int:
most_recent = None
for item in pl.Path().iterdir():
if item.is_dir() and not item.name.startswith('.') and not item.name.startswith('_'):
day_num_str = item.name.split("day")[-1]
if day_num_str.startswith('0'):
day_num_str = day_num_str[-1]
day_num = int(day_num_str)
if most_recent is None or day_num > most_recent:
most_recent = day_num
if most_recent is None:
raise Exception
return most_recent
if __name__ == "__main__":
main()