-
Notifications
You must be signed in to change notification settings - Fork 0
/
Main.kt
99 lines (93 loc) · 3.51 KB
/
Main.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
@file:Suppress("FunctionName")
import androidx.compose.foundation.layout.*
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import kotlinx.coroutines.*
/**
* Number of random numbers.
* For each the Collatz sequence will be calculated and displayed.
* - 100-200 nodes is usually fast on modern computers
* - 1000 is demanding, but still OK
* - 10000 you should expect some lags
*/
const val numberOfNodes = 5000
/**
* For previewing (while sliders are moved), we just display a smaller graph
*/
const val numberOfPreviewNodes = 100
/**
* Random numbers will be drawn from the range 2 to [maxNumberValue]
*/
const val maxNumberValue = 10_000_000L
/**
* Draw random numbers and calculates the Collatz graph for them
*/
suspend fun initializeGraph(
graph: MutableState<CollatzGraph>,
previewGraph: MutableState<CollatzGraph>,
progress: MutableState<Double>,
isDone: MutableState<Boolean>
) {
withContext(Dispatchers.Default) {
isDone.value = false
val nodes = List(numberOfNodes) { (2L..maxNumberValue).random() }
val previewNodes = List(numberOfPreviewNodes) { (2L..maxNumberValue).random() }
graph.value.addNodes(nodes) { p -> progress.value = p / 2f }
previewGraph.value.addNodes(previewNodes) { p -> progress.value = 0.5f + p / 2f }
isDone.value = true
}
}
fun main() = application {
val appScope = rememberCoroutineScope()
val progress = remember { mutableStateOf(0.0) }
val isDone = remember { mutableStateOf(false) }
val previewGraph = remember { mutableStateOf(CollatzGraph()) }
val graph = remember { mutableStateOf(CollatzGraph()) }
appScope.launch {
initializeGraph(graph, previewGraph, progress, isDone)
}
Window(
onCloseRequest = ::exitApplication,
state = rememberWindowState(width = 1500.dp, height = 1000.dp),
title = "Collatz Visualization",
icon = painterResource("Logo.png")
) {
MaterialTheme {
// It doesn't really makes sense to have a loading screen for graphs < 1000 nodes, but why not?.
if (!isDone.value) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(
progress = progress.value.toFloat(), modifier = Modifier.size(200.dp)
)
Text("Loading Graph")
}
} else {
var style by remember { mutableStateOf(GraphStyle()) }
val moving = remember { mutableStateOf(false) }
Row(
Modifier.padding(5.dp)
) {
SettingsPanel(style, moving) { newStyle -> style = newStyle }
if (moving.value) {
CollatzCanvas(previewGraph.value, style)
} else {
CollatzCanvas(graph.value, style )
}
}
}
}
}
}