Hacky quick generalise

This commit is contained in:
Anupam Jain 2024-12-02 18:51:33 +05:30
parent cf1dd7c28e
commit 9395bea26a
18 changed files with 169 additions and 91 deletions

3
aoc Executable file
View file

@ -0,0 +1,3 @@
# The `aoc` part is required as the first argument is the name of the script
node --max-old-space-size=8192 -e "let main = await import('./output/PCC.Main/index.js'); main.main()" -- aoc --aoc "$@"

2
ebc Executable file
View file

@ -0,0 +1,2 @@
# The `ecc` part is required as the first argument is the name of the script
node --max-old-space-size=8192 -e "let main = await import('./output/PCC.Main/index.js'); main.main()" -- ebc --ebc "$@"

1
pcc
View file

@ -1,2 +1,3 @@
# The `pcc` part is required as the first argument is the name of the script
node --max-old-space-size=8192 -e "let main = await import('./output/PCC.Main/index.js'); main.main()" -- pcc "$@"

View file

@ -1,4 +1,4 @@
module Year2024.Quest01 where
module EveryBodyCodes.Year2024.Quest01 where
import PCC.Lib

View file

@ -1,4 +1,4 @@
module Year2024.Quest02 where
module EveryBodyCodes.Year2024.Quest02 where
import PCC.Lib
@ -55,9 +55,12 @@ part2 input = fold do
overlapsAll i = Array.any (overlaps i) allIndices
Array.length $ Array.filter identity $ map overlapsAll (0 .. (String.length sentence - 1))
part3 :: String -> Effect Unit
part3 input = part2 input
part3 _input = log $ "Part 3 ==> <TODO>"
transpose :: Array String -> Array String
transpose matrix = map fromChars $ Array.transpose $ map chars matrix
--------------------------------------------------------------------------------

View file

@ -1,10 +0,0 @@
module Main where
import Control.Alternative (pure)
import Data.Unit (Unit, unit)
import Effect (Effect)
main :: Effect Unit
main = do
pure unit

View file

@ -30,7 +30,7 @@ import Data.Show (show)
import Data.String as S
import Data.String as String
import Data.String.CodeUnits (fromCharArray, toCharArray)
import Data.String.Pattern (Pattern(..))
import Data.String.Pattern (Pattern)
import Data.Unit (Unit)
import Effect (Effect)
import Node.Encoding (Encoding(..))

View file

