generated from lsmor/template-advent-of-code
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aoc-hs
executable file
·250 lines (206 loc) · 6.77 KB
/
aoc-hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#!/bin/bash
YEAR=2023
AOC_BASE_URL="https://adventofcode.com/$YEAR/"
# Function to create a new Advent of Code solution for a given day
create_new_solution() {
echo "Creating a new Advent of Code template for day $number."
local number="$1"
local d="day-$number"
if [ -f "./.env" ]; then
echo "found .env file..."
export "$(grep -v '^#' .env | xargs)"
fi
# Create a directory for the day
mkdir -p inputs
mkdir -p solutions
# Create the Haskell solution file
module_template="module Main where
import System.Environment (getArgs)
import Data.ByteString qualified as B
{- Types for your input and your solution
- Input should as the type of your input parameter. AOC, typically uses arrays, matrices or complex data structures.
- Solution should be the type of your solution. Typically is an Int, but It can be other things, like a list of numbers
or a list of characters
-}
type Input = B.ByteString -- default to Bytestring, but very likely you'll need to change it
type Solution = Int
-- | parser transforms a raw bytestring (from your ./input/day-X.input) to your Input type.
-- this is intended to use attoparsec for such a transformation. You can use Prelude's
-- String if it fit better for the problem
parser :: B.ByteString -> Input
parser = undefined
-- | The function which calculates the solution for part one
solve1 :: Input -> Solution
solve1 = error \"Part 1 Not implemented\"
-- | The function which calculates the solution for part two
solve2 :: Input -> Solution
solve2 = error \"Part 2 Not implemented\"
main :: IO ()
main = do
-- run this with cabal run -- day-x <part-number> <file-to-solution>
-- example: cabal run -- day-3 2 \"./input/day-3.example\"
-- will run part two of day three with input file ./input/day-3.example
[part, filepath] <- getArgs
input <- parser <$> B.readFile filepath -- use parser <$> readFile filepath if String is better
if read @Int part == 1
then do
putStrLn \"solution to problem 1 is:\"
print $ solve1 input
else do
putStrLn \"solution to problem 2 is:\"
print $ solve2 input
"
echo Creating files...
echo "$module_template" > "./solutions/$d.hs"
# Create an empty input file
touch "./inputs/$d.example"
# Download the input data from Advent of Code
if [ "$download" == true ]; then
# Ensure that the AOC_SESSION cookie is set
if [ -z "$AOC_SESSION" ]; then
echo "AOC_SESSION is not set. Please provide your Advent of Code session cookie:"
read -r AOC_SESSION
fi
curl -o "./inputs/$d.input" -b "session=${AOC_SESSION}" "$AOC_BASE_URL"day/"$number"/input
else
touch "./inputs/$d.input"
fi
# Append the day to the advent-of-code.cabal file
cabal_day="executable ${d}
import: deps
hs-source-dirs:
solutions
main-is: ${d}.hs
"
echo "$cabal_day" >> advent-of-code.cabal
echo "Created a new Advent of Code solution for day $number."
}
run_solution() {
local number="$1"
local part="$2"
local file_name="$3"
local d="day-$number"
# Check if the file exists
if [ ! -f "$file_name" ]; then
echo "input file $file_name does not exist."
exit 1
fi
# Check if the number is a positive integer
if ! [[ "$number" =~ ^([1-9]|1\d|2[0-5])$ ]]; then
echo "Invalid day: $number. It should be between 1 and 25"
exit 1
fi
# Check if the number is a positive integer
if ! [[ "$part" =~ ^[1-2]+$ ]]; then
echo "Invalid part number: $part. It should be 1 or 2"
exit 1
fi
echo "Running solution for a new Advent of Code template for day $number, Part $part"
cabal run "$d" -- "$part" "$file_name"
}
# Check if the first argument is a subcommand and shift it out
if [ "$1" == "new" ] || [ "$1" == "run" ]; then
subcommand="$1"
shift
fi
while getopts ":d:-:f:ei:p:" opt; do
case $opt in
d)
number="$OPTARG"
;;
f)
run_command=f
run_filename="$OPTARG"
;;
e)
run_command=example
;;
i)
run_command=input
;;
-)
run_command="$OPTARG"
;;
p)
part="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done
# Now you can check the parsed options and execute the corresponding actions.
if [ "$subcommand" == "new" ]; then
if [ -z "$number" ]; then
echo "Missing day for 'new' command."
exit 1
fi
if [ -z "$run_command" ]; then
download=true
fi
case "$run_command" in
no-curl)
download=false
;;
esac
create_new_solution "$number"
elif [ "$subcommand" == "run" ]; then
if [ -z "$number" ]; then
echo "Missing day for 'run' command. Use option -d <day-number>"
exit 1
fi
if [ -z "$part" ]; then
echo "Missing part for 'run' command. Use option -p <part-number>"
exit 1
fi
if [ -z "$run_command" ]; then
# Default to '--input' if no filename is provided
run_command=input
fi
case "$run_command" in
example)
run_filename="./inputs/day-$number.example"
;;
input)
run_filename="./inputs/day-$number.input"
;;
f) ;;
*)
echo "unknown file. Use -f <file-path> for custom files"
esac
run_solution "$number" "$part" "$run_filename"
else
echo "Usage: aoc-hs [new -d <day> [--no-curl] | run -d <day> -p <part> [-f <file-name> | --example | -e | --input | -i]]
Description:
This tool simplifies Advent of Code solutions in Haskell by creating templates and handling input files. No need to learn Cabal!
Subcommand: new
Create a new Advent of Code solution for the specified day. It creates a main module, modifies the .cabal file, and downloads the input data.
Usage: aoc-hs new -d <day>
Example: aoc-hs new -d 3
aoc-hs new -d 3 --no-curl
Options:
-d <day> Specify the day for the Advent of Code puzzle (1-25).
--no-curl It wont download your personal AoC input file. You don't have you provide a cookie with this option
Subcommand: run
Run an Advent of Code solution for the specified day and part. The input data is read from a file which can be supplied via -f or you can
use shortcuts --example and --input. Default --input
Usage: aoc-hs run -d <day> -p <part> [-f <file-name> | --example | -e | --input | -i]
Example: aoc-hs run -d 3 -p 2 --example
aoc-hs run -d 3 -p 3 -e
aoc-hs run -d 3 -p 2 --input
aoc-hs run -d 3 -p 2 -i
aoc-hs run -d 3 -p 2 -f my-input-file.txt
Options:
-d <day> Specify the day for the Advent of Code puzzle (1-25).
-p <part> Specify the part of the puzzle (1 or 2).
-f <file-name> Specify a custom input file to use.
--example, -e Use the example input file (./inputs/day-<day>.example) as input.
--input, -i (Default) Use the puzzle input file (./inputs/day-<day>.input) as input.
"
exit 1
fi