diff --git a/plugin/src/main/kotlin/sc/plugin2023/Board.kt b/plugin/src/main/kotlin/sc/plugin2023/Board.kt index 2e3f81b8e..61d0fc1c7 100644 --- a/plugin/src/main/kotlin/sc/plugin2023/Board.kt +++ b/plugin/src/main/kotlin/sc/plugin2023/Board.kt @@ -3,6 +3,8 @@ package sc.plugin2023 import com.thoughtworks.xstream.annotations.XStreamAlias import com.thoughtworks.xstream.annotations.XStreamImplicit import sc.api.plugins.* +import kotlin.math.min +import kotlin.math.roundToInt import sc.framework.deepCopy import kotlin.random.Random import sc.plugin2023.util.PenguinConstants as Constants @@ -11,7 +13,7 @@ import sc.plugin2023.util.PenguinConstants as Constants @XStreamAlias(value = "board") class Board( @XStreamImplicit(itemFieldName = "row") - override val gameField: MutableTwoDBoard = generateFields() + override val gameField: MutableTwoDBoard = generateFields(), ): RectangularBoard(), IBoard { constructor(board: Board): this(board.gameField.deepCopy()) @@ -69,9 +71,10 @@ class Board( companion object { /** Generiert ein neues Spielfeld mit zufällig auf dem Spielbrett verteilten Fischen. */ private fun generateFields(seed: Int = Random.nextInt()): MutableTwoDBoard { - var remainingFish = Constants.BOARD_SIZE * Constants.BOARD_SIZE val random = Random(seed) - println("Board Seed: $seed") + println("Board seed: $seed") + + var remainingFish = Constants.BOARD_SIZE * Constants.BOARD_SIZE var maxholes = 5 // Pro Hälfte 32 Felder, mind. 27 Schollen // Maximal (64-20)/2 = 22 2-Fisch-Schollen, @@ -95,5 +98,78 @@ class Board( } } + private fun generateFieldsRandom(seed: Int = Random.nextInt()): MutableTwoDBoard { + val random = Random(seed) + println("Board seed: $seed") + + val length = Constants.BOARD_SIZE + val width = Constants.BOARD_SIZE + val weightedInts = + listOf(Field(0) to 0.1f, Field(1) to 0.2f, Field(2) to 0.4f, Field(3) to 0.2f, Field(4) to 0.1f) + val totalSum = length * width + val halfWidth = width / 2 + val halfEnforcedOnes = Constants.BOARD_SIZE / 2 + val fields: TwoDBoard = Array(length) { Array(width) { Field(0) } } + var countOne = 0 + + for(i in 0 until length) { + for(j in 0 until halfWidth) { + if(i * halfWidth + j < halfEnforcedOnes) { + fields[i][j] = Field(1) + countOne += 1 + continue + } + + val currentSum = fields.sumOf { it -> it.sumOf { it.fish } } + val notFilled = totalSum - (i * halfWidth + j) + + val weightedSum = weightedInts.sumOf { it.second.toDouble() } + if(weightedSum.roundToInt() != 1) { + throw IllegalArgumentException("The sum of the probabilities must be 1. It is $weightedSum") + } + + val lowestPossible = weightedInts.filter { it.first.fish >= (totalSum - currentSum) / notFilled } + .minOf { it.first.fish } + val highestPossible = min(totalSum - currentSum, weightedInts.maxOf { it.first.fish }) + + val possibleValues = + weightedInts.filter { it.first.fish in lowestPossible..highestPossible }.map { it.first.fish } + val possibleWeights = + weightedInts.filter { it.first.fish in lowestPossible..highestPossible }.map { it.second } + + val value = random.nextFloat() + var cumulativeWeight = 0f + var index = 0 + while(index < possibleValues.size && cumulativeWeight + possibleWeights[index] < value) { + cumulativeWeight += possibleWeights[index] + index++ + } + + fields[i][j] = Field(possibleValues[index]) + countOne += if(fields[i][j].fish == 1) 1 else 0 + } + } + + for(i in 0 until length) { + for(j in 0 until halfWidth) { + val x = random.nextInt(length) + val y = random.nextInt(halfWidth) + fields[i][j] = fields[x][y].also { fields[x][y] = fields[i][j] } + } + } + + for(i in 0 until length) { + for(j in 0 until halfWidth) { + // TODO ?? + // fields[i] += fields[length - i - 1][halfWidth - j - 1] + } + } + + return fields.let { + it + it.reversedArray().map { list -> + Array(Constants.BOARD_SIZE) { index -> list[Constants.BOARD_SIZE - index - 1].deepCopy() } + } + } + } } }