diff --git a/studium/favicon.ico b/studium/favicon.ico
new file mode 100644
index 0000000..9b36118
Binary files /dev/null and b/studium/favicon.ico differ
diff --git a/studium/index.html b/studium/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/studium/it-lab/images/favicon.ico b/studium/it-lab/images/favicon.ico
new file mode 100644
index 0000000..9b36118
Binary files /dev/null and b/studium/it-lab/images/favicon.ico differ
diff --git a/studium/it-lab/images/logo.svg b/studium/it-lab/images/logo.svg
new file mode 100644
index 0000000..197b65d
--- /dev/null
+++ b/studium/it-lab/images/logo.svg
@@ -0,0 +1,12 @@
+
\ No newline at end of file
diff --git a/studium/it-lab/images/symbols.svg b/studium/it-lab/images/symbols.svg
new file mode 100644
index 0000000..da5b542
--- /dev/null
+++ b/studium/it-lab/images/symbols.svg
@@ -0,0 +1,191 @@
+
+
+
+
diff --git a/studium/it-lab/index.html b/studium/it-lab/index.html
new file mode 100644
index 0000000..d0b5d6a
--- /dev/null
+++ b/studium/it-lab/index.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Minesweeper by Elias Fink
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/studium/it-lab/script.js b/studium/it-lab/script.js
new file mode 100644
index 0000000..337bb8f
--- /dev/null
+++ b/studium/it-lab/script.js
@@ -0,0 +1,306 @@
+window.addEventListener('load', () => {
+ minesweeper.init();
+});
+
+const minesweeper = {
+
+ init() {
+ this.logic = remoteLogic;
+ this.generateBody();
+ this.newGame('small');
+ },
+
+ // ------------------------------------ //
+ // ----- Basic Body Structure ----- //
+ // ------------------------------------ //
+
+ generateBody() {
+ const body = document.body;
+
+ const container = document.createElement('div');
+ container.id = 'container';
+ body.appendChild(container);
+
+ container.append(this.getHeader(), this.getMain(), this.getButtons(), this.getFooter());
+ },
+
+ getHeader() {
+ const header = document.createElement('header');
+
+ const title = document.createElement('div');
+ title.id = 'title';
+ header.appendChild(title);
+
+ const heading = document.createElement('h1');
+ heading.innerText = 'Minesweeper';
+
+ const subheading = document.createElement('p');
+ subheading.innerText = 'by Elias Fink';
+
+ title.append(heading, subheading);
+
+ return header;
+ },
+
+ getMain() {
+ const main = document.createElement('main');
+
+ return main;
+ },
+
+ getButtons() {
+ const buttons = document.createElement('div');
+ buttons.id = 'buttons';
+
+ const smallButton = this.createButton('small');
+ const mediumButton = this.createButton('medium');
+ const largeButton = this.createButton('large');
+
+ buttons.append(smallButton, mediumButton, largeButton);
+
+ return buttons;
+ },
+
+ getFooter() {
+ const footer = document.createElement('footer');
+
+ const copyright = document.createElement('span');
+ copyright.innerHTML = 'Copyright © 2024 Elias Fink';
+
+ const webLink = document.createElement('span');
+ webLink.innerHTML = 'Web Version';
+
+ const gitLink = document.createElement('span');
+ gitLink.innerHTML = 'Git Repository';
+
+ footer.append(copyright, webLink, gitLink);
+
+ return footer;
+ },
+
+ // ---------------------------------- //
+ // ----- Buttons and Fields ----- //
+ // ---------------------------------- //
+
+ createButton(type) {
+ const button = document.createElement('button');
+ button.id = type;
+ button.innerText = type;
+
+ button.addEventListener('click', () => {
+ this.newGame(type);
+ });
+
+ return button;
+ },
+
+ generatePlayfield(size) {
+ const playfield = document.querySelector('main');
+ playfield.innerText = '';
+
+ for (let row = 0; row < size; row++) {
+ for (let col = 0; col < size; col++) {
+ playfield.appendChild(this.createCell(row, col));
+ }
+ }
+ },
+
+ createCell(row, col) {
+ const cell = document.createElement('div');
+ cell.classList.add('cell', 'covered');
+
+ cell.dataset.x = col;
+ cell.dataset.y = row;
+
+ cell.style.width = `calc(100% / ${this.size} - 2px)`;
+ cell.style.height = `calc(100% / ${this.size} - 2px)`;
+
+ this.cellEventListeners(cell);
+
+ return cell;
+ },
+
+ cellEventListeners(cell) {
+ cell.addEventListener('click', (event) => {
+ this.cellLeftClickHandler(event);
+ });
+ cell.addEventListener('contextmenu', (event) => {
+ this.cellRightClickHandler(event);
+ });
+
+ cell.addEventListener('touchstart', (event) => {
+ this.cellTouchStartHandler(event);
+ });
+ cell.addEventListener('touchend', (event) => {
+ this.cellTouchEndHandler(event);
+ });
+ },
+
+ // -------------------------- //
+ // ----- Game Start ----- //
+ // -------------------------- //
+
+ gameModes: [
+ {
+ name: 'small',
+ size: 9,
+ mines: 10
+ },
+ {
+ name: 'medium',
+ size: 16,
+ mines: 40
+ },
+ {
+ name: 'large',
+ size: 24,
+ mines: 150
+ },
+ ],
+
+ async newGame(gameMode) {
+ for (const mode of this.gameModes) {
+ if (mode.name == gameMode) {
+ this.size = mode.size;
+ this.mines = mode.mines;
+ }
+ }
+
+ this.generatePlayfield(this.size);
+
+ await this.logic.init(this.size, this.mines);
+ },
+
+ // ------------------------------------ //
+ // ----- Click/Touch Handling ----- //
+ // ------------------------------------ //
+
+ async cellLeftClickHandler(event) {
+ event.preventDefault();
+
+ const x = event.target.dataset.x;
+ const y = event.target.dataset.y;
+
+ const result = await this.logic.sweep(x, y);
+
+ if (result.minehit) {
+ this.logic.gameLost(event, result.mines);
+ } else {
+ this.logic.uncoverCell(x, y, result.minesAround);
+ for (const cell of result.emptyCells) {
+ this.logic.uncoverCell(cell.x, cell.y, cell.minesAround);
+ }
+ if (result.userwins) {
+ this.logic.gameWon();
+ }
+ }
+ },
+
+ cellRightClickHandler(event) {
+ event.preventDefault();
+
+ event.target.classList.toggle('symbol-f');
+ },
+
+ cellTouchStartHandler(event) {
+ event.preventDefault();
+
+ this.touchStartTime = new Date().getTime();
+ },
+
+ cellTouchEndHandler(event) {
+ event.preventDefault();
+
+ const touchDuration = new Date().getTime() - this.touchStartTime;
+ if (touchDuration < 500) {
+ this.cellLeftClickHandler(event);
+ } else {
+ this.cellRightClickHandler(event);
+ }
+ }
+
+};
+
+
+
+
+
+// -------------------------------------------------- //
+// -------------------------------------------------- //
+// -------------------------------------------------- //
+
+
+
+
+
+const remoteLogic = {
+
+ // ----------------------------- //
+ // ----- Field Filling ----- //
+ // ----------------------------- //
+
+ async init(size, mines) {
+ this.serverUrl = 'https://www2.hs-esslingen.de/~melcher/it/minesweeper/?';
+ const request = `request=init&size=${size}&mines=${mines}&userid=elfiit00`;
+ const response = await this.fetchAndDecode(request);
+ this.token = response.token;
+ },
+
+ async fetchAndDecode(request) {
+ return fetch(this.serverUrl + request).then(response => response.json());
+ },
+
+ // ------------------------------- //
+ // ----- Move Processing ----- //
+ // ------------------------------- //
+
+ async sweep(x, y) {
+ const request = `request=sweep&token=${this.token}&x=${x}&y=${y}`;
+ return this.fetchAndDecode(request);
+ },
+
+ // ------------------------------- //
+ // ----- Cell Uncovering ----- //
+ // ------------------------------- //
+
+ getCell(x, y) {
+ return document.querySelector(`[data-x="${x}"][data-y="${y}"]`);
+ },
+
+ uncoverCell(x, y, symbol) {
+ this.getCell(x, y).classList.remove('covered');
+
+ if (symbol) {
+ this.getCell(x, y).classList.add(`symbol-${symbol}`);
+ }
+ },
+
+ // ------------------------ //
+ // ----- Game End ----- //
+ // ------------------------ //
+
+ gameLost(event, mines) {
+ event.target.id = 'mine-hit';
+ for (const m of mines) {
+ this.uncoverCell(m.x, m.y, 'm');
+ }
+ this.displayOverlay('Game Over');
+ },
+
+ gameWon() {
+ this.displayOverlay('Victory');
+ },
+
+ displayOverlay(text) {
+ const overlay = document.createElement('div');
+ overlay.id = 'overlay';
+
+ const div = document.createElement('div');
+ div.innerText = text;
+ overlay.appendChild(div);
+
+ const main = document.querySelector('main');
+ main.appendChild(overlay);
+ }
+
+};
\ No newline at end of file
diff --git a/studium/it-lab/styles.css b/studium/it-lab/styles.css
new file mode 100644
index 0000000..b641166
--- /dev/null
+++ b/studium/it-lab/styles.css
@@ -0,0 +1,231 @@
+/* ------------------------- */
+/* General */
+/* ------------------------- */
+
+:root {
+ --blue-1: #001A33;
+ --blue-2: #004D99;
+ --blue-3: #0080FF;
+ --blue-4: #66B3FF;
+ --blue-5: #CCE6FF;
+ --grey-1: #161A1D;
+ --grey-2: #434D56;
+ --grey-3: #708090;
+ --grey-4: #A9B3BC;
+ --grey-5: #E2E6E9;
+ --peach-fuzz: #ffbe98;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+html, body {
+ height: 100%;
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+}
+
+#container {
+ width: min(100vw, 55.555vh);
+ height: min(100vh, 180vw);
+ margin: 0 auto;
+}
+
+
+/* ------------------------ */
+/* Header */
+/* ------------------------ */
+
+
+header {
+ height: calc(4 * 100% / 18);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 20px;
+ background-color: var(--blue-3);
+ color: #fff;
+}
+
+#title h1 {
+ font-size: 40px;
+ margin-bottom: 5px;
+}
+
+#title p {
+ font-size: 20px;
+}
+
+@media (min-width: 420px) {
+
+ header {
+ background-image: url(images/logo.svg);
+ background-size: 100px;
+ background-position: right 20px center;
+ background-repeat: no-repeat;
+ }
+
+}
+
+
+/* ------------------------------- */
+/* Playing Field */
+/* ------------------------------- */
+
+main {
+ position: relative;
+ height: calc(10 * 100% / 18);
+ display: flex;
+ flex-wrap: wrap;
+ align-content: space-between;
+ justify-content: space-between;
+ border: 1px solid var(--grey-3);
+}
+
+.cell {
+ flex-shrink: 0;
+ background-color: var(--blue-5);
+ border: 1px solid var(--grey-3);
+}
+
+.covered {
+ background-color: var(--grey-4);
+}
+
+.symbol-1, .symbol-2, .symbol-3, .symbol-4, .symbol-5, .symbol-6, .symbol-7, .symbol-8, .symbol-f.covered, .symbol-m {
+ background-size: 1000%;
+ background-image: url(images/symbols.svg);
+}
+
+.symbol-1 {
+ background-position: calc(100% * 0 / 9);
+}
+
+.symbol-2 {
+ background-position: calc(100% * 1 / 9);
+}
+
+.symbol-3 {
+ background-position: calc(100% * 2 / 9);
+}
+
+.symbol-4 {
+ background-position: calc(100% * 3 / 9);
+}
+
+.symbol-5 {
+ background-position: calc(100% * 4 / 9);
+}
+
+.symbol-6 {
+ background-position: calc(100% * 5 / 9);
+}
+
+.symbol-7 {
+ background-position: calc(100% * 6 / 9);
+}
+
+.symbol-8 {
+ background-position: calc(100% * 7 / 9);
+}
+
+.symbol-f.covered {
+ background-position: calc(100% * 8 / 9);
+}
+
+.symbol-m {
+ background-position: calc(100% * 9 / 9);
+}
+
+#mine-hit {
+ background-color: var(--peach-fuzz);
+}
+
+#overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: rgba(0, 0, 0, 0.4);
+}
+
+#overlay div {
+ padding: 16px 32px;
+ border-radius: 16px;
+ background-color: var(--blue-4);
+ font-size: 48px;
+}
+
+#overlay div:hover {
+ opacity: 0.2;
+ transition: 0.2s;
+}
+
+
+/* ------------------------- */
+/* Buttons */
+/* ------------------------- */
+
+#buttons {
+ height: calc(3 * 100% / 18);
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ padding: 0 20px;
+ background-color: var(--grey-5);
+}
+
+button {
+ font-size: 16px;
+ text-transform: capitalize;
+ padding: 15px 30px;
+ margin: 0 2px;
+ color: #fff;
+ background-color: var(--blue-3);
+ border: 2px solid var(--blue-3);
+ cursor: pointer;
+ transition: 0.2s;
+}
+
+button:hover {
+ color: var(--blue-3);
+ background-color: transparent;
+}
+
+
+/* ------------------------ */
+/* Footer */
+/* ------------------------ */
+
+footer {
+ height: calc(100% / 18);
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ padding: 0 20px;
+ background-color: var(--grey-2);
+ color: #fff;
+}
+
+footer a {
+ color: #fff;
+ text-decoration: none;
+ border-bottom: 1px solid #fff;
+}
+
+footer a:hover {
+ border-bottom: 0;
+}
+
+@media (max-width: 480px) {
+
+ footer span:not(:first-child) {
+ display: none;
+ }
+
+}
\ No newline at end of file