From 5088d36ae83938d8288adf5503705b3f39ea87a0 Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Fri, 29 Oct 2021 10:37:27 -0500 Subject: [PATCH] First version with graphs. --- src/main/java/cs1/graphs/UnweightedGraph.kt | 44 +++++++++++---------- src/test/kotlin/TestUnweightedGraph.kt | 3 ++ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/main/java/cs1/graphs/UnweightedGraph.kt b/src/main/java/cs1/graphs/UnweightedGraph.kt index 81bc9f0..3f279b7 100644 --- a/src/main/java/cs1/graphs/UnweightedGraph.kt +++ b/src/main/java/cs1/graphs/UnweightedGraph.kt @@ -3,16 +3,16 @@ package cs1.graphs import java.util.Objects import java.util.Random -class Node(var value: T) { +class Node(var value: T, val nonce: Int) { override fun equals(other: Any?) = when (other) { !is Node<*> -> false - else -> value == other.value + else -> value == other.value && nonce == other.nonce } - override fun hashCode() = Objects.hash(value) + override fun hashCode() = Objects.hash(value, nonce) } -class GraphNode(val value: T, val nonce: Int, var neighbors: Set> = setOf()) { +class GraphNode @JvmOverloads constructor(val value: T, val nonce: Int, var neighbors: Set> = setOf()) { constructor(node: GraphNode) : this(node.value, node.nonce) override fun equals(other: Any?) = when (other) { @@ -49,9 +49,9 @@ fun Map, Set>>.toGraphNodes(random: Random) = forEach { (node, neighbors) -> node.neighbors = neighbors } + check(keys.first().find() == mapping.values.toSet()) { "Graph is not connected" } keys.forEach { node -> check(node !in node.neighbors) { "Graph contains a self-edge" } - check(node.find() == mapping.values.toSet()) { "Graph is not connected" } for (neighbor in node.neighbors) { check(node in neighbor.neighbors) { "Graph is not undirected" } } @@ -72,7 +72,7 @@ private fun Map, Set>>.copyGraphNodes() = } } -fun Map, Set>>.toNodes() = keys.associateWith { Node(it.value) }.let { mapping -> +fun Map, Set>>.toNodes() = keys.associateWith { Node(it.value, 0) }.let { mapping -> map { (key, values) -> check(mapping[key] != null) { "Missing mapping for node in graph creation" } mapping[key]!! to values.map { value -> @@ -99,19 +99,21 @@ class UnweightedGraph private constructor( override fun hashCode() = Objects.hash(edges) + val node = edges.keys.minByOrNull { it.nonce }!! + @Suppress("TooManyFunctions") companion object { @JvmStatic fun singleNodeGraph(value: T, random: Random = Random()) = - UnweightedGraph(mapOf(Node(value) to setOf()), random) + UnweightedGraph(mapOf(Node(value, 0) to setOf()), random) @JvmStatic fun twoNodeGraph(first: T, second: T, random: Random = Random()): UnweightedGraph { - val mapping = mapOf(first to Node(first), second to Node(second)) + val mapping = mapOf(0 to Node(first, 0), 1 to Node(second, 1)) return UnweightedGraph( mapOf( - mapping[first]!! to setOf(mapping[second]!!), - mapping[second]!! to setOf(mapping[first]!!) + mapping[0]!! to setOf(mapping[1]!!), + mapping[1]!! to setOf(mapping[0]!!) ), random ) @@ -120,26 +122,26 @@ class UnweightedGraph private constructor( @JvmStatic fun circleGraph(list: List, random: Random = Random()): UnweightedGraph { require(list.size >= 2) { "List has fewer than two elements" } - val mapping = list.associateWith { Node(it) } + val mapping = list.mapIndexed { i, it -> i to Node(it, i) }.toMap() val edges = mapping.values.associateWith { mutableSetOf>() } for (i in 0 until (list.size - 1)) { - edges[mapping[list[i]]]!! += mapping[list[i + 1]]!! - edges[mapping[list[i + 1]]]!! += mapping[list[i]]!! + edges[mapping[i]]!! += mapping[i + 1]!! + edges[mapping[i + 1]]!! += mapping[i]!! } - edges[mapping[list[0]]]!! += mapping[list[list.size - 1]]!! - edges[mapping[list[list.size - 1]]]!! += mapping[list[0]]!! + edges[mapping[0]]!! += mapping[list.size - 1]!! + edges[mapping[list.size - 1]]!! += mapping[0]!! return UnweightedGraph(edges, random) } @JvmStatic fun fullyConnectedGraph(list: List, random: Random = Random()): UnweightedGraph { require(list.size >= 2) { "List has fewer than two elements" } - val mapping = list.associateWith { Node(it) } + val mapping = list.mapIndexed { i, it -> i to Node(it, i) }.toMap() val edges = mapping.values.associateWith { mutableSetOf>() } for (i in list.indices) { for (j in (i + 1) until list.size) { - edges[mapping[list[i]]]!! += mapping[list[j]]!! - edges[mapping[list[j]]]!! += mapping[list[i]]!! + edges[mapping[i]]!! += mapping[j]!! + edges[mapping[j]]!! += mapping[i]!! } } return UnweightedGraph(edges, random) @@ -148,7 +150,7 @@ class UnweightedGraph private constructor( @JvmStatic fun randomGraph(list: List, random: Random = Random()): UnweightedGraph { require(list.size >= 2) { "List has fewer than two elements" } - val mapping = list.associateWith { Node(it) } + val mapping = list.mapIndexed { i, it -> i to Node(it, i) }.toMap() val edges = mapping.values.associateWith { mutableSetOf>() } for (i in list.indices) { val previous = ((i + 1) until list.size).toList() @@ -156,8 +158,8 @@ class UnweightedGraph private constructor( continue } for (j in previous.shuffled(random).take(random.nextInt(previous.size) + 1)) { - edges[mapping[list[i]]]!! += mapping[list[j]]!! - edges[mapping[list[j]]]!! += mapping[list[i]]!! + edges[mapping[i]]!! += mapping[j]!! + edges[mapping[j]]!! += mapping[i]!! } } return UnweightedGraph(edges, random) diff --git a/src/test/kotlin/TestUnweightedGraph.kt b/src/test/kotlin/TestUnweightedGraph.kt index 245cd15..022f122 100644 --- a/src/test/kotlin/TestUnweightedGraph.kt +++ b/src/test/kotlin/TestUnweightedGraph.kt @@ -60,6 +60,9 @@ class TestUnweightedGraph : StringSpec({ } graphs.size shouldBe 1024 } + "it should create a random string graph" { + UnweightedGraph.randomStringGraph(1024) + } "it should create equal graphs" { UnweightedGraph.fullyConnectedGraph((32..63).toList()).also { graph -> graph shouldBe UnweightedGraph.fullyConnectedGraph((32..63).toList())