diff --git a/.idea/inspectionProfiles/ktlint.xml b/.idea/inspectionProfiles/ktlint.xml
index 7d04a74..b94d800 100644
--- a/.idea/inspectionProfiles/ktlint.xml
+++ b/.idea/inspectionProfiles/ktlint.xml
@@ -3,5 +3,8 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/src/main/java/cs1/graphs/UndirectedGraph.kt b/src/main/java/cs1/graphs/UndirectedGraph.kt
deleted file mode 100644
index a72ff7f..0000000
--- a/src/main/java/cs1/graphs/UndirectedGraph.kt
+++ /dev/null
@@ -1,203 +0,0 @@
-package cs1.graphs
-
-import java.util.Objects
-
-class Node(val value: T, private val index: Int, val neighbors: MutableSet> = mutableSetOf()) {
- override fun toString() = "Node $index ($value)"
- override fun equals(other: Any?): Boolean {
- if (other !is Node<*>) {
- return false
- }
- return value == other.value && toMap() == other.toMap()
- }
-
- override fun hashCode() = Objects.hash(value, toMap())
-}
-
-class InputNode(var value: T)
-
-private fun Node.find(visited: MutableSet>) {
- visited += this
- for (neighbor in neighbors) {
- if (neighbor !in visited) {
- neighbor.find(visited)
- }
- }
-}
-
-private fun Node.find(): Set> {
- val nodes = mutableSetOf>()
- println(nodes.size)
- find(nodes)
- return nodes
-}
-
-fun Node.toMap(): Map, Set>> {
- find()
- return mapOf, Set>>()
-}
-
-fun Map, Set>>.toGraph(): Node {
- check(isNotEmpty()) { "Graph is empty" }
- val mapping = keys.mapIndexed { index, key -> key to Node(key.value, index) }.toMap()
- forEach { (key, values) ->
- check(mapping[key] != null) { "Missing mapping for key in graph creation" }
- mapping[key]!!.neighbors.addAll(
- values.map {
- mapping[it] ?: error("Missing mapping for value in graph creation")
- }
- )
- }
-
- mapping.values.forEach {
- check(it !in it.neighbors) { "Graph contains a self-edge" }
- check(it.find() == mapping.values.toSet()) { "Graph is not connected" }
- for (node in it.neighbors) {
- check(it in node.neighbors) { "Graph is not undirected" }
- }
- }
- return mapping.values.first()
-}
-
-fun singleNodeGraph(value: T) = mapOf(InputNode(value) to setOf>()).toGraph()
-
-fun twoNodeGraph(first: T, second: T): Node {
- val mapping = mapOf(first to InputNode(first), second to InputNode(second))
- return mapOf(
- mapping[first]!! to setOf(mapping[second]!!),
- mapping[second]!! to setOf(mapping[first]!!)
- ).toGraph()
-}
-
-fun circleGraph(list: List): Node {
- require(list.size >= 2) { "List has fewer than two elements" }
- val mapping = list.associateWith {
- InputNode(it)
- }
- 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[list[0]]]!! += mapping[list[list.size - 1]]!!
- edges[mapping[list[list.size - 1]]]!! += mapping[list[0]]!!
- return edges.toGraph()
-}
-
-fun fullyConnectedGraph(list: List): Node {
- require(list.size >= 2) { "List has fewer than two elements" }
- val mapping = list.associateWith {
- InputNode(it)
- }
- val edges = mapping.values.associateWith { mutableSetOf>() }
- for (i in list.indices) {
- for (j in list.indices - i) {
- edges[mapping[list[i]]]!! += mapping[list[j]]!!
- edges[mapping[list[j]]]!! += mapping[list[i]]!!
- }
- }
- return edges.toGraph()
-}
-
-/*
-class UndirectedGraph(inputEdges: Map, Set>>) {
- private val edges: Map>
- val node: Node
-
- init {
- check(inputEdges.isNotEmpty()) { "Graph is empty" }
- val edgeMapping = inputEdges.keys.mapIndexed { index, key ->
- key to Node(key, index)
- }.toMap()
- edges = inputEdges.map { (key, values) ->
- check(edgeMapping[key] != null) { "Missing mapping for key in graph creation" }
- edgeMapping[key]!! to values.map { value ->
- edgeMapping[value] ?: error("Missing mapping for value during graph creation")
- }.toSet()
- }.toMap()
-
- for ((first, neighbors) in edges) {
- check(first !in neighbors) { "Graph contains a self-edge" }
- for (second in neighbors) {
- check(second.connectedTo(first)) { "Graph is not undirected" }
- }
- check(first.find() == edges.keys) { "Graph is not connected" }
- }
-
- node = edges.keys.first()
- }
-
- inner class Node(var value: T, private val index: Int) {
- constructor(graphNode: InputNode, index: Int) : this(graphNode.value, index)
-
- val neighbors: Set
- get() = edges[this]!!
-
- internal fun connectedTo(second: Node) = edges[this]?.contains(second) ?: false
- internal fun find(): Set {
- val nodes = mutableSetOf()
- find(nodes)
- return nodes
- }
-
- private fun find(visited: MutableSet) {
- visited += this
- for (neighbor in neighbors) {
- if (neighbor !in visited) {
- neighbor.find(visited)
- }
- }
- }
-
- override fun toString() = "Node $index ($value)"
- }
-
- companion object {
- @JvmStatic
- fun singleNodeGraph(value: T) = UndirectedGraph(mapOf(InputNode(value) to setOf()))
-
- @JvmStatic
- fun twoNodeGraph(first: T, second: T): UndirectedGraph {
- val mapping = mapOf(first to InputNode(first), second to InputNode(second))
- return UndirectedGraph(
- mapOf(
- mapping[first]!! to setOf(mapping[second]!!),
- mapping[second]!! to setOf(mapping[first]!!)
- )
- )
- }
-
- @JvmStatic
- fun circleGraph(list: List): UndirectedGraph {
- require(list.size >= 2) { "List has fewer than two elements" }
- val mapping = list.associateWith {
- InputNode(it)
- }
- 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[list[0]]]!! += mapping[list[list.size - 1]]!!
- edges[mapping[list[list.size - 1]]]!! += mapping[list[0]]!!
- return UndirectedGraph(edges)
- }
-
- @JvmStatic
- fun fullyConnectedGraph(list: List): UndirectedGraph {
- require(list.size >= 2) { "List has fewer than two elements" }
- val mapping = list.associateWith {
- InputNode(it)
- }
- val edges = mapping.values.associateWith { mutableSetOf>() }
- for (i in list.indices) {
- for (j in list.indices - i) {
- edges[mapping[list[i]]]!! += mapping[list[j]]!!
- edges[mapping[list[j]]]!! += mapping[list[i]]!!
- }
- }
- return UndirectedGraph(edges)
- }
- }
-}
-*/
diff --git a/src/main/java/cs1/graphs/UnweightedGraph.kt b/src/main/java/cs1/graphs/UnweightedGraph.kt
new file mode 100644
index 0000000..81bc9f0
--- /dev/null
+++ b/src/main/java/cs1/graphs/UnweightedGraph.kt
@@ -0,0 +1,208 @@
+package cs1.graphs
+
+import java.util.Objects
+import java.util.Random
+
+class Node(var value: T) {
+ override fun equals(other: Any?) = when (other) {
+ !is Node<*> -> false
+ else -> value == other.value
+ }
+
+ override fun hashCode() = Objects.hash(value)
+}
+
+class GraphNode(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) {
+ !is GraphNode<*> -> false
+ else -> value == other.value && nonce == other.nonce
+ }
+
+ override fun hashCode() = Objects.hash(value, nonce)
+}
+
+private fun GraphNode.find(): Set> = mutableSetOf>().also { nodes ->
+ find(nodes)
+}
+
+private fun GraphNode.find(visited: MutableSet>) {
+ visited += this
+ for (neighbor in neighbors) {
+ if (neighbor !in visited) {
+ neighbor.find(visited)
+ }
+ }
+}
+
+@Suppress("NestedBlockDepth")
+fun Map, Set>>.toGraphNodes(random: Random) =
+ keys.associateWith { GraphNode(it.value, random.nextInt()) }.let { mapping ->
+ map { (key, values) ->
+ check(mapping[key] != null) { "Missing mapping for node in graph creation" }
+ mapping[key]!! to values.map { value ->
+ check(mapping[value] != null) { "Missing mapping for node in graph creation" }
+ mapping[value]!!
+ }.toSet()
+ }.toMap().apply {
+ forEach { (node, neighbors) ->
+ node.neighbors = neighbors
+ }
+ 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" }
+ }
+ }
+ }
+ }
+
+private fun Map, Set>>.copyGraphNodes() =
+ keys.associateWith { GraphNode(it) }.let { mapping ->
+ map { (key, values) ->
+ check(mapping[key] != null) { "Missing mapping for node in graph copy" }
+ mapping[key]!! to values.map { value ->
+ check(mapping[value] != null) { "Missing mapping for node in graph creation" }
+ mapping[value]!!
+ }.toSet()
+ }.toMap().onEach { (node, neighbors) ->
+ node.neighbors = neighbors
+ }
+ }
+
+fun Map, Set>>.toNodes() = keys.associateWith { Node(it.value) }.let { mapping ->
+ map { (key, values) ->
+ check(mapping[key] != null) { "Missing mapping for node in graph creation" }
+ mapping[key]!! to values.map { value ->
+ check(mapping[value] != null) { "Missing mapping for node in graph creation" }
+ mapping[value]!!
+ }.toSet()
+ }.toMap()
+}
+
+@Suppress("unused")
+class UnweightedGraph private constructor(
+ val edges: Map, Set>>,
+ @Suppress("unused") private val unused: Boolean
+) {
+ constructor(edges: Map, Set>>, random: Random = Random()) : this(edges.toGraphNodes(random), true)
+ constructor(graph: UnweightedGraph) : this(graph.edges.copyGraphNodes(), true)
+
+ @Suppress("UNCHECKED_CAST")
+ override fun equals(other: Any?) = when (other) {
+ !is UnweightedGraph<*> -> false
+ else -> (edges as Map, Set>>).toNodes() ==
+ (other.edges as Map, Set>>).toNodes()
+ }
+
+ override fun hashCode() = Objects.hash(edges)
+
+ @Suppress("TooManyFunctions")
+ companion object {
+ @JvmStatic
+ fun singleNodeGraph(value: T, random: Random = Random()) =
+ UnweightedGraph(mapOf(Node(value) 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))
+ return UnweightedGraph(
+ mapOf(
+ mapping[first]!! to setOf(mapping[second]!!),
+ mapping[second]!! to setOf(mapping[first]!!)
+ ),
+ random
+ )
+ }
+
+ @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 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[list[0]]]!! += mapping[list[list.size - 1]]!!
+ edges[mapping[list[list.size - 1]]]!! += mapping[list[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 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]]!!
+ }
+ }
+ return UnweightedGraph(edges, random)
+ }
+
+ @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 edges = mapping.values.associateWith { mutableSetOf>() }
+ for (i in list.indices) {
+ val previous = ((i + 1) until list.size).toList()
+ if (previous.isEmpty()) {
+ 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]]!!
+ }
+ }
+ return UnweightedGraph(edges, random)
+ }
+
+ @JvmStatic
+ fun randomIntegerGraph(random: Random, size: Int, maxInteger: Int): UnweightedGraph {
+ require(size > 0) { "size must be positive: $size" }
+ return randomGraph(List(size) { random.nextInt(maxInteger) - (maxInteger / 2) }, random)
+ }
+
+ @JvmStatic
+ fun randomIntegerGraph(size: Int, maxInteger: Int): UnweightedGraph {
+ return randomIntegerGraph(Random(), size, maxInteger)
+ }
+
+ @JvmStatic
+ fun randomIntegerGraph(size: Int): UnweightedGraph {
+ return randomIntegerGraph(Random(), size, 128)
+ }
+
+ private fun Random.nextInt(min: Int, max: Int) = let {
+ require(min < max)
+ nextInt(max - min) + min
+ }
+
+ @Suppress("SpellCheckingInspection")
+ private const val CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "
+ private fun randomAlphanumericString(random: Random, maxLength: Int) =
+ String(CharArray(random.nextInt(1, maxLength)) { CHARACTERS[random.nextInt(CHARACTERS.length)] })
+
+ @JvmStatic
+ fun randomStringGraph(random: Random, size: Int, maxLength: Int): UnweightedGraph {
+ require(size > 0) { "size must be positive: $size" }
+ return randomGraph(List(size) { randomAlphanumericString(random, maxLength) }, random)
+ }
+
+ @JvmStatic
+ fun randomStringGraph(size: Int, maxLength: Int): UnweightedGraph {
+ return randomStringGraph(Random(), size, maxLength)
+ }
+
+ @JvmStatic
+ fun randomStringGraph(size: Int): UnweightedGraph {
+ return randomStringGraph(Random(), size, 32)
+ }
+ }
+}
diff --git a/src/main/java/cs1/trees/BinaryTree.kt b/src/main/java/cs1/trees/BinaryTree.kt
new file mode 100644
index 0000000..7cb8ee1
--- /dev/null
+++ b/src/main/java/cs1/trees/BinaryTree.kt
@@ -0,0 +1,186 @@
+package cs1.trees
+
+import java.util.Objects
+import java.util.Random
+
+@Suppress("unused")
+class BinaryTree(var value: T) {
+ var left: BinaryTree? = null
+ var right: BinaryTree? = null
+ private var size: Int = 1
+
+ constructor(value: T, setLeft: T?, setRight: T?) : this(value) {
+ if (setLeft != null) {
+ left = BinaryTree(setLeft)
+ size++
+ }
+ if (setRight != null) {
+ right = BinaryTree(setRight)
+ size++
+ }
+ }
+
+ constructor(other: BinaryTree) : this(other.value) {
+ copy(other, this)
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return when {
+ other?.javaClass != javaClass -> false
+ else -> {
+ other as BinaryTree<*>
+ return other.value == value && Objects.equals(other.left, left) && Objects.equals(other.right, right)
+ }
+ }
+ }
+
+ override fun hashCode() = Objects.hash(value, left, right)
+
+ override fun toString() = "BinaryTree($size nodes)"
+
+ companion object {
+ private fun copy(from: BinaryTree, to: BinaryTree) {
+ require(from.value == to.value)
+ if (from.left != null) {
+ to.left = BinaryTree(from.left!!.value)
+ copy(from.left!!, to.left!!)
+ }
+ if (from.right != null) {
+ to.right = BinaryTree(from.right!!.value)
+ copy(from.right!!, to.right!!)
+ }
+ }
+
+ private fun add(tree: BinaryTree, value: T, random: Random) {
+ if (random.nextBoolean()) {
+ if (tree.right == null) {
+ tree.right = BinaryTree(value)
+ } else {
+ add(tree.right!!, value, random)
+ }
+ } else {
+ if (tree.left == null) {
+ tree.left = BinaryTree(value)
+ } else {
+ add(tree.left!!, value, random)
+ }
+ }
+ tree.size++
+ }
+
+ private fun depth(tree: BinaryTree?): Int {
+ return when (tree) {
+ null -> 0
+ else -> 1 + depth(tree.right).coerceAtLeast(depth(tree.left))
+ }
+ }
+
+ private fun balancedAdd(tree: BinaryTree, value: T, random: Random) {
+ if (tree.right == null && tree.left == null) {
+ if (random.nextBoolean()) {
+ tree.right = BinaryTree(value)
+ } else {
+ tree.left = BinaryTree(value)
+ }
+ } else if (tree.right == null) {
+ tree.right = BinaryTree(value)
+ } else if (tree.left == null) {
+ tree.left = BinaryTree(value)
+ } else {
+ val rightDepth = depth(tree.right)
+ val leftDepth = depth(tree.left)
+ if (leftDepth > rightDepth) {
+ balancedAdd(tree.right!!, value, random)
+ } else if (rightDepth > leftDepth) {
+ balancedAdd(tree.left!!, value, random)
+ } else {
+ if (random.nextBoolean()) {
+ balancedAdd(tree.right!!, value, random)
+ } else {
+ balancedAdd(tree.left!!, value, random)
+ }
+ }
+ }
+ tree.size++
+ }
+
+ @JvmStatic
+ fun randomIntegerTree(random: Random, size: Int, maxInteger: Int): BinaryTree {
+ require(size > 0) { "size must be positive: $size" }
+ return BinaryTree(random.nextInt(maxInteger) - (maxInteger / 2)).also { tree ->
+ repeat(size - 1) {
+ add(tree, random.nextInt(maxInteger) - (maxInteger / 2), random)
+ }
+ check(tree.size == size)
+ }
+ }
+
+ @JvmStatic
+ fun randomIntegerTree(size: Int, maxInteger: Int): BinaryTree {
+ return randomIntegerTree(Random(), size, maxInteger)
+ }
+
+ @JvmStatic
+ fun randomIntegerTree(size: Int): BinaryTree {
+ return randomIntegerTree(Random(), size, 128)
+ }
+
+ @JvmStatic
+ fun randomBalancedIntegerTree(random: Random, size: Int, maxInteger: Int): BinaryTree {
+ require(size > 0) { "size must be positive: $size" }
+ return BinaryTree(random.nextInt(maxInteger / 2) - maxInteger).also { tree ->
+ repeat(size - 1) {
+ balancedAdd(tree, random.nextInt(maxInteger / 2) - maxInteger, random)
+ }
+ check(tree.size == size)
+ }
+ }
+
+ @JvmStatic
+ fun randomBalancedIntegerTree(size: Int, maxInteger: Int): BinaryTree {
+ return randomBalancedIntegerTree(Random().apply { setSeed(124) }, size, maxInteger)
+ }
+
+ private fun Random.nextInt(min: Int, max: Int) = let {
+ require(min < max)
+ nextInt(max - min) + min
+ }
+
+ @Suppress("SpellCheckingInspection")
+ private const val CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz "
+ private fun randomAlphanumericString(random: Random, maxLength: Int) =
+ String(CharArray(random.nextInt(1, maxLength)) { CHARACTERS[random.nextInt(CHARACTERS.length)] })
+
+ @JvmStatic
+ fun randomStringTree(random: Random, size: Int, maxLength: Int): BinaryTree {
+ require(size > 0) { "size must be positive: $size" }
+ return BinaryTree(randomAlphanumericString(random, maxLength)).also { tree ->
+ repeat(size - 1) {
+ add(tree, randomAlphanumericString(random, maxLength), random)
+ }
+ check(tree.size == size)
+ }
+ }
+
+ @JvmStatic
+ fun randomStringTree(size: Int, maxLength: Int): BinaryTree {
+ return randomStringTree(Random().apply { setSeed(124) }, size, maxLength)
+ }
+
+ @JvmStatic
+ fun randomBalancedStringTree(random: Random, size: Int, maxLength: Int): BinaryTree {
+ require(size > 0) { "size must be positive: $size" }
+ return BinaryTree(randomAlphanumericString(random, maxLength)).also { tree ->
+ repeat(size - 1) {
+ balancedAdd(tree, randomAlphanumericString(random, maxLength), random)
+ }
+ check(tree.size == size)
+ }
+ }
+
+ @JvmStatic
+ fun randomBalancedStringTree(size: Int, maxInteger: Int): BinaryTree {
+ return randomBalancedStringTree(Random().apply { setSeed(124) }, size, maxInteger)
+ }
+ }
+}
diff --git a/src/test/java/com/example/Example.java b/src/test/java/com/example/Example.java
index 39ebb15..f971325 100644
--- a/src/test/java/com/example/Example.java
+++ b/src/test/java/com/example/Example.java
@@ -1,33 +1,38 @@
package com.example;
-import cs1.graphs.Node;
+import cs1.graphs.GraphNode;
+import cs1.graphs.UnweightedGraph;
import java.util.HashSet;
import java.util.Set;
public class Example {
- public static int size(Node graph) {
- Set> visited = new HashSet<>();
- traverse(graph, visited);
- return visited.size();
+ public static int size(UnweightedGraph graph) {
+ return graph.getEdges().size();
}
- private static void traverse(Node node, Set> visited) {
+ public static int size(GraphNode node) {
+ Set> nodes = new HashSet<>();
+ traverse(node, nodes);
+ return nodes.size();
+ }
+
+ public static int sum(UnweightedGraph graph) {
+ return graph.getEdges().keySet().stream().mapToInt(GraphNode::getValue).sum();
+ }
+
+ public static int sum(GraphNode node) {
+ Set> nodes = new HashSet<>();
+ traverse(node, nodes);
+ return nodes.stream().mapToInt(GraphNode::getValue).sum();
+ }
+
+ private static void traverse(GraphNode node, Set> visited) {
visited.add(node);
- for (Node neighbor : node.getNeighbors()) {
+ for (GraphNode neighbor : node.getNeighbors()) {
if (!(visited.contains(neighbor))) {
traverse(neighbor, visited);
}
}
}
-
- public static int sum(Node graph) {
- Set> visited = new HashSet<>();
- traverse(graph, visited);
- int sum = 0;
- for (Node node : visited) {
- sum += node.getValue();
- }
- return sum;
- }
}
diff --git a/src/test/kotlin/TestUndirectedGraph.kt b/src/test/kotlin/TestUndirectedGraph.kt
deleted file mode 100644
index 71008d1..0000000
--- a/src/test/kotlin/TestUndirectedGraph.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-import com.example.Example
-import cs1.graphs.circleGraph
-import cs1.graphs.fullyConnectedGraph
-import cs1.graphs.singleNodeGraph
-import cs1.graphs.toMap
-import cs1.graphs.twoNodeGraph
-import io.kotest.core.spec.style.StringSpec
-import io.kotest.matchers.shouldBe
-
-class TestUndirectedGraph : StringSpec({
- "f: it should create a single-node graph" {
- singleNodeGraph(8).also {
- println(it.toMap())
- //Example.size(it) shouldBe 1
- //Example.sum(it) shouldBe 8
- }
- }
- "it should create a two-node graph" {
- twoNodeGraph(8, 16).also {
- Example.size(it) shouldBe 2
- Example.sum(it) shouldBe 24
- }
- }
- "it should create a circular graph" {
- circleGraph((0..31).toList()).also {
- Example.size(it) shouldBe 32
- Example.sum(it) shouldBe (0..31).sum()
- }
- }
- "it should create a fully-connected graph" {
- fullyConnectedGraph((32..63).toList()).also {
- Example.size(it) shouldBe 32
- Example.sum(it) shouldBe (32..63).sum()
- }
- }
-})
diff --git a/src/test/kotlin/TestUnweightedGraph.kt b/src/test/kotlin/TestUnweightedGraph.kt
new file mode 100644
index 0000000..245cd15
--- /dev/null
+++ b/src/test/kotlin/TestUnweightedGraph.kt
@@ -0,0 +1,81 @@
+import com.example.Example
+import cs1.graphs.UnweightedGraph
+import io.kotest.core.spec.style.StringSpec
+import io.kotest.matchers.shouldBe
+import io.kotest.matchers.shouldNotBe
+
+class TestUnweightedGraph : StringSpec({
+ "it should create a single-node graph" {
+ UnweightedGraph.singleNodeGraph(8).also { graph ->
+ Example.size(graph) shouldBe 1
+ Example.sum(graph) shouldBe 8
+ graph.edges.keys.forEach { node ->
+ Example.size(node) shouldBe 1
+ Example.sum(node) shouldBe 8
+ }
+ }
+ }
+ "it should create a two-node graph" {
+ UnweightedGraph.twoNodeGraph(8, 16).also { graph ->
+ Example.size(graph) shouldBe 2
+ Example.sum(graph) shouldBe 24
+ graph.edges.keys.forEach { node ->
+ Example.size(node) shouldBe 2
+ Example.sum(node) shouldBe 24
+ }
+ }
+ }
+ "it should create a circular graph" {
+ UnweightedGraph.circleGraph((0..31).toList()).also { graph ->
+ Example.size(graph) shouldBe 32
+ Example.sum(graph) shouldBe (0..31).sum()
+ graph.edges.keys.forEach { node ->
+ Example.size(node) shouldBe 32
+ Example.sum(node) shouldBe (0..31).sum()
+ }
+ }
+ }
+ "it should create a fully-connected graph" {
+ UnweightedGraph.fullyConnectedGraph((32..63).toList()).also { graph ->
+ Example.size(graph) shouldBe 32
+ Example.sum(graph) shouldBe (32..63).sum()
+ graph.edges.keys.forEach { node ->
+ Example.size(node) shouldBe 32
+ Example.sum(node) shouldBe (32..63).sum()
+ }
+ }
+ }
+ "it should create a random graph" {
+ UnweightedGraph.randomGraph((32..63).toList()).also { graph ->
+ Example.size(graph) shouldBe 32
+ Example.sum(graph) shouldBe (32..63).sum()
+ graph.edges.keys.forEach { node ->
+ Example.size(node) shouldBe 32
+ Example.sum(node) shouldBe (32..63).sum()
+ }
+ }
+ val graphs = mutableSetOf>()
+ repeat(1024) {
+ graphs += UnweightedGraph.randomGraph((32..63).toList())
+ }
+ graphs.size shouldBe 1024
+ }
+ "it should create equal graphs" {
+ UnweightedGraph.fullyConnectedGraph((32..63).toList()).also { graph ->
+ graph shouldBe UnweightedGraph.fullyConnectedGraph((32..63).toList())
+ graph shouldNotBe UnweightedGraph.fullyConnectedGraph((31..62).toList())
+ graph shouldNotBe UnweightedGraph.circleGraph((32..63).toList())
+ }
+ }
+ "it should copy graphs" {
+ UnweightedGraph.fullyConnectedGraph((32..63).toList()).also { graph ->
+ val copy = UnweightedGraph(graph)
+ graph shouldBe UnweightedGraph(copy)
+ (graph === copy) shouldBe false
+ graph.edges.keys.forEach { node ->
+ copy.edges[node] shouldNotBe null
+ copy.edges.keys.find { it === node } shouldBe null
+ }
+ }
+ }
+})