Skip to content

Commit

Permalink
New challenge: Square-difference-free
Browse files Browse the repository at this point in the history
  • Loading branch information
shape-warrior-t committed Jul 7, 2024
1 parent e0f4b4b commit a02c311
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 27 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Challenges:
- [Extract Strings](typescript-challenges/code/extract-strings.ts) ([tests](typescript-challenges/code/extract-strings.test.ts)) [TypeScript, unit testing, property-based testing, data structures & algorithms, parsing, state machines]
- [Rainfall + tests](rust_challenges/src/rainfall.rs) [Rust, unit testing, data structures & algorithms, dynamic programming, complexity analysis, macros]
- [Island Sizes + tests](rust_challenges/src/island_sizes.rs) [Rust, unit testing, data structures & algorithms, flood fill, complexity analysis, macros, object-oriented programming]
- [Square-difference-free](typescript-challenges/code/square-difference-free.ts) ([tests](typescript-challenges/code/square-difference-free.test.ts)) [TypeScript, data structures & algorithms, object-oriented programming]

Helper code:

Expand Down
61 changes: 34 additions & 27 deletions typescript-challenges/code/square-difference-free.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,6 @@

import assert from 'node:assert/strict';

/**
* Data type modelling a perfect square distance between two numbers.
*
* Consists of an origin integer (`origin`, available as `this.origin`),
* an integer square root of a distance (`sqrtDist`, available as `this.sqrtDist`),
* and a destination integer (`dest`, not directly available on the object)
* such that `origin + sqrtDist^2 = dest`.
*/
interface SquareDistance {
origin: bigint;
sqrtDist: bigint;
}

/** Yield the elements of OEIS sequence A030193. */
export default function* squareDifferenceFree(): Generator<bigint, never> {
/*
Expand All @@ -43,31 +30,51 @@ export default function* squareDifferenceFree(): Generator<bigint, never> {
NOTE: the data in the above is organized in a way that
prioritizes understandability over precise accuracy to the actual implementation.
For efficiency, `{0 + 4^2 = 16, 2 + 3^2 = 11, 5 + 3^2 = 14, 7 + 2^2 = 11}`
For efficiency purposes, `{0 + 4^2 = 16, 2 + 3^2 = 11, 5 + 3^2 = 14, 7 + 2^2 = 11}`
is actually organized as something closer to
`{11 = 2 + 3^2 = 7 + 2^2, 14 = 5 + 3^2, 16 = 0 + 4^2}`.
*/
const destToDistance = new Map<bigint, SquareDistance[]>();
const destToDistances = new Map<bigint, SquareDistance[]>();
for (let dest = 0n; ; dest++) {
if (!destToDistance.has(dest)) {
if (!destToDistances.has(dest)) {
yield dest;
destToDistance.set(dest, [{ origin: dest, sqrtDist: 0n }]);
const distance = new SquareDistance(dest, 0n);
destToDistances.set(dest, [distance]);
}
for (const { origin, sqrtDist } of destToDistance.get(dest)!) {
assert(origin + sqrtDist ** 2n === dest);
const nextSqrtDist = sqrtDist + 1n;
const nextDest = origin + nextSqrtDist ** 2n;
if (!destToDistance.has(nextDest)) {
destToDistance.set(nextDest, []);
for (const distance of destToDistances.get(dest)!) {
assert(dest === distance.dest);
const nextDistance = distance.next();
const nextDest = nextDistance.dest;
if (!destToDistances.has(nextDest)) {
destToDistances.set(nextDest, []);
}
destToDistance
.get(nextDest)!
.push({ origin, sqrtDist: nextSqrtDist });
destToDistances.get(nextDest)!.push(nextDistance);
}
/*
Not necessary for correctness,
but it's more memory-efficient to delete entries that will no longer be accessed.
*/
assert(destToDistance.delete(dest));
assert(destToDistances.delete(dest));
}
}

/** Data type modelling a perfect square distance between two numbers. */
class SquareDistance {
/** Create a new distance. */
constructor(
/** The origin (smaller of the two numbers). */
readonly origin: bigint,
/** The square root of the distance between the two numbers. */
readonly sqrtDist: bigint,
) {}

/** The destination (larger of the two numbers). */
get dest(): bigint {
return this.origin + this.sqrtDist ** 2n;
}

/** Return a new distance with the same origin and the next larger possible destination. */
next(): SquareDistance {
return new SquareDistance(this.origin, this.sqrtDist + 1n);
}
}

0 comments on commit a02c311

Please sign in to comment.