Skip to content

Commit

Permalink
new MixIns for Sequence and IntRange for Day 3 of 2023
Browse files Browse the repository at this point in the history
  • Loading branch information
norganos committed Dec 3, 2023
1 parent 3ac1b17 commit d926261
Show file tree
Hide file tree
Showing 8 changed files with 393 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# AoC Lib

This is a semi-private collection of helpers to solve [Advent of code](http://adventofcode.com) puzzles.
This is a semi-private collection of helpers to solve [Advent of code](https://adventofcode.com) puzzles.
9 changes: 9 additions & 0 deletions lib/src/main/kotlin/de/linkel/aoc/utils/IntRangeMixIn.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.linkel.aoc.utils

fun IntRange.intersects(other: IntRange): Boolean {
return (this.first <= other.first && this.last >= other.first) || (other.first <= this.first && other.last >= this.first)
}

fun IntRange.extend(front: Int = 0, back: Int = 0): IntRange {
return IntRange(this.first - front, this.last + back)
}
68 changes: 68 additions & 0 deletions lib/src/main/kotlin/de/linkel/aoc/utils/SequenceMixIn.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package de.linkel.aoc.utils

fun <T> Sequence<T>.prepend(element: T): Sequence<T> {
return if (this is ConcatSequence<T>) {
ConcatSequence(listOf(sequenceOf(element)) + this.sequences)
} else {
ConcatSequence(listOf(sequenceOf(element), this))
}
}
fun <T> Sequence<T>.prepend(other: Sequence<T>): Sequence<T> {
return if (this is ConcatSequence<T>) {
ConcatSequence(listOf(other) + this.sequences)
} else {
ConcatSequence(listOf(other, this))
}
}
fun <T> Sequence<T>.append(element: T): Sequence<T> {
return if (this is ConcatSequence<T>) {
ConcatSequence(this.sequences + listOf(sequenceOf(element)))
} else {
ConcatSequence(listOf(this, sequenceOf(element)))
}
}
fun <T> Sequence<T>.append(other: Sequence<T>): Sequence<T> {
return if (this is ConcatSequence<T>) {
ConcatSequence(this.sequences + listOf(other))
} else {
ConcatSequence(listOf(this, other))
}
}
operator fun <T> Sequence<T>.plus(other: Sequence<T>): Sequence<T> {
return if (this is ConcatSequence<T>) {
ConcatSequence(this.sequences + listOf(other))
} else {
ConcatSequence(listOf(this, other))
}
}

class ConcatSequence<T>(
val sequences: List<Sequence<T>>
): Sequence<T> {
override fun iterator(): Iterator<T> {
return ConcatIterator(sequences.map { it.iterator() })
}
}

class ConcatIterator<T>(
iterators: List<Iterator<T>>
): Iterator<T> {
private val parents = iterators.toMutableList()
private var current: Iterator<T>? = null

private fun cycleIfNecessary() {
while (current?.hasNext() != true && parents.isNotEmpty()) {
current = parents.removeAt(0)
}
}

override fun hasNext(): Boolean {
cycleIfNecessary()
return current?.hasNext() == true
}

override fun next(): T {
cycleIfNecessary()
return current?.next() ?: throw NoSuchElementException()
}
}
118 changes: 118 additions & 0 deletions lib/src/test/kotlin/de/linkel/aoc/utils/IntRangeMixInTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package de.linkel.aoc.utils

import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class IntRangeMixInTest {
@Test
fun `1 to 3 and 4 to 6 do not intersect`() {
Assertions.assertThat(
(1..3).intersects(4..6)
).isFalse()
}

@Test
fun `10 to 30 and 4 to 6 do not intersect`() {
Assertions.assertThat(
(10..30).intersects(4..6)
).isFalse()
}

@Test
fun `1 to 3 and 2 to 4 intersect`() {
Assertions.assertThat(
(1..3).intersects(2..4)
).isTrue()
}

@Test
fun `1 to 3 and 3 to 4 intersect`() {
Assertions.assertThat(
(1..3).intersects(3..4)
).isTrue()
}

@Test
fun `-1 to 1 and 0 to 4 intersect`() {
Assertions.assertThat(
(-1..1).intersects(0..4)
).isTrue()
}

@Test
fun `-3 to -1 and -2 to 4 intersect`() {
Assertions.assertThat(
(-3..-1).intersects(-2..4)
).isTrue()
}

@Test
fun `1 to 5 and 5 to 10 intersect`() {
Assertions.assertThat(
(1..5).intersects(5..10)
).isTrue()
}

@Test
fun `1 to 5 and 4 to 5 intersect`() {
Assertions.assertThat(
(1..5).intersects(4..5)
).isTrue()
}

@Test
fun `1 to 5 and 3 to 4 intersect`() {
Assertions.assertThat(
(1..5).intersects(3..4)
).isTrue()
}

@Test
fun `1 to 5 and 5 to 5 intersect`() {
Assertions.assertThat(
(1..5).intersects(5..5)
).isTrue()
}

@Test
fun `2 to 4 extended by 1 at front is 1 to 4`() {
Assertions.assertThat(
(2..4).extend(front = 1)
).isEqualTo(1..4)
}

@Test
fun `2 to 4 extended by 2 at front is 0 to 4`() {
Assertions.assertThat(
(2..4).extend(front = 2)
).isEqualTo(0..4)
}

@Test
fun `2 to 4 extended by 3 at front is -1 to 4`() {
Assertions.assertThat(
(2..4).extend(front = 3)
).isEqualTo(-1..4)
}

@Test
fun `2 to 4 extended by 1 at back is 2 to 5`() {
Assertions.assertThat(
(2..4).extend(back = 1)
).isEqualTo(2..5)
}

@Test
fun `2 to 4 extended by 2 at back is 2 to 6`() {
Assertions.assertThat(
(2..4).extend(back = 2)
).isEqualTo(2..6)
}

@Test
fun `2 to 4 extended by 2 at front and back is 0 to 6`() {
Assertions.assertThat(
(2..4).extend(front = 2, back = 2)
).isEqualTo(0..6)
}
}
69 changes: 69 additions & 0 deletions lib/src/test/kotlin/de/linkel/aoc/utils/SequenceConcatTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package de.linkel.aoc.utils

import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class SequenceConcatTest {
@Test
fun `1,2,3 can be prepended with 0`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).prepend(0).toList()
).isEqualTo(listOf(0,1,2,3))
}

