diff --git a/32_Diamond/kotlin/README.md b/32_Diamond/kotlin/README.md index f43a5b70..83eaac65 100644 --- a/32_Diamond/kotlin/README.md +++ b/32_Diamond/kotlin/README.md @@ -1,3 +1,12 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Kotlin](https://kotlinlang.org/) +Conversion to [Kotlin](https://kotlinlang.org/), structure inspired from [the Java port](https://github.com/coding-horror/basic-computer-games/blob/main/32_Diamond/java/Diamond.java). + +### How to Run +1. Install [kotlin command line](https://kotlinlang.org/docs/command-line.html) compiler from JetBrains. +2. Compile with `kotlinc diamond.kt -include-runtime -d diamond.jar` +3. Run with `java -jar diamond.jar` + +### Changes from Original +This version validates that user input is correct. + diff --git a/32_Diamond/kotlin/diamond.kt b/32_Diamond/kotlin/diamond.kt new file mode 100644 index 00000000..9db6125f --- /dev/null +++ b/32_Diamond/kotlin/diamond.kt @@ -0,0 +1,154 @@ + +/** + * Game of Diamond + *

+ * Based on the BASIC game of Diamond + * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas + *

+ * + * Changes From Original: Input is validated. + * + * Converted from BASIC to Kotlin by Martin Marconcini (@Gryzor) + * Inspired in the Java code written by Darren Cardenas. + */ + + +fun main() { + Diamond().startGame() +} + +class Diamond { + init { + printIntro() + } + + fun startGame() { + var body: Int + var end: Int + var start: Int = 1 + var row: Int = 1 + var numPerRow: Int + var increment: Int = 2 + var lineContent: String + var prefixIndex: Int + + printPrompt() + + // Read the user input + val input = readLine() + + // Validate input + val userInput: Int = try { + input?.toInt() ?: -1 + } catch (e: NumberFormatException) { + -1 + } + if (!isValid(userInput)) { + printInvalidInput() + return + } + + // Calculate how many diamonds can horizontally fit in the given space + numPerRow = calculateDiamondsPerRow(userInput) + end = userInput + + // Loop throw rows of Diamonds + while (row <= numPerRow) { + body = start + while (canLoop(increment, body, end)) { + lineContent = "" + + // Add white spaces to the "left" of the leftmost diamond. + while (lineContent.length < ((userInput - body) / 2)) { + lineContent += " " + } + + // Begin loop through each column of diamonds + for (col in 1..numPerRow) { + prefixIndex = 1 + + // Begin loop that fills each diamond with characters (not whitespace) + for (fill in 1..body) { + // Right side of diamond, if the index is greater than the prefix, put a Symbol. + if (prefixIndex > PREFIX.length) { + lineContent += SYMBOL + } + // Left side of diamond, pick a Prefix character (-1 since it starts at 0) + else { + lineContent += PREFIX[prefixIndex - 1] + prefixIndex++ + } + }// End loop that fills each diamond with characters + + // Is Column finished? + if (col == numPerRow) { + break + } + // Column is not finished... + else { + // Add whitespace on the "right" side of the current diamond, and fill the "left" side of the + // next; doesn't fill the space to the right of the rightmost diamond. + while (lineContent.length < (userInput * col + (userInput - body) / 2)) { + lineContent += " " + } + + } + + }// End loop through each column of diamonds + + // Print the current Line + println(lineContent) + + // Increment the body that moves + body += increment + } //end While Loop throw rows of Diamonds + + // Increment the current Row of diamonds. + row++ + + if (start != 1) { + start = 1 + end = userInput + increment = 2 + } else { + // We're rendering the "bottom half" of the total rendering. + // Alter the parameters, and decrease the row number so the logic can loop again. + start = userInput - 2 + end = 1 + increment = -2 + row-- + } + } // End loop through each row of diamonds + } + + private fun canLoop(increment: Int, body: Int, end: Int): Boolean = if (increment < 0) body >= end else body <= end + + private fun calculateDiamondsPerRow(totalDiamonds: Int): Int = LINE_WIDTH / totalDiamonds + + private fun isValid(input: Int): Boolean = (input in 5..21) && (input % 2 != 0) + + private fun printInvalidInput() = println("Invalid input") + + private fun printPrompt() { + println( + """ + FOR A PRETTY DIAMOND PATTERN + TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? + """.trimIndent() + ) + println() + } + + private fun printIntro() { + println(" ".repeat(32) + "DIAMOND") + println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + println() + println() + } + + companion object { + const val LINE_WIDTH = 60 + const val PREFIX = "CC" + const val SYMBOL = "!" + } +}