@ -2,35 +2,53 @@ import fs from "fs";
// import request from "request";
// import path from "path";
import { exec } from "child_process";
import {AOC, EBC} from '../PCC.Types/index.js';
// import dotenv from "dotenv";
'use strict';
// dotenv.config();
export const bootstrap = function (year, quest) {
function handleErr(rest) {
return function(err, body) {
if (err) {
console.log(err);
return;
}
if(rest) rest(body);
};
}
export const bootstrap = function (env) {
const year = env.year;
let quest = env.quest;
const puzzle = env.puzzle == AOC.value? 'AOC' : 'EBC';
// Left-pad quest!
quest = `${quest}`;
quest = `${env.quest}`;
if (quest.length == 1) {
quest = `0${quest}`;
}
// Write file
fs.mkdir(`src/Year${year}`, { recursive: true }, function (err) {
if (err) {
console.log(err);
return;
}
fs.readFile('templates/QuestXX.purs.template', 'utf8', function (err, body) {
fs.mkdir(`src/${puzzle}/Year${year}`, { recursive: true }, handleErr(function () {
fs.readFile(`templates/${puzzle}.purs.template`, 'utf8', handleErr(function (body) {
let b = body.replace(/__YEAR__/g, year).replace(/__QUEST__/g, quest);
fs.writeFile(`src/Year${year}/Quest${quest}.purs`, b, function (err) {
if (err) {
console.log(err);
return;
}
console.log(`Open src/Year${year}/Quest${quest}.purs in your editor`);
});
});
});
fs.writeFile(`src/${puzzle}/Year${year}/Quest${quest}.purs`, b, handleErr(function () {
console.log(`Open src/${puzzle}/Year${year}/Quest${quest}.purs in your editor`);
console.log(`Creating blank input files at location ../../quests/${puzzle}/year${year}`);
fs.mkdir(`quests/${puzzle}/year${year}`, { recursive: true }, handleErr(function () {
fs.writeFile(`quests/${puzzle}/year${year}/quest${quest}-1`, 'ADD INPUT HERE', handleErr());
fs.writeFile(`quests/${puzzle}/year${year}/quest${quest}-2`, 'ADD INPUT HERE', handleErr());
if(puzzle === "EBC") fs.writeFile(`quests/${puzzle}/year${year}/quest${quest}-3`, 'ADD INPUT HERE', handleErr());
}));
}))
}));
}));
};
export const download = function (year, quest, cookie, filepath, cb) {
export const download = function (env, cookie, filepath, cb) {
// TODO
let year = env.year;
let quest = env.quest;
const puzzle = env.puzzle == AOC.value? 'aoc' : 'ebc';
const puzzleName = env.puzzle == AOC.value? 'AOC' : 'EBC';
return;
// const exists = fs.existsSync(filepath);
@ -67,23 +85,36 @@ export const download = function (year, quest, cookie, filepath, cb) {
// }
};
export async function run(year, quest, part, inputfilepath) {
export async function run(env, part) {
let year = env.year;
let quest = `${env.quest}`;
// Left-pad quest!
quest = `${quest}`;
if (quest.length == 1) {
quest = `0${quest}`;
}
const puzzle = env.puzzle == AOC.value? 'AOC' : 'EBC';
runner(year, quest, puzzle, part, `quests/${puzzle}/year${year}/quest${quest}-${part}`);
};
export async function test(env, part) {
let year = env.year;
let quest = `${env.quest}`;
// Left-pad quest!
if (quest.length == 1) {
quest = `0${quest}`;
}
const puzzle = env.puzzle == AOC.value? 'AOC' : 'EBC';
runner(year, quest, puzzle, part, `tests/${puzzle}/year${year}/quest${quest}-${part}`);
};
async function runner(year, quest, puzzle, part, inputfilepath) {
exec('spago build', async function (err, stdout, stderr) {
if (err) {
console.log(err);
return;
}
let Module = await import(`../Year${year}.Quest${quest}/index.js`);
fs.readFile(inputfilepath, 'utf8', function (err, body) {
if (err) {
console.log(err);
return;
}
let Module = await import(`../${puzzle}.Year${year}.Quest${quest}/index.js`);
fs.readFile(inputfilepath, 'utf8', handleErr(function(body) {
if (part == 1 || !part) {
console.time("Obtained in");
Module.part1(body)();
@ -94,12 +125,12 @@ export async function run(year, quest, part, inputfilepath) {
Module.part2(body)();
console.timeEnd("Obtained in");
}
if (part == 3 || !part) {
if (part == 3 || (!part && puzzle === 'EBC')) {
console.time("Obtained in");
Module.part3(body)();
console.timeEnd("Obtained in");
}
});
}));
});
};

View file

@ -1,11 +1,12 @@
module PCC.Main where
import Options.Applicative
import Control.Alternative ((<|>))
import Control.Apply ((<*>))
import Control.Bind (bind, (=<<))
import Data.Distributive (collect)
import Data.Eq ((==))
import Data.Foldable (for_)
import Data.Functor ((<$>))
import Data.Functor ((<$>), map)
import Data.Maybe (Maybe(..), fromMaybe, optional)
import Data.Semigroup ((<>))
import Data.Show (show)
@ -13,51 +14,57 @@ import Data.Unit (Unit)
import Effect (Effect)
import Effect.Uncurried as EFn
import Node.Path (FilePath)
import PCC.Lib (inputFileLocationYearQuest, testFileLocationYearQuest)
type Year = Int
type Quest = Int
type Part = Int
type Cookie = String
data Command = Bootstrap Year Quest | Download Year Quest Part | Run Year Quest (Maybe Part) | Test Year Quest (Maybe Part)
import Options.Applicative (Parser, ParserInfo, argument, command, execParser, flag', fullDesc, header, help, helper, info, int, long, metavar, option, progDesc, short, subparser, (<**>))
import PCC.Lib (inputFileLocationYearQuest)
import PCC.Types (Command(..), Cookie, Env, Part, Puzzle(..), WithPuzzle)
configOptions :: Parser Command
configOptions = subparser
configOptions =
mkConfig <$> (flagAOC <|> flagECC) <*> commandOptions
where
mkConfig puzzle makeCommand = makeCommand puzzle
flagAOC = flag' AOC (long "aoc" <> help "Advent of Code puzzles")
flagECC = flag' EBC (long "ebc" <> help "Everybody Codes puzzles")
commandOptions :: Parser (Puzzle -> Command)
commandOptions = subparser
( command "bootstrap" (info bootstrapOptions ( progDesc "Bootstrap a solution for a particular quest" ))
<> command "download" (info downloadOptions ( progDesc "Download the puzzle input for a particular quest" ))
<> command "run" (info runOptions ( progDesc "Run the solution for a particular quest" ))
<> command "test" (info testOptions ( progDesc "Run the solution with the test input for a particular quest, the test input must be manually saved in a file called test<quest>" ))
)
bootstrapOptions :: Parser Command
bootstrapOptions =
Bootstrap
<$> argument int ( metavar "YEAR" )
<*> argument int ( metavar "QUEST" )
envOptions :: WithPuzzle Parser Env
envOptions = mkEnv
<$> argument int ( metavar "YEAR" )
<*> argument int ( metavar "QUEST" )
where
mkEnv year quest = \puzzle -> {year, quest, puzzle} -- puzzle: fromMaybe AOC mpuzzle}
downloadOptions :: Parser Command
bootstrapOptions :: WithPuzzle Parser Command
bootstrapOptions =
map Bootstrap <$> envOptions
downloadOptions :: WithPuzzle Parser Command
downloadOptions =
Download
<$> argument int ( metavar "YEAR" )
<*> argument int ( metavar "QUEST" )
collect Download
<$> envOptions
<*> argument int ( metavar "PART" )
runOptions :: Parser Command
runOptions :: WithPuzzle Parser Command
runOptions =
Run
<$> argument int ( metavar "YEAR" )
<*> argument int ( metavar "QUEST" )
collect Run
<$> envOptions
<*> optional (option int
( long "part"
<> short 'p'
<> metavar "PART"
<> help "Use this to run only one part from that quest. Valid options are 1 or 2 or 3" ))
testOptions :: Parser Command
testOptions :: WithPuzzle Parser Command
testOptions =
Test
<$> argument int ( metavar "YEAR" )
<*> argument int ( metavar "QUEST" )
collect Test
<$> envOptions
<*> optional (option int
( long "part"
<> short 'p'
@ -76,27 +83,26 @@ opts = info (configOptions <**> helper)
foreign import pcc_cookie :: Effect String
doit :: Command -> Effect Unit
doit (Bootstrap year quest) = do
doit (Bootstrap env) = do
-- doit (Download year quest part)
EFn.runEffectFn2 bootstrap year quest
doit (Download year quest part) = do
EFn.runEffectFn1 bootstrap env
doit (Download env part) = do
cookie <- pcc_cookie
loc <- inputFileLocationYearQuest (show year) (show quest) (show part)
EFn.runEffectFn4 download year quest cookie loc
doit (Run year quest mpart) = case mpart of
Nothing -> runParts year quest [1,2,3]
Just p -> runParts year quest [p]
doit (Test year quest mpart) = do
loc <- testFileLocationYearQuest (show year) (show quest)
EFn.runEffectFn4 run year quest (fromMaybe 0 mpart) loc
loc <- inputFileLocationYearQuest (show env.year) (show env.quest) (show part)
EFn.runEffectFn3 download env cookie loc
doit (Run env mpart) = case mpart of
Nothing -> runParts env (if env.puzzle == AOC then [1,2] else [1,2,3])
Just p -> runParts env [p]
doit (Test env mpart) = do
EFn.runEffectFn2 test env (fromMaybe 0 mpart)
runParts :: Int -> Int -> Array Int -> Effect Unit
runParts year quest parts = for_ parts \part -> do
loc <- inputFileLocationYearQuest (show year) (show quest) (show part)
EFn.runEffectFn4 run year quest part loc
runParts :: Env -> Array Int -> Effect Unit
runParts env parts = for_ parts \part -> do
EFn.runEffectFn2 run env part
foreign import bootstrap :: EFn.EffectFn2 Year Quest Unit
foreign import download :: EFn.EffectFn4 Year Quest Cookie FilePath Unit
foreign import bootstrap :: EFn.EffectFn1 Env Unit
foreign import download :: EFn.EffectFn3 Env Cookie FilePath Unit
-- TODO: 'run' is async
foreign import run :: EFn.EffectFn4 Year Quest Part String Unit
foreign import run :: EFn.EffectFn2 Env Part Unit
foreign import test :: EFn.EffectFn2 Env Part Unit

18
src/PCC/Types.purs Normal file
View file

@ -0,0 +1,18 @@
module PCC.Types where
import Data.Eq (class Eq)
import Data.Maybe (Maybe)
type Year = Int
type Quest = Int
type Part = Int
type Cookie = String
data Puzzle
= AOC -- Advent of Code
| EBC -- Everybody Codes
derive instance Eq Puzzle
type Env = {year :: Year, quest :: Quest, puzzle :: Puzzle}
type WithPuzzle :: forall k. (Type -> k) -> Type -> k
type WithPuzzle f a = f (Puzzle -> a)
data Command = Bootstrap Env | Download Env Part | Run Env (Maybe Part) | Test Env (Maybe Part)

View file

@ -0,0 +1,25 @@
module AOC.Year__YEAR__.Quest__QUEST__ where
import PCC.Lib
import Data.Function (($))
import Data.Functor (map)
import Data.Semigroup ((<>))
import Data.Unit (Unit)
import Effect (Effect)
import Effect.Class.Console (log)
--------------------------------------------------------------------------------
-- Write your solutions here
part1 :: String -> Effect Unit
part1 input = do
let result = "<TODO>"
log $ "Part 1 ==> " <> result
part2 :: String -> Effect Unit
part2 input = do
let result = "<TODO>"
log $ "Part 2 ==> " <> result
--------------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
module Year__YEAR__.Quest__QUEST__ where
module EBC.Year__YEAR__.Quest__QUEST__ where
import PCC.Lib
import Data.Function (($))
@ -26,5 +26,4 @@ part3 input = do
let result = "<TODO>"
log $ "Part 3 ==> " <> result
--------------------------------------------------------------------------------