Skip to content

Commit 6b127a2

Browse files
committed
Move the MutableRingList to collections package
It already is implemented in a generic way.
1 parent 1599386 commit 6b127a2

File tree

4 files changed

+136
-127
lines changed

4 files changed

+136
-127
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package de.ronny_h.aoc.extensions.collections
2+
3+
class MutableRingList<T>(initialList: List<T>) {
4+
private val list: MutableList<T> = initialList.toMutableList()
5+
private var offset = 0
6+
7+
companion object {
8+
fun <T> mutableRingListOf(vararg elements: T): MutableRingList<T> = MutableRingList(elements.toList())
9+
fun mutableRingListOf(elements: String): MutableRingList<Char> = MutableRingList(elements.toList())
10+
}
11+
12+
operator fun get(index: Int) = list[(index + offset) % list.size]
13+
14+
operator fun set(index: Int, value: T) {
15+
list[(index + offset) % list.size] = value
16+
}
17+
18+
/**
19+
* Makes [n] elements move from the end to the front, but maintain their order otherwise.
20+
*/
21+
fun shiftRight(n: Int): MutableRingList<T> {
22+
check(n <= list.size) { "the number of items to spin must be smaller than or equal to the list's length" }
23+
offset = (offset + list.size - n) % list.size
24+
return this
25+
}
26+
27+
/**
28+
* Swaps the elements at [indexA] and [indexB].
29+
*/
30+
fun swap(indexA: Int, indexB: Int): MutableRingList<T> {
31+
val tmp = get(indexA)
32+
set(indexA, get(indexB))
33+
set(indexB, tmp)
34+
return this
35+
}
36+
37+
/**
38+
* Swaps the positions of the specified elements [elemA] and [elemB].
39+
* If not unique, only their first occurrences are swapped.
40+
*/
41+
fun swap(elemA: T, elemB: T): MutableRingList<T> {
42+
val indexA = list.indexOf(elemA)
43+
val indexB = list.indexOf(elemB)
44+
require(indexA >= 0) { "$elemA is not in the list" }
45+
require(indexB >= 0) { "$elemB is not in the list" }
46+
list[indexA] = elemB
47+
list[indexB] = elemA
48+
return this
49+
}
50+
51+
/**
52+
* @return A snapshot of the current state of this [MutableRingList]
53+
*/
54+
fun toList(): List<T> = list.subList(offset, list.size) + list.subList(0, offset)
55+
56+
override fun toString(): String = toList().toString()
57+
58+
fun toJoinedString(): String = toList().joinToString("")
59+
}
Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package de.ronny_h.aoc.year2017.day16
22

33
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.collections.MutableRingList
5+
import de.ronny_h.aoc.extensions.collections.MutableRingList.Companion.mutableRingListOf
46
import de.ronny_h.aoc.year2017.day16.DanceMove.*
5-
import de.ronny_h.aoc.year2017.day16.MutableRingList.Companion.mutableRingListOf
67

78
fun main() = PermutationPromenade().run("kgdchlfniambejop", "fjpmholcibdgeakn")
89