@Test
fun `1,2,3 can be extended with 4`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).append(4).toList()
).isEqualTo(listOf(1,2,3,4))
}

@Test
fun `1,2,3 can be prepended with 0 and extended with 4`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).prepend(0).append(4).toList()
).isEqualTo(listOf(0,1,2,3,4))
}

@Test
fun `1,2,3 can be extended with 4 and prepended with 0`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).append(4).prepend(0).toList()
).isEqualTo(listOf(0,1,2,3,4))
}

@Test
fun `1,2,3 can be prepended with -1,0`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).prepend(sequenceOf(-1,0)).toList()
).isEqualTo(listOf(-1,0,1,2,3))
}

@Test
fun `1,2,3 can be extended with 4,5`() {
Assertions.assertThat(
sequenceOf(1, 2, 3).append(sequenceOf(4,5)).toList()
).isEqualTo(listOf(1,2,3,4,5))
}

@Test
fun `1,2 + 3 can be extended with 4 and prepended with 0`() {
Assertions.assertThat(
sequenceOf(1, 2).append(3).append(4).prepend(0).toList()
).isEqualTo(listOf(0,1,2,3,4))
}

@Test
fun `1,2 + 3 can be extended with 4,5 and prepended with -1,0`() {
Assertions.assertThat(
sequenceOf(1, 2).append(3).append(sequenceOf(4,5)).prepend(sequenceOf(-1,0)).toList()
).isEqualTo(listOf(-1,0,1,2,3,4,5))
}

@Test
fun `0,1 + 2,3 + 4,5 works`() {
Assertions.assertThat(
(sequenceOf(0, 1) + sequenceOf(2, 3) + sequenceOf(4, 5)).toList()
).isEqualTo(listOf(0,1,2,3,4,5))
}
}
31 changes: 29 additions & 2 deletions lib/src/test/kotlin/de/linkel/aoc/utils/TopListTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,28 @@ import org.junit.jupiter.api.Test

