diff --git a/2025/composer.json b/2025/composer.json
index 98ade79..4874634 100644
--- a/2025/composer.json
+++ b/2025/composer.json
@@ -1,21 +1,22 @@
{
- "name": "danchadwick/aoc-2025",
- "description": "Advent of code 2025",
- "type": "project",
- "autoload": {
- "psr-4": {
- "Aoc2025\\": "src/"
- }
- },
- "authors": [
- {
- "name": "dan612",
- "email": "daniel.chadwick612@gmail.com"
- }
- ],
- "minimum-stability": "dev",
- "require": {},
- "scripts": {
- "start": "sh start.sh"
+ "name": "danchadwick/aoc-2025",
+ "description": "Advent of code 2025",
+ "type": "project",
+ "autoload": {
+ "psr-4": {
+ "Aoc2025\\": "src/"
}
+ },
+ "authors": [
+ {
+ "name": "dan612",
+ "email": "daniel.chadwick612@gmail.com"
+ }
+ ],
+ "minimum-stability": "dev",
+ "require": {},
+ "scripts": {
+ "start": "sh start.sh",
+ "frontend": "sass theme/style.scss theme/style.css"
+ }
}
diff --git a/2025/day_1/day_1.php b/2025/day_1/day_1.php
deleted file mode 100644
index e69de29..0000000
diff --git a/2025/index.php b/2025/index.php
index 8d2ad88..a277616 100644
--- a/2025/index.php
+++ b/2025/index.php
@@ -2,4 +2,16 @@
require_once __DIR__ . '/vendor/autoload.php';
-echo "These are the results of the AoC 2025 challenge:\n";
+use Aoc2025\Days\Day1;
+use Aoc2025\Services\Template;
+
+$day_1 = new Day1();
+$day_1_answer = $day_1->run();
+
+$template = new Template('main.html');
+$substitutions = [
+ 'day_1_answer' => $day_1_answer,
+];
+$response = $template->render($substitutions);
+
+echo $response;
diff --git a/2025/inputs/day_1_input.txt b/2025/inputs/day_1_input.txt
new file mode 100644
index 0000000..53287c7
--- /dev/null
+++ b/2025/inputs/day_1_input.txt
@@ -0,0 +1,10 @@
+L68
+L30
+R48
+L5
+R60
+L55
+L1
+L99
+R14
+L82
diff --git a/2025/src/Day.php b/2025/src/Day.php
new file mode 100644
index 0000000..669dee8
--- /dev/null
+++ b/2025/src/Day.php
@@ -0,0 +1,29 @@
+getInputFile('day_1_input.txt');
+ return "12345";
+ }
+
+
+}
diff --git a/2025/src/Services/Template.php b/2025/src/Services/Template.php
new file mode 100644
index 0000000..7fc9c3b
--- /dev/null
+++ b/2025/src/Services/Template.php
@@ -0,0 +1,56 @@
+template = file_get_contents('templates/' . $template_name);
+ }
+
+ /**
+ * Renders the template and returns the result.
+ */
+ public function render($substitutions = []) {
+ $this->replaceSections();
+
+ if ($substitutions) {
+ foreach ($substitutions as $key => $value) {
+ $this->template = str_replace('{{ ' . $key . ' }}', $value, $this->template);
+ }
+ }
+
+ return $this->template;
+ }
+
+ /**
+ * Replaces all sections in the template with the contents of the included file.
+ */
+ public function replaceSections() {
+ preg_match_all('/\[\[\s*(.+?)\s*\]\]/', $this->template, $matches);
+
+ foreach ($matches[0] as $i => $placeholder) {
+ $filename = $matches[1][$i];
+ $template_path = rtrim('templates', '/') . '/' . $filename;
+
+ if (file_exists($template_path)) {
+ $contents = file_get_contents($template_path);
+ }
+ else {
+ $contents = "";
+ }
+ $this->template = str_replace($placeholder, $contents, $this->template);
+ }
+
+ return $this->template;
+ }
+
+}
diff --git a/2025/start.sh b/2025/start.sh
index 1b23442..53cda72 100644
--- a/2025/start.sh
+++ b/2025/start.sh
@@ -1,2 +1,3 @@
-!#/usr/bin/env bash
-php -S localhost:8088 index.php
+#!/bin/bash
+
+php -S 127.0.0.1:8088
diff --git a/2025/templates/head.html b/2025/templates/head.html
new file mode 100644
index 0000000..0b2b672
--- /dev/null
+++ b/2025/templates/head.html
@@ -0,0 +1,7 @@
+
+ Advent of Code 2025
+
+
+
+
+
diff --git a/2025/templates/main.html b/2025/templates/main.html
new file mode 100644
index 0000000..56ba7de
--- /dev/null
+++ b/2025/templates/main.html
@@ -0,0 +1,47 @@
+
+
+ [[ head.html ]]
+
+
+
+
Advent of Code 2025
+
+
+
+
+
Day 1
+
+
+
Part 1: {{ day_1_answer }}
+
Part 2:
+
+
+
+
+
+
+
Day 2
+
+
+
Part 1:
+
Part 2:
+
+
+
+
+
+
+
Day 3
+
+
+
Part 1:
+
Part 2:
+
+
+
+
+
+
+
+
+
diff --git a/2025/theme/images/.DS_Store b/2025/theme/images/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/2025/theme/images/.DS_Store differ
diff --git a/2025/theme/images/holiday.jpg b/2025/theme/images/holiday.jpg
new file mode 100644
index 0000000..0184de9
Binary files /dev/null and b/2025/theme/images/holiday.jpg differ
diff --git a/2025/theme/js/main.js b/2025/theme/js/main.js
new file mode 100644
index 0000000..b874407
--- /dev/null
+++ b/2025/theme/js/main.js
@@ -0,0 +1 @@
+// console.log('hello world');
diff --git a/2025/theme/partials/cards.scss b/2025/theme/partials/cards.scss
new file mode 100644
index 0000000..ebfb61a
--- /dev/null
+++ b/2025/theme/partials/cards.scss
@@ -0,0 +1,33 @@
+.card {
+ background-color: var(--primary-2);
+ padding: 15px;
+ flex: 1;
+
+ h2 {
+ margin: 0;
+ color: var(--primary-0);
+ border-bottom: 1px solid var(--primary-3);
+ margin-bottom: 12px;
+ font-size: 2.5rem;
+ }
+
+ &-wrapper {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ vertical-align: top;
+ align-items: flex-start;
+ gap: 12px;
+ }
+
+ &-body {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ justify-content: space-between;
+
+ p {
+ color: var(--primary-0);
+ }
+ }
+}
diff --git a/2025/theme/partials/font-scale.scss b/2025/theme/partials/font-scale.scss
new file mode 100644
index 0000000..ea906a5
--- /dev/null
+++ b/2025/theme/partials/font-scale.scss
@@ -0,0 +1,14 @@
+.fs-1 {
+ font-size: 2rem;
+ line-height: 2.2rem;
+
+ @media (min-width: 768px) {
+ font-size: 3rem;
+ line-height: 3.2rem;
+ }
+
+ @media (min-width: 1024px) {
+ font-size: 4rem;
+ line-height: 4.2rem;
+ }
+}
diff --git a/2025/theme/style.css b/2025/theme/style.css
new file mode 100644
index 0000000..1e2cda3
--- /dev/null
+++ b/2025/theme/style.css
@@ -0,0 +1,188 @@
+@import url("https://fonts.googleapis.com/css2?family=Bitcount+Prop+Double+Ink:wght@100..900&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
+:root {
+ --primary-0: #230C33;
+ --primary-1: #592E83;
+ --primary-2: #9984D4;
+ --primary-3: #CAA8F5;
+ --primary-accent: #B27C66;
+}
+
+.accent {
+ color: var(--primary-accent);
+}
+
+.bitcount {
+ font-family: "Bitcount Prop Double Ink", system-ui;
+ font-optical-sizing: auto;
+ font-weight: 500;
+ font-style: normal;
+ font-variation-settings: "slnt" 0, "CRSV" 0.5, "ELSH" 0, "ELXP" 0, "SZP1" 0, "SZP2" 0, "XPN1" 0, "XPN2" 0, "YPN1" 0, "YPN2" 0;
+}
+
+.montserrat {
+ font-family: "Montserrat", system-ui;
+}
+
+.light {
+ font-weight: 100;
+}
+
+.regular {
+ font-weight: 500;
+}
+
+.bold {
+ font-weight: 700;
+}
+
+.bolder {
+ font-weight: 900;
+}
+
+body {
+ min-height: 100vh;
+ background-image: url("images/holiday.jpg");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ color: var(--primary-3);
+ font-family: "Montserrat", system-ui;
+ font-size: 16px;
+ line-height: 1.5;
+}
+@media (min-width: 768px) {
+ body {
+ font-size: 18px;
+ line-height: 1.6;
+ }
+}
+
+.overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--primary-1);
+ opacity: 0.85;
+ z-index: -1;
+}
+
+h1 {
+ color: var(--primary-0);
+ text-align: center;
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: "Montserrat", system-ui;
+ font-weight: bold;
+ line-height: 1.2;
+}
+@media (min-width: 768px) {
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ line-height: 1.3;
+ }
+}
+
+p {
+ margin: 0;
+}
+
+a {
+ color: var(--primary-accent);
+ text-decoration: none;
+}
+a:hover {
+ text-decoration: underline;
+}
+
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ background-color: var(--primary-0);
+ border: none;
+ border-radius: 4px;
+ color: var(--primary-text);
+ cursor: pointer;
+ font-family: "Montserrat", system-ui;
+ font-size: 16px;
+ font-weight: bold;
+ line-height: 1.2;
+ padding: 8px 16px;
+ text-align: center;
+ text-decoration: none;
+ transition: background-color 0.2s ease-in-out;
+}
+button:hover {
+ background-color: var(--primary-1);
+}
+button:active {
+ background-color: var(--primary-2);
+}
+
+.container {
+ max-width: 1024px;
+ margin: 0 auto;
+ padding: 0 16px;
+}
+
+.fs-1 {
+ font-size: 2rem;
+ line-height: 2.2rem;
+}
+@media (min-width: 768px) {
+ .fs-1 {
+ font-size: 3rem;
+ line-height: 3.2rem;
+ }
+}
+@media (min-width: 1024px) {
+ .fs-1 {
+ font-size: 4rem;
+ line-height: 4.2rem;
+ }
+}
+
+.card {
+ background-color: var(--primary-2);
+ padding: 15px;
+ flex: 1;
+}
+.card h2 {
+ margin: 0;
+ color: var(--primary-0);
+ border-bottom: 1px solid var(--primary-3);
+ margin-bottom: 12px;
+ font-size: 2.5rem;
+}
+.card-wrapper {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-evenly;
+ vertical-align: top;
+ align-items: flex-start;
+ gap: 12px;
+}
+.card-body {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ justify-content: space-between;
+}
+.card-body p {
+ color: var(--primary-0);
+}
+
+/*# sourceMappingURL=style.css.map */
diff --git a/2025/theme/style.css.map b/2025/theme/style.css.map
new file mode 100644
index 0000000..329d22f
--- /dev/null
+++ b/2025/theme/style.css.map
@@ -0,0 +1 @@
+{"version":3,"sourceRoot":"","sources":["style.scss","partials/font-scale.scss","partials/cards.scss"],"names":[],"mappings":"AACQ;AAGR;EAEE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA,yBACE;;;AAYJ;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EAXF;IAYI;IACA;;;;AAIJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;AAAA;AAAA;AAAA;AAAA;EAKE;EACA;EACA;;AAEA;EATF;AAAA;AAAA;AAAA;AAAA;IAUI;;;;AAIJ;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;AAGF;EACE;;;AAIJ;EACE;EACA;EACA;;;ACpJF;EACE;EACA;;AAEA;EAJF;IAKI;IACA;;;AAGF;EATF;IAUI;IACA;;;;ACXJ;EACE;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE","file":"style.css"}
\ No newline at end of file
diff --git a/2025/theme/style.scss b/2025/theme/style.scss
new file mode 100644
index 0000000..041986e
--- /dev/null
+++ b/2025/theme/style.scss
@@ -0,0 +1,154 @@
+// Fonts.
+@import url('https://fonts.googleapis.com/css2?family=Bitcount+Prop+Double+Ink:wght@100..900&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
+
+// Variables
+:root {
+ // colors
+ --primary-0: #230C33;
+ --primary-1: #592E83;
+ --primary-2: #9984D4;
+ --primary-3: #CAA8F5;
+ --primary-accent: #B27C66;
+}
+
+.accent {
+ color: var(--primary-accent);
+}
+
+.bitcount {
+ font-family: "Bitcount Prop Double Ink", system-ui;
+ font-optical-sizing: auto;
+ font-weight: 500;
+ font-style: normal;
+ font-variation-settings:
+ "slnt" 0,
+ "CRSV" 0.5,
+ "ELSH" 0,
+ "ELXP" 0,
+ "SZP1" 0,
+ "SZP2" 0,
+ "XPN1" 0,
+ "XPN2" 0,
+ "YPN1" 0,
+ "YPN2" 0;
+}
+
+.montserrat {
+ font-family: "Montserrat", system-ui;
+}
+
+.light {
+ font-weight: 100;
+}
+
+.regular {
+ font-weight: 500;
+}
+
+.bold {
+ font-weight: 700;
+}
+
+.bolder {
+ font-weight: 900;
+}
+
+body {
+ min-height: 100vh;
+ background-image: url("images/holiday.jpg");
+ background-size: cover;
+ background-position: center;
+ background-repeat: no-repeat;
+ color: var(--primary-3);
+ font-family: "Montserrat", system-ui;
+ font-size: 16px;
+ line-height: 1.5;
+
+ @media (min-width: 768px) {
+ font-size: 18px;
+ line-height: 1.6;
+ }
+}
+
+.overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: var(--primary-1);
+ opacity: 0.85;
+ z-index: -1;
+}
+
+h1 {
+ color: var(--primary-0);
+ text-align: center;
+}
+
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-family: "Montserrat", system-ui;
+ font-weight: bold;
+ line-height: 1.2;
+
+ @media (min-width: 768px) {
+ line-height: 1.3;
+ }
+}
+
+p {
+ margin: 0;
+}
+
+a {
+ color: var(--primary-accent);
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ background-color: var(--primary-0);
+ border: none;
+ border-radius: 4px;
+ color: var(--primary-text);
+ cursor: pointer;
+ font-family: "Montserrat", system-ui;
+ font-size: 16px;
+ font-weight: bold;
+ line-height: 1.2;
+ padding: 8px 16px;
+ text-align: center;
+ text-decoration: none;
+ transition: background-color 0.2s ease-in-out;
+
+ &:hover {
+ background-color: var(--primary-1);
+ }
+
+ &:active {
+ background-color: var(--primary-2);
+ }
+}
+
+.container {
+ max-width: 1024px;
+ margin: 0 auto;
+ padding: 0 16px;
+}
+
+// partials
+@import "partials/font-scale";
+@import "partials/cards";