@@ -69,61 +70,3 @@ fun List<String>.parseDanceMoves() = single().split(",").map {
6970
else -> error("unknown move: $it")
7071
}
7172
}
72-
73-
class MutableRingList<T>(initialList: List<T>) {
74-
private val list: MutableList<T> = initialList.toMutableList()
75-
private var offset = 0
76-
77-
companion object {
78-
fun <T> mutableRingListOf(vararg elements: T): MutableRingList<T> = MutableRingList(elements.toList())
79-
fun mutableRingListOf(elements: String): MutableRingList<Char> = MutableRingList(elements.toList())
80-
}
81-
82-
operator fun get(index: Int) = list[(index + offset) % list.size]
83-
84-
operator fun set(index: Int, value: T) {
85-
list[(index + offset) % list.size] = value
86-
}
87-
88-
/**
89-
* Makes [n] elements move from the end to the front, but maintain their order otherwise.
90-
*/
91-
fun shiftRight(n: Int): MutableRingList<T> {
92-
check(n <= list.size) { "the number of items to spin must be smaller than or equal to the list's length" }
93-
offset = (offset + list.size - n) % list.size
94-
return this
95-
}
96-
97-
/**
98-
* Swaps the elements at [indexA] and [indexB].
99-
*/
100-
fun swap(indexA: Int, indexB: Int): MutableRingList<T> {
101-
val tmp = get(indexA)
102-
set(indexA, get(indexB))
103-
set(indexB, tmp)
104-
return this
105-
}
106-
107-
/**
108-
* Swaps the positions of the specified elements [elemA] and [elemB].
109-
* If not unique, only their first occurrences are swapped.
110-
*/
111-
fun swap(elemA: T, elemB: T): MutableRingList<T> {
112-
val indexA = list.indexOf(elemA)
113-
val indexB = list.indexOf(elemB)
114-
require(indexA >= 0) { "$elemA is not in the list" }
115-
require(indexB >= 0) { "$elemB is not in the list" }
116-
list[indexA] = elemB
117-
list[indexB] = elemA
118-
return this
119-
}
120-
121-
/**
122-
* @return A snapshot of the current state of this [MutableRingList]
123-
*/
124-
fun toList(): List<T> = list.subList(offset, list.size) + list.subList(0, offset)
125-
126-
override fun toString(): String = toList().toString()
127-
128-
fun toJoinedString(): String = toList().joinToString("")
129-
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package de.ronny_h.aoc.extensions.collections
2+
3+
import de.ronny_h.aoc.extensions.collections.MutableRingList.Companion.mutableRingListOf
4+
import io.kotest.core.spec.style.StringSpec
5+
import io.kotest.matchers.shouldBe
6+
7+
class MutableRingListTest : StringSpec({
8+
9+
"a MutableRingList<Char> can be created from a variable amounts of Chars and toString() generates a nice representation" {
10+
mutableRingListOf('a', 'b', 'c', 'd', 'e').toString() shouldBe "[a, b, c, d, e]"
11+
}
12+
13+
"a MutableRingList<Char> can be created from a String and toJoinedString() recreates that String" {
14+
mutableRingListOf("abcde").toJoinedString() shouldBe "abcde"
15+
}
16+
17+
"get(index) returns the element at index" {
18+
mutableRingListOf("abcde").get(2) shouldBe 'c'
19+
mutableRingListOf("abcde")[2] shouldBe 'c'
20+
}
21+
22+
"set(index, value) sets the value at index" {
23+
val list = mutableRingListOf("abcde")
24+
25+
list.set(2, 'z')
26+
list[2] shouldBe 'z'
27+
28+
list[0] = 'y'
29+
list[0] shouldBe 'y'
30+
}
31+
32+
"shiftRight() moves elements from the end to the front" {
33+
mutableRingListOf("abcde").shiftRight(1).toJoinedString() shouldBe "eabcd"
34+
35+
mutableRingListOf("abcde").shiftRight(2).toJoinedString() shouldBe "deabc"
36+
mutableRingListOf("abcde").shiftRight(1).shiftRight(1).toJoinedString() shouldBe "deabc"
37+
38+
mutableRingListOf("abcde").shiftRight(3).toJoinedString() shouldBe "cdeab"
39+
mutableRingListOf("abcde").shiftRight(1).shiftRight(2).toJoinedString() shouldBe "cdeab"
40+
41+
mutableRingListOf("abcde").shiftRight(5).toJoinedString() shouldBe "abcde"
42+
}
43+
44+
"get after shiftRight returns the shifted elements" {
45+
val list = mutableRingListOf("abcde").shiftRight(1)
46+
list[0] shouldBe 'e'
47+
list[4] shouldBe 'd'
48+
}
49+
50+
"set after shiftRight sets the element at the shifted position" {
51+
val list = mutableRingListOf("abcde").shiftRight(1)
52+
list[0] = 'x'
53+
list[0] shouldBe 'x'
54+
list[4] shouldBe 'd'
55+
}
56+
57+
"toList returns the modified state" {
58+
val list = mutableRingListOf("abcde")
59+
.shiftRight(2)
60+
.swap(0, 1)
61+
list.toList() shouldBe listOf('e', 'd', 'a', 'b', 'c')
62+
}
63+
64+
"swap(indexA, indexB) exchanges the elements at the given indexes" {
65+
mutableRingListOf("abcde").swap(3, 4).toJoinedString() shouldBe "abced"
66+
mutableRingListOf("abcde").swap(0, 4).toJoinedString() shouldBe "ebcda"
67+
mutableRingListOf("abcde").swap(3, 3).toJoinedString() shouldBe "abcde"
68+
}
69+
70+
"swap(elemA, elemB) exchanges the elements by their name" {
71+
mutableRingListOf("abcde").swap('d', 'e').toJoinedString() shouldBe "abced"
72+
mutableRingListOf("abcde").swap('a', 'e').toJoinedString() shouldBe "ebcda"
73+
mutableRingListOf("abcde").swap('c', 'c').toJoinedString() shouldBe "abcde"
74+
}
75+
})

src/test/kotlin/de/ronny_h/aoc/year2017/day16/PermutationPromenadeTest.kt

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package de.ronny_h.aoc.year2017.day16
22

33
import de.ronny_h.aoc.year2017.day16.DanceMove.*
4-
import de.ronny_h.aoc.year2017.day16.MutableRingList.Companion.mutableRingListOf
54
import io.kotest.core.spec.style.StringSpec
65
import io.kotest.matchers.shouldBe
76

@@ -13,73 +12,6 @@ class PermutationPromenadeTest : StringSpec({
1312
input.parseDanceMoves() shouldBe listOf(Spin(1), Exchange(3, 4), Partner('e', 'b'))
1413
}
1514

16-
"a MutableRingList<Char> can be created from a variable amounts of Chars and toString() generates a nice representation" {
17-
mutableRingListOf('a', 'b', 'c', 'd', 'e').toString() shouldBe "[a, b, c, d, e]"
18-
}
19-
20-
"a MutableRingList<Char> can be created from a String and toJoinedString() recreates that String" {
21-
mutableRingListOf("abcde").toJoinedString() shouldBe "abcde"
22-
}
23-
24-
"MutableRingList: get" {
25-
mutableRingListOf("abcde").get(2) shouldBe 'c'
26-
mutableRingListOf("abcde")[2] shouldBe 'c'
27-
}
28-
29-
"MutableRingList: set" {
30-
val list = mutableRingListOf("abcde")
31-
32-
list.set(2, 'z')
33-
list[2] shouldBe 'z'
34-
35-
list[0] = 'y'
36-
list[0] shouldBe 'y'
37-
}
38-
39-
"MutableRingList: programs can be spun" {
40-
mutableRingListOf("abcde").shiftRight(1).toJoinedString() shouldBe "eabcd"
41-
42-
mutableRingListOf("abcde").shiftRight(2).toJoinedString() shouldBe "deabc"
43-
mutableRingListOf("abcde").shiftRight(1).shiftRight(1).toJoinedString() shouldBe "deabc"
44-
45-
mutableRingListOf("abcde").shiftRight(3).toJoinedString() shouldBe "cdeab"
46-
mutableRingListOf("abcde").shiftRight(1).shiftRight(2).toJoinedString() shouldBe "cdeab"
47-
48-
mutableRingListOf("abcde").shiftRight(5).toJoinedString() shouldBe "abcde"
49-
}
50-
51-
"MutableRingList: get after spin" {
52-
val list = mutableRingListOf("abcde").shiftRight(1)
53-
list[0] shouldBe 'e'
54-
list[4] shouldBe 'd'
55-
}
56-
57-
"MutableRingList: set after spin" {
58-
val list = mutableRingListOf("abcde").shiftRight(1)
59-
list[0] = 'x'
60-
list[0] shouldBe 'x'
61-
list[4] shouldBe 'd'
62-
}
63-
64-
"MutableRingList: toList returns the modified state" {
65-
val list = mutableRingListOf("abcde")
66-
.shiftRight(2)
67-
.swap(0, 1)
68-
list.toList() shouldBe listOf('e', 'd', 'a', 'b', 'c')
69-
}
70-
71-
"programs can be exchanged at positions" {
72-
mutableRingListOf("abcde").swap(3, 4).toJoinedString() shouldBe "abced"
73-
mutableRingListOf("abcde").swap(0, 4).toJoinedString() shouldBe "ebcda"
74-
mutableRingListOf("abcde").swap(3, 3).toJoinedString() shouldBe "abcde"
75-
}
76-
77-
"programs can be exchanged by their name" {
78-
mutableRingListOf("abcde").swap('d', 'e').toJoinedString() shouldBe "abced"
79-
mutableRingListOf("abcde").swap('a', 'e').toJoinedString() shouldBe "ebcda"
80-
mutableRingListOf("abcde").swap('c', 'c').toJoinedString() shouldBe "abcde"
81-
}
82-
8315
"part 1: The order of the programs after their dance" {
8416
PermutationPromenade().doTheDance("abcde", input) shouldBe "baedc"
8517
PermutationPromenade().part1(input) shouldBe "paedcbfghijklmno"

0 commit comments

Comments
 (0)