class TopListTest {
@Test
fun `top 3 list with 3 elements works`() {
val top3 = TopList<Int>(3).plus(listOf(1, 2, 5, 3, 4)).toList()
fun `empty top 3 list works`() {
val top3 = TopList<Int>(3)
Assertions.assertThat(top3).hasSize(0)
Assertions.assertThat(top3.isEmpty()).isTrue()
}

@Test
fun `default collection methods work`() {
val top3 = TopList<Int>(3).plus(listOf(1, 2, 5, 3, 4))
Assertions.assertThat(top3).hasSize(3)
Assertions.assertThat(top3).contains(5)
Assertions.assertThat(top3).contains(4)
Assertions.assertThat(top3).contains(3)
Assertions.assertThat(top3.isEmpty()).isFalse()
Assertions.assertThat(top3.contains(3)).isTrue()
Assertions.assertThat(top3.containsAll(listOf(5, 4))).isTrue()
Assertions.assertThat(top3.first()).isEqualTo(5)
}

@Test
fun `top 3 list with 3 elements in 2 batches works`() {
val top3 = TopList<Int>(3).plus(listOf(1, 2, 5)).plus(listOf(3, 4)).toList()
Assertions.assertThat(top3).hasSize(3)
Assertions.assertThat(top3).contains(5)
Assertions.assertThat(top3).contains(4)
Expand All @@ -16,6 +36,13 @@ class TopListTest {

@Test
fun `top 3 list with 1 element works`() {
val top3 = TopList<Int>(3).plus(23).toList()
Assertions.assertThat(top3).hasSize(1)
Assertions.assertThat(top3).contains(23)
}

@Test
fun `top 3 list with 1 element in list works`() {
val top3 = TopList<Int>(3).plus(listOf(23)).toList()
Assertions.assertThat(top3).hasSize(1)
Assertions.assertThat(top3).contains(23)
Expand Down
72 changes: 72 additions & 0 deletions lib/src/test/kotlin/de/linkel/aoc/utils/grid/AreaTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package de.linkel.aoc.utils.grid

import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class AreaTest {
@Test
fun `basic properties work`() {
val area = Area(1, 2, 10, 5)
Assertions.assertThat(area.origin).isEqualTo(Point(1, 2))
Assertions.assertThat(area.northWest).isEqualTo(Point(1, 2))
Assertions.assertThat(area.northEast).isEqualTo(Point(10, 2))
Assertions.assertThat(area.southWest).isEqualTo(Point(1, 6))
Assertions.assertThat(area.southEast).isEqualTo(Point(10, 6))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(10, 5))
}

@Test
fun `can extend to into east`() {
val area = Area(0, 0, 3, 3).extendTo(Point(5, 1))
Assertions.assertThat(area.origin).isEqualTo(Point(0, 0))
Assertions.assertThat(area.northWest).isEqualTo(Point(0, 0))
Assertions.assertThat(area.northEast).isEqualTo(Point(5, 0))
Assertions.assertThat(area.southWest).isEqualTo(Point(0, 2))
Assertions.assertThat(area.southEast).isEqualTo(Point(5, 2))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(6, 3))
}

@Test
fun `can extend to into west`() {
val area = Area(0, 0, 3, 3).extendTo(Point(-1, 1))
Assertions.assertThat(area.origin).isEqualTo(Point(-1, 0))
Assertions.assertThat(area.northWest).isEqualTo(Point(-1, 0))
Assertions.assertThat(area.northEast).isEqualTo(Point(2, 0))
Assertions.assertThat(area.southWest).isEqualTo(Point(-1, 2))
Assertions.assertThat(area.southEast).isEqualTo(Point(2, 2))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(4, 3))
}

@Test
fun `can extend to into north`() {
val area = Area(0, 0, 3, 3).extendTo(Point(0, -1))
Assertions.assertThat(area.origin).isEqualTo(Point(0, -1))
Assertions.assertThat(area.northWest).isEqualTo(Point(0, -1))
Assertions.assertThat(area.northEast).isEqualTo(Point(2, -1))
Assertions.assertThat(area.southWest).isEqualTo(Point(0, 2))
Assertions.assertThat(area.southEast).isEqualTo(Point(2, 2))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(3, 4))
}

@Test
fun `can extend to into south`() {
val area = Area(0, 0, 3, 3).extendTo(Point(0, 3))
Assertions.assertThat(area.origin).isEqualTo(Point(0, 0))
Assertions.assertThat(area.northWest).isEqualTo(Point(0, 0))
Assertions.assertThat(area.northEast).isEqualTo(Point(2, 0))
Assertions.assertThat(area.southWest).isEqualTo(Point(0, 3))
Assertions.assertThat(area.southEast).isEqualTo(Point(2, 3))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(3, 4))
}

@Test
fun `can be moved`() {
val area = Area(0, 0, 3, 3).plus(Vector(2, 1))
Assertions.assertThat(area.origin).isEqualTo(Point(2, 1))
Assertions.assertThat(area.northWest).isEqualTo(Point(2, 1))
Assertions.assertThat(area.northEast).isEqualTo(Point(4, 1))
Assertions.assertThat(area.southWest).isEqualTo(Point(2, 3))
Assertions.assertThat(area.southEast).isEqualTo(Point(4, 3))
Assertions.assertThat(area.dimension).isEqualTo(Dimension(3, 3))
}
}
Loading

0 comments on commit d926261

Please sign in to comment.