aboutsummaryrefslogtreecommitdiff
path: root/src/scalevalapokalypsi/utils/utils.scala
blob: 81795855ca7859e2ef49759071963c2786c78d22 (plain)
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
package scalevalapokalypsi.utils

import java.io.InputStream
import java.nio.charset.StandardCharsets
import scala.util.Try
import scalevalapokalypsi.constants.*
import scala.io.StdIn.readLine
import scala.math.{min,abs}

/** Converts this string to an array of bytes (probably for transmission).
  *
  * @param str the string to convert
  * @return an array of bytes representing the string in UTF8.
  */
def stringToByteArray(str: String): Array[Byte] =
	str.getBytes(StandardCharsets.UTF_8)

/** Converts the given byte array to a string if possible*.
  * (* Doesn't convert strings with control sequences in them)
  *
  * @param bytes the byte array to convert
  * @return      the matching string, if possible*.
  */
def byteArrayToString(bytes: Array[Byte]): Option[String] =
	Try(String(bytes, StandardCharsets.UTF_8))
		.toOption

/** Incredibly LÖRS string metric algorithm.
  * LÖRSiness explained by there being 6 hours left to the DL
  */
def hammingDistance(s1: String, s2: String): Int =
	s1.zip(s2).map(p => p(0) != p(1)).filter((b: Boolean) => b).length

/** Reads n characters from the given InputStream blockingly.
  *
  * @param input the InputStream to read from
  * @param n     the number of bytes to read
  * @return      The read result, or None in case of failure
  */
def getNCharsFromSocket(input: InputStream, n: Int): Option[String] =
	val buffer: Array[Byte] = Array.ofDim(n)
	var i = 0
	var failed = false
	while i < n && !failed do
		val res = input.read(buffer, i, n - i)
		if res < 0 then failed = true
		i += res
	if failed then None else byteArrayToString(buffer)

def isPrintable(s: String): Boolean =
	FORBIDDEN_CHARACTERS.forall((c: Char) => !(s contains c))


/** Gets input from STDIN until the line entered is appoved
  * by a validator function.
  *
  * @param message   A query to represent the user with when requesting input
  * @param validator A validator function. Should return Right[A] when the
  *                  input is valid and Left[String] when the input is invalid,
  *                  where the string will be printed to the user to notify
  *                  their input was invalid.
  * @return          The first encountered valid string, see `validator`.
  */
def getValidInput[A](
	message: String,
	validator: String => Either[String, A]
): A =
	LazyList.continually(readLine(s"$message\n> "))
		.flatMap(input =>
			validator(input) match
				case Left(s) =>
					println(s)
					None
				case Right(a) =>
					Some(a)
		).head