2048: Difference between revisions

6,048 bytes added ,  8 years ago
no edit summary
m (C solution: Add forgotten array element.)
No edit summary
Line 1,549:
}
</lang>
 
=={{header|Kotlin}}==
Stateless with focus on clarity rather than conciseness.
 
<lang kotlin>
package com.sbg.g2048.stateless
 
import java.io.BufferedReader
import java.io.InputStreamReader
 
const val positiveGameOverMessage = "So sorry, but you lost the game."
const val negativeGameOverMessage = "So sorry, but you won the game."
 
fun main(args: Array<String>) {
val grid = arrayOf(
arrayOf(0, 0, 0, 0),
arrayOf(0, 0, 0, 0),
arrayOf(0, 0, 0, 0),
arrayOf(0, 0, 0, 0)
)
 
val gameOverMessage = run2048(grid)
println(gameOverMessage)
}
 
fun run2048(grid: Array<Array<Int>>): String {
if (isGridSolved(grid)) return positiveGameOverMessage
else if (isGridFull(grid)) return negativeGameOverMessage
 
val populatedGrid = spawnNumber(grid)
display(populatedGrid)
 
return run2048(manipulateGrid(populatedGrid, waitForValidInput()))
}
 
fun isGridSolved(grid: Array<Array<Int>>): Boolean = grid.any { row -> row.contains(2048) }
fun isGridFull(grid: Array<Array<Int>>): Boolean = grid.all { row -> !row.contains(0) }
 
fun spawnNumber(grid: Array<Array<Int>>):Array<Array<Int>> {
val coordinates = locateSpawnCoordinates(grid)
val number = generateNumber()
 
return updateGrid(grid, coordinates, number)
}
 
fun locateSpawnCoordinates(grid: Array<Array<Int>>): Pair<Int, Int> {
val emptyCells = arrayListOf<Pair<Int, Int>>()
grid.forEachIndexed { x, row ->
row.forEachIndexed { y, cell ->
if (cell == 0) emptyCells.add(Pair(x, y))
}
}
 
return emptyCells[(Math.random() * (emptyCells.size()-1)).toInt()]
}
fun generateNumber(): Int = if (Math.random() > 0.10) 2 else 4
 
fun updateGrid(grid: Array<Array<Int>>, at: Pair<Int, Int>, value: Int): Array<Array<Int>> {
val updatedGrid = grid.copyOf()
updatedGrid[at.first][at.second] = value
return updatedGrid
}
 
fun waitForValidInput():String {
val input = waitForInput()
return if (isValidInput(input)) input else waitForValidInput()
}
fun isValidInput(input: String): Boolean = arrayOf("a", "s", "d", "w").contains(input)
 
fun waitForInput(): String {
val br = BufferedReader(InputStreamReader(System.`in`));
println("Direction? ")
return br.readLine()
}
 
fun manipulateGrid(grid: Array<Array<Int>>, input: String): Array<Array<Int>> = when (input) {
"a" -> shiftCellsLeft(grid)
"s" -> shiftCellsDown(grid)
"d" -> shiftCellsRight(grid)
"w" -> shiftCellsUp(grid)
else -> throw IllegalArgumentException("Expected one of [a, s, d, w]")
}
 
fun shiftCellsLeft(grid: Array<Array<Int>>): Array<Array<Int>> =
grid.map { row -> mergeAndShiftCells(row) }.toTypedArray()
 
fun shiftCellsRight(grid: Array<Array<Int>>): Array<Array<Int>> =
grid.map { row -> mergeAndShiftCells(row.reversed().toTypedArray()).reversed().toTypedArray() }.toTypedArray()
 
fun shiftCellsUp(grid: Array<Array<Int>>): Array<Array<Int>> {
val rows: Array<Array<Int>> = arrayOf(
arrayOf(grid[0][0], grid[1][0], grid[2][0], grid[3][0]),
arrayOf(grid[0][1], grid[1][1], grid[2][1], grid[3][1]),
arrayOf(grid[0][2], grid[1][2], grid[2][2], grid[3][2]),
arrayOf(grid[0][3], grid[1][3], grid[2][3], grid[3][3])
)
 
val updatedGrid = grid.copyOf()
 
rows.map { row ->
mergeAndShiftCells(row)
}.forEachIndexed { rowIdx, row ->
updatedGrid[0][rowIdx] = row[0]
updatedGrid[1][rowIdx] = row[1]
updatedGrid[2][rowIdx] = row[2]
updatedGrid[3][rowIdx] = row[3]
}
 
return updatedGrid
}
 
fun shiftCellsDown(grid: Array<Array<Int>>): Array<Array<Int>> {
val rows: Array<Array<Int>> = arrayOf(
arrayOf(grid[3][0], grid[2][0], grid[1][0], grid[0][0]),
arrayOf(grid[3][1], grid[2][1], grid[1][1], grid[0][1]),
arrayOf(grid[3][2], grid[2][2], grid[1][2], grid[0][2]),
arrayOf(grid[3][3], grid[2][3], grid[1][3], grid[0][3])
)
 
val updatedGrid = grid.copyOf()
 
rows.map { row ->
mergeAndShiftCells(row)
}.forEachIndexed { rowIdx, row ->
updatedGrid[3][rowIdx] = row[0]
updatedGrid[2][rowIdx] = row[1]
updatedGrid[1][rowIdx] = row[2]
updatedGrid[0][rowIdx] = row[3]
}
 
return updatedGrid
}
 
fun mergeAndShiftCells(row: Array<Int>): Array<Int> = organize(merge(row.copyOf()))
 
fun merge(row: Array<Int>, idxToMatch: Int = 0, idxToCompare: Int = 1): Array<Int> {
if (idxToMatch >= row.size)
return row
if (idxToCompare >= row.size)
return merge(row, idxToMatch + 1, idxToMatch + 2)
if (row[idxToMatch] == 0)
return merge(row, idxToMatch + 1, idxToMatch + 2)
 
if (row[idxToMatch] == row[idxToCompare]) {
row[idxToMatch] *= 2
row[idxToCompare] = 0
 
return merge(row, idxToMatch + 1, idxToMatch + 2)
} else {
return if (row[idxToCompare] != 0) merge(row, idxToMatch + 1, idxToMatch + 2)
else merge(row, idxToMatch, idxToCompare + 1)
}
}
 
fun organize(row: Array<Int>, idxToMatch: Int = 0, idxToCompare: Int = 1): Array<Int> {
if (idxToMatch >= row.size)
return row
if (idxToCompare >= row.size)
return organize(row, idxToMatch + 1, idxToMatch + 2)
if (row[idxToMatch] != 0)
return organize(row, idxToMatch + 1, idxToMatch + 2)
 
if (row[idxToCompare] != 0) {
row[idxToMatch] = row[idxToCompare]
row[idxToCompare] = 0
 
return organize(row, idxToMatch + 1, idxToMatch + 2)
} else {
return organize(row, idxToMatch, idxToCompare + 1)
}
}
 
fun display(grid: Array<Array<Int>>) {
val prettyPrintableGrid = grid.map { row ->
row.map { cell ->
if (cell == 0) " " else java.lang.String.format("%4d", cell)
}
}
 
println("New Grid:")
prettyPrintableGrid.forEach { row ->
println("+----+----+----+----+")
row.forEach { print("|$it") }
println("|")
}
println("+----+----+----+----+")
}</lang kotlin>
 
=={{header|Perl 6}}==
Anonymous user