Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Problems/Bingo-Check/bingo-check.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import type { FixedArray } from "../../utilities/types/fixedArray";
import type FixedArray from "../../utilities/types/fixedArray";
import bingoCheck from "./solver";

type CardType = FixedArray<FixedArray<"x" | number, 5>, 5>;
Expand Down
2 changes: 1 addition & 1 deletion Problems/Bingo-Check/solver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FixedArray } from "../../utilities/types/fixedArray";
import type FixedArray from "../../utilities/types/fixedArray";

export default function bingoCheck(card: FixedArray<FixedArray<"x" | number, 5>, 5>): boolean {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,39 @@ import { describe, expect, it } from "vitest";
import findPath from "./solver";

describe("Finds the correct path for given tickets", () => {
const input1 = [
{ start: "C", end: "F" },
{ start: "A", end: "C" },
{ start: "I", end: "Z" },
{ start: "F", end: "I" },
];

it("should return the correct path for 4 tickets", () => {
expect(findPath(input1)).toEqual(["A", "C", "F", "I", "Z"]);
expect(
findPath([
{ start: "C", end: "F" },
{ start: "A", end: "C" },
{ start: "I", end: "Z" },
{ start: "F", end: "I" },
])
).toEqual(["A", "C", "F", "I", "Z"]);
});

const input2 = [
{ start: "A", end: "C" },
{ start: "A", end: "B" },
{ start: "C", end: "B" },
{ start: "B", end: "A" },
{ start: "B", end: "C" },
];

it("should return the correct path for 5 tickets with same start destinations", () => {
expect(findPath(input2)).toEqual(["A", "B", "A", "C", "B", "C"]);
expect(
findPath([
{ start: "A", end: "C" },
{ start: "A", end: "B" },
{ start: "C", end: "B" },
{ start: "B", end: "A" },
{ start: "B", end: "C" },
])
).toEqual(["A", "B", "A", "C", "B", "C"]);
});

const input3 = [
{ start: "Y", end: "L" },
{ start: "D", end: "A" },
{ start: "A", end: "D" },
{ start: "R", end: "Y" },
{ start: "A", end: "R" },
];

it("should return the correct path for 5 tickets", () => {
expect(findPath(input3)).toEqual(["A", "D", "A", "R", "Y", "L"]);
expect(
findPath([
{ start: "Y", end: "L" },
{ start: "D", end: "A" },
{ start: "A", end: "D" },
{ start: "R", end: "Y" },
{ start: "A", end: "R" },
])
).toEqual(["A", "D", "A", "R", "Y", "L"]);
});

it("should return the correct path for 6 tickets which have the same start and end", () => {
Expand All @@ -52,10 +52,6 @@ describe("Finds the correct path for given tickets", () => {
});

describe("Throws the correct error when handling wrong input", () => {
it("should throw the correct error for an empty array", () => {
expect(() => findPath([])).toThrowError("It's not possible to find a path when no tickets are given!");
});

it("should throw the correct error when no start ticket (Ticket with start = 'A') is given", () => {
expect(() =>
findPath([
Expand Down
4 changes: 3 additions & 1 deletion Problems/Itinerary-In-Alphabetical-Order/solver.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type NonEmptyArray from "../../utilities/types/nonEmptyArray";

interface Ticket {
start: string;
end: string;
}

export default function findPath(tickets: Ticket[]): string[] {
export default function findPath(tickets: NonEmptyArray<Ticket>): string[] {
if (tickets.length <= 0) throw new Error("It's not possible to find a path when no tickets are given!");

const path = findTicketPath("A", tickets, ["A"]);
Expand Down
22 changes: 8 additions & 14 deletions Problems/Keyword-Cipher/keyword-cipher.test.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,32 @@
import { describe, expect, it } from "vitest";
import keyword_cipher from "./solver";
import keywordCipher from "./solver";

describe("Encrypt the word correct", () => {
it("should return keyabc for abchij", () => {
expect(keyword_cipher("keyword", "abchij")).toEqual("keyabc");
expect(keywordCipher("keyword", "abchij")).toEqual("keyabc");
});

it("should return pur for abc", () => {
expect(keyword_cipher("purplepineapple", "abc")).toEqual("pur");
expect(keywordCipher("purplepineapple", "abc")).toEqual("pur");
});

it("should return samucq for edabit", () => {
expect(keyword_cipher("mubashir", "edabit")).toEqual("samucq");
expect(keywordCipher("mubashir", "edabit")).toEqual("samucq");
});

it("should return eta for abc", () => {
expect(keyword_cipher("etaoinshrdlucmfwypvbgkjqxz", "abc")).toEqual("eta");
expect(keywordCipher("etaoinshrdlucmfwypvbgkjqxz", "abc")).toEqual("eta");
});

it("should return qxz for xyz", () => {
expect(keyword_cipher("etaoinshrdlucmfwypvbgkjqxz", "xyz")).toEqual("qxz");
expect(keywordCipher("etaoinshrdlucmfwypvbgkjqxz", "xyz")).toEqual("qxz");
});

it("should return eirfg for aeiou", () => {
expect(keyword_cipher("etaoinshrdlucmfwypvbgkjqxz", "aeiou")).toEqual("eirfg");
expect(keywordCipher("etaoinshrdlucmfwypvbgkjqxz", "aeiou")).toEqual("eirfg");
});

it("should return EiRfg for AeIou", () => {
expect(keyword_cipher("etaoinshrdlucmfwypvbgkjqxz", "AeIou.")).toEqual("EiRfg.");
});
});

describe("While trying to encrypt a word throws the correct error", () => {
it("should throw the correct error for an equation with no result", () => {
expect(() => keyword_cipher("", "")).toThrowError("An empty word cannot be encrypted");
expect(keywordCipher("etaoinshrdlucmfwypvbgkjqxz", "AeIou.")).toEqual("EiRfg.");
});
});
6 changes: 4 additions & 2 deletions Problems/Keyword-Cipher/solver.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export default function keyword_cipher(keyword: string, word: string): string {
import type NonEmptyString from "../../utilities/types/nonEmptyString";

export default function keywordCipher<T extends string>(keyword: NonEmptyString<T>, word: string): string {
// biome-ignore format: the array should not be formatted
const alphabetA = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
// biome-ignore format: the array should not be formatted
const alphabetB = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

if (word.length <= 0) throw new Error("An empty word cannot be encrypted");

let extraAlphabet = keyword;
let extraAlphabet: NonEmptyString<T> | string = keyword;

extraAlphabet.split("").forEach((e) => {
if (alphabetA.some((value) => value === e)) alphabetA.splice(alphabetA.indexOf(e), 1);
Expand Down
4 changes: 2 additions & 2 deletions Problems/Missing-Number/solver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { FixedArray } from "../../utilities/types/fixedArray";
import type { IntRange } from "../../utilities/types/intRange";
import type FixedArray from "../../utilities/types/fixedArray";
import type IntRange from "../../utilities/types/intRange";

export default function missingNumber(array: FixedArray<IntRange<1, 11>, 9>): number {
return 55 - array.reduce((preVal, val) => preVal + val, 0);
Expand Down
6 changes: 0 additions & 6 deletions Problems/Nom-Nom-Numbers/nom-nom-numbers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,3 @@ describe("Returns the correct remaining numbers", () => {
expect(nom_nom([2])).toEqual([2]);
});
});

// describe("Another description for the tests. Maybe those which are throwing errors", () => {
// it("should return something for this input", () => {
// expect(true).toEqual(true);
// });
// });
4 changes: 3 additions & 1 deletion utilities/types/fixedArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ type GrowToSize<T, A extends Array<T>, N extends number> = {
1: GrowToSize<T, Grow<T, A>, N>;
}[A["length"] extends N ? 0 : 1];

export type FixedArray<T, N extends number> = GrowToSize<T, [], N>;
type FixedArray<T, N extends number> = GrowToSize<T, [], N>;

export default FixedArray;
5 changes: 4 additions & 1 deletion utilities/types/intRange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ type Enumerate<N extends number, Acc extends number[] = []> = Acc["length"] exte
? Acc[number]
: Enumerate<N, [...Acc, Acc["length"]]>;

export type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
// A number from F to T
type IntRange<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;

export default IntRange;
7 changes: 7 additions & 0 deletions utilities/types/nonEmptyArray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Source - https://stackoverflow.com/a/56006703
// Posted by jcalz, modified by community. See post 'Timeline' for change history
// Retrieved 2026-05-03, License - CC BY-SA 4.0

type NonEmptyArray<T> = [T, ...T[]];

export default NonEmptyArray;
7 changes: 7 additions & 0 deletions utilities/types/nonEmptyString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Source - https://stackoverflow.com/a/69252250
// Posted by Grochni
// Retrieved 2026-05-03, License - CC BY-SA 4.0

type NonEmptyString<T extends string> = "" extends T ? never : T;

export default NonEmptyString;
Loading