From c437f715c4d2a8e1fd7fa699dcec8d6f5e813c6e Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Mon, 13 Mar 2017 20:05:38 +0300 Subject: [PATCH] Tetris --- sdl_test/sdl.def | 5 + sdl_test/tetris.kt | 817 ++++++++++++++++++++++++++++++++ sdl_test/tetris_all.bmp | Bin 0 -> 36054 bytes sdl_test/tetris_cells_texts.bmp | Bin 0 -> 99126 bytes 4 files changed, 822 insertions(+) create mode 100644 sdl_test/sdl.def create mode 100644 sdl_test/tetris.kt create mode 100755 sdl_test/tetris_all.bmp create mode 100755 sdl_test/tetris_cells_texts.bmp diff --git a/sdl_test/sdl.def b/sdl_test/sdl.def new file mode 100644 index 00000000000..c68646d6ec7 --- /dev/null +++ b/sdl_test/sdl.def @@ -0,0 +1,5 @@ +headers = /Library/Frameworks/SDL2.framework/Headers/SDL.h stdio.h string.h unistd.h stdlib.h time.h +excludedFunctions = _IO_flockfile _IO_funlockfile _IO_ftrylockfile _IO_cleanup_region_start _IO_cleanup_region_end \ + mkstemp_dprotected_np + +compilerOpts = -D_POSIX_SOURCE -mxsave -mavx -mf16c diff --git a/sdl_test/tetris.kt b/sdl_test/tetris.kt new file mode 100644 index 00000000000..bc8f3520e15 --- /dev/null +++ b/sdl_test/tetris.kt @@ -0,0 +1,817 @@ +import kotlinx.cinterop.* +import konan.internal.* +import sdl.* + +typealias Field = Array + +enum class Move { + Left, + Right, + Down, + Rotate +} + +enum class PlacementResult(val linesCleared: Int = 0, val bonus: Int = 0) { + Nothing, + GameOver, + // For values of bonuses see https://tetris.wiki/Scoring + Single(1, 40), + Double(2, 100), + Triple(3, 300), + Tetris(4, 1200) +} + +val EMPTY: Byte = 0 +val BRICK: Byte = -1 + +class Point(var x: Int, var y: Int) + +operator fun Point.plus(other: Point): Point { + return Point(x + other.x, y + other.y) +} + +class PiecePosition(piece: Piece, private val origin: Point) { + private var p = piece.origin + val x get() = p.x + origin.x + val y get() = p.y + origin.y + + var state: Int get private set + val numberOfStates = piece.numberOfStates + + init { + state = 0 + } + + fun makeMove(move: Move) { + when (move) { + Move.Left -> --p.y + Move.Right -> ++p.y + Move.Down -> ++p.x + Move.Rotate -> state = (state + 1) % numberOfStates + } + } + + fun unMakeMove(move: Move) { + when (move) { + Move.Left -> ++p.y + Move.Right -> --p.y + Move.Down -> --p.x + Move.Rotate -> state = (state + numberOfStates - 1) % numberOfStates + } + } +} + +/* + * We use Nintendo Rotation System, right-handed version. + * See https://tetris.wiki/Nintendo_Rotation_System + */ +enum class Piece(private val origin_: Point, vararg val states: Field) { + T(Point(-1, -2), + arrayOf( + byteArrayOf(0, 0, 0), + byteArrayOf(1, 1, 1), + byteArrayOf(0, 1, 0)), + arrayOf( + byteArrayOf(0, 1, 0), + byteArrayOf(1, 1, 0), + byteArrayOf(0, 1, 0)), + arrayOf( + byteArrayOf(0, 1, 0), + byteArrayOf(1, 1, 1), + byteArrayOf(0, 0, 0)), + arrayOf( + byteArrayOf(0, 1, 0), + byteArrayOf(0, 1, 1), + byteArrayOf(0, 1, 0)) + ), + J(Point(-1, -2), + arrayOf( + byteArrayOf(0, 0, 0), + byteArrayOf(2, 2, 2), + byteArrayOf(0, 0, 2)), + arrayOf( + byteArrayOf(0, 2, 0), + byteArrayOf(0, 2, 0), + byteArrayOf(2, 2, 0)), + arrayOf( + byteArrayOf(2, 0, 0), + byteArrayOf(2, 2, 2), + byteArrayOf(0, 0, 0)), + arrayOf( + byteArrayOf(0, 2, 2), + byteArrayOf(0, 2, 0), + byteArrayOf(0, 2, 0)) + ), + Z(Point(-1, -2), + arrayOf( + byteArrayOf(0, 0, 0), + byteArrayOf(3, 3, 0), + byteArrayOf(0, 3, 3)), + arrayOf( + byteArrayOf(0, 0, 3), + byteArrayOf(0, 3, 3), + byteArrayOf(0, 3, 0)) + ), + O(Point(0, -2), + arrayOf( + byteArrayOf(1, 1), + byteArrayOf(1, 1)) + ), + S(Point(-1, -2), + arrayOf( + byteArrayOf(0, 0, 0), + byteArrayOf(0, 2, 2), + byteArrayOf(2, 2, 0)), + arrayOf( + byteArrayOf(0, 2, 0), + byteArrayOf(0, 2, 2), + byteArrayOf(0, 0, 2)) + ), + L(Point(-1, -2), + arrayOf( + byteArrayOf(0, 0, 0), + byteArrayOf(3, 3, 3), + byteArrayOf(3, 0, 0)), + arrayOf( + byteArrayOf(3, 3, 0), + byteArrayOf(0, 3, 0), + byteArrayOf(0, 3, 0)), + arrayOf( + byteArrayOf(0, 0, 3), + byteArrayOf(3, 3, 3), + byteArrayOf(0, 0, 0)), + arrayOf( + byteArrayOf(0, 3, 0), + byteArrayOf(0, 3, 0), + byteArrayOf(0, 3, 3)) + ), + I(Point(-2, -2), + arrayOf( + byteArrayOf(0, 0, 0, 0), + byteArrayOf(0, 0, 0, 0), + byteArrayOf(1, 1, 1, 1), + byteArrayOf(0, 0, 0, 0)), + arrayOf( + byteArrayOf(0, 0, 1, 0), + byteArrayOf(0, 0, 1, 0), + byteArrayOf(0, 0, 1, 0), + byteArrayOf(0, 0, 1, 0)) + ); + + val origin get() = Point(origin_.x, origin_.y) + val numberOfStates: Int = states.size + + fun canBePlaced(field: Field, position: PiecePosition): Boolean { + val piece = states[position.state] + val x = position.x + val y = position.y + for (i in piece.indices) { + val pieceRow = piece[i] + val boardRow = field[x + i] + for (j in pieceRow.indices) { + if (pieceRow[j] != EMPTY && boardRow[y + j] != EMPTY) + return false + } + } + return true + } + + fun place(field: Field, position: PiecePosition) { + val piece = states[position.state] + val x = position.x + val y = position.y + for (i in piece.indices) { + val pieceRow = piece[i] + for (j in pieceRow.indices) { + if (pieceRow[j] != EMPTY) field[x + i][y + j] = pieceRow[j] + } + } + } + + fun unPlace(field: Field, position: PiecePosition) { + val piece = states[position.state] + val x = position.x + val y = position.y + for (i in piece.indices) { + val pieceRow = piece[i] + for (j in pieceRow.indices) { + if (pieceRow[j] != EMPTY) field[x + i][y + j] = EMPTY + } + } + } +} + +interface GameFieldVisualizer { + fun drawCell(x: Int, y: Int, cell: Byte) + fun drawNextPieceCell(x: Int, y: Int, cell: Byte) + fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) + fun refresh() +} + +enum class UserCommand { + LEFT, + RIGHT, + DOWN, + RELEASE, + ROTATE, + EXIT +} + +interface UserInput { + fun readCommands(): List +} + +fun sleep(millis: Int) { + SDL_Delay(millis) +} + +class GameField(val width: Int, val height: Int, val visualizer: GameFieldVisualizer) { + val MARGIN = 4 + + private val field: Field + private val origin: Point + private val nextPieceField: Field + + init { + field = Array(height + MARGIN * 2) { ByteArray(width + MARGIN * 2) } + for (i in field.indices) { + val row = field[i] + for (j in row.indices) { + if (i >= (MARGIN + height) // Bottom (field is flipped over). + || (j < MARGIN) // Left + || (j >= MARGIN + width)) // Right + row[j] = BRICK + } + } + // Coordinates are relative to the central axis and top of the field. + origin = Point(MARGIN, MARGIN + (width + 1) / 2) + nextPieceField = Array(4) { ByteArray(4) } + } + + lateinit var currentPiece: Piece + lateinit var nextPiece: Piece + lateinit var currentPosition: PiecePosition + + fun reset() { + for (i in 0..height - 1) + for (j in 0..width - 1) + field[i + MARGIN][j + MARGIN] = 0 + srand(time(null).toInt()) + nextPiece = getNextPiece(false) + switchCurrentPiece() + } + + private fun randInt() = (rand() and 32767) or ((rand() and 32767) shl 15) + + private fun getNextPiece(denyPrevious: Boolean): Piece { + val pieces = Piece.values() + if (!denyPrevious) + return pieces[randInt() % pieces.size] + while (true) { + val nextPiece = pieces[randInt() % pieces.size] + if (nextPiece != currentPiece) return nextPiece + } + } + + private fun switchCurrentPiece() { + currentPiece = nextPiece + nextPiece = getNextPiece(denyPrevious = true) // Forbid repeating the same piece for better distribution. + currentPosition = PiecePosition(currentPiece, origin) + } + + fun makeMove(move: Move): Boolean { + currentPosition.makeMove(move) + if (currentPiece.canBePlaced(field, currentPosition)) + return true + currentPosition.unMakeMove(move) + return false + } + + /** + * Places current piece at its current location. + */ + fun place(): PlacementResult { + currentPiece.place(field, currentPosition) + val linesCleared = clearLines() + if (isOutOfBorders()) return PlacementResult.GameOver + switchCurrentPiece() + if (!currentPiece.canBePlaced(field, currentPosition)) + return PlacementResult.GameOver + when (linesCleared) { + 1 -> return PlacementResult.Single + 2 -> return PlacementResult.Double + 3 -> return PlacementResult.Triple + 4 -> return PlacementResult.Tetris + else -> return PlacementResult.Nothing + } + } + + private fun clearLines(): Int { + val clearedLines = mutableListOf() + for (i in 0..height - 1) { + val row = field[i + MARGIN] + if ((0..width - 1).all { j -> row[j + MARGIN] != EMPTY }) { + clearedLines.add(i + MARGIN) + (0..width - 1).forEach { j -> row[j + MARGIN] = EMPTY } + } + } + if (clearedLines.size == 0) return 0 + draw(false) + visualizer.refresh() + sleep(500) + for (i in clearedLines) { + for (k in i - 1 downTo 1) + for (j in 0..width - 1) + field[k + 1][j + MARGIN] = field[k][j + MARGIN] + } + draw(false) + visualizer.refresh() + return clearedLines.size + } + + private fun isOutOfBorders(): Boolean { + for (i in 0..MARGIN - 1) + for (j in 0..width - 1) + if (field[i][j + MARGIN] != EMPTY) + return true + return false + } + + fun draw() { + draw(true) + drawNextPiece() + } + + private fun drawNextPiece() { + for (i in 0..3) + for (j in 0..3) + nextPieceField[i][j] = 0 + nextPiece.place(nextPieceField, PiecePosition(nextPiece, Point(1, 2))) + for (i in 0..3) + for (j in 0..3) + visualizer.drawNextPieceCell(i, j, nextPieceField[i][j]) + } + + private fun draw(drawCurrentPiece: Boolean) { + if (drawCurrentPiece) + currentPiece.place(field, currentPosition) + for (i in 0..height - 1) + for (j in 0..width - 1) + visualizer.drawCell(i, j, field[i + MARGIN][j + MARGIN]) + if (drawCurrentPiece) + currentPiece.unPlace(field, currentPosition) + } +} + +class Game(width: Int, height: Int, val visualizer: GameFieldVisualizer, val userInput: UserInput) { + private val field = GameField(width, height, visualizer) + + private var gameOver = true + private var startLevel = 0 + private var leveledUp = false + private var level = 0 + private var linesClearedAtCurrentLevel = 0 + private var linesCleared = 0 + private var tetrises = 0 + private var score = 0 + + /* + * For speed constants and level up thresholds see https://tetris.wiki/Tetris_(NES,_Nintendo) + */ + private val speeds = intArrayOf(48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) + private val levelUpThreshold + get() = + if (leveledUp) 10 + else minOf(startLevel * 10 + 10, maxOf(100, startLevel * 10 - 50)) + private val speed get() = if (level < 29) speeds[level] else 1 + + private var ticks = 0 + + fun startNewGame(level: Int) { + gameOver = false + startLevel = level + leveledUp = false + this.level = level + linesClearedAtCurrentLevel = 0 + linesCleared = 0 + tetrises = 0 + score = 0 + ticks = 0 + field.reset() + + visualizer.setInfo(linesCleared, level, score, tetrises) + field.draw() + visualizer.refresh() + + mainLoop() + } + + private fun placePiece() { + val placementResult = field.place() + ticks = 0 + println(placementResult.toString()) + when (placementResult) { + PlacementResult.Nothing -> return + PlacementResult.GameOver -> { + gameOver = true + return + } + else -> { + linesCleared += placementResult.linesCleared + linesClearedAtCurrentLevel += placementResult.linesCleared + score += placementResult.bonus * (level + 1) + if (placementResult == PlacementResult.Tetris) + ++tetrises + val levelUpThreshold = levelUpThreshold + if (linesClearedAtCurrentLevel >= levelUpThreshold) { + ++level + linesClearedAtCurrentLevel -= levelUpThreshold + leveledUp = true + } + + visualizer.setInfo(linesCleared, level, score, tetrises) + } + } + } + + /* + * Number of additional gravity shifts before locking a piece landed on the ground. + * This is needed in order to let user to move a piece to the left/right before locking. + */ + private val LOCK_DELAY = 1 + + private fun mainLoop() { + var prevCmd: UserCommand? = null + var das = false + var dasTicks = 0 + var attemptsToLock = 0 + while (!gameOver) { + sleep(1000 / 60) // Refresh rate - 60 frames per second. + //sleep(200) + val commands = userInput.readCommands() + for (cmd in commands) { + val success: Boolean + when (cmd) { + UserCommand.EXIT -> return + UserCommand.LEFT -> success = field.makeMove(Move.Left) + UserCommand.RIGHT -> success = field.makeMove(Move.Right) + UserCommand.ROTATE -> success = field.makeMove(Move.Rotate) + UserCommand.DOWN -> { + success = field.makeMove(Move.Down) + if (!success) placePiece() + } + UserCommand.RELEASE -> { + while (field.makeMove(Move.Down)) { + } + success = true + placePiece() + } + } + if (success) { + field.draw() + visualizer.refresh() + } + } + ++ticks + if (ticks < speed) continue + if (!field.makeMove(Move.Down)) { + if (++attemptsToLock >= LOCK_DELAY) { + placePiece() + attemptsToLock = 0 + } + } + field.draw() + visualizer.refresh() + ticks -= speed + } + } + +} + +fun main(args: Array) { + SDL_main(args) +} + +fun print_SDL_Error() { + externals.printf(SDL_GetError()!!.rawValue) +} + +class SDL_Visualizer(val width: Int, val height: Int): GameFieldVisualizer, UserInput { + private val CELL_SIZE = 20 + private val SYMBOL_SIZE = 21 + private val INFO_MARGIN = 10 + private val MARGIN = 2 + private val BORDER_WIDTH = 18 + private val INFO_SPACE_WIDTH = SYMBOL_SIZE * (2 + 8) + + private val field: Field = Array(height) { ByteArray(width) } + private val nextPieceField: Field = Array(4) { ByteArray(4) } + private var linesCleared: Int = 0 + private var level: Int = 0 + private var score: Int = 0 + private var tetrises: Int = 0 + + private val fieldWidth: Int + private val fieldHeight: Int + private val window: CPointer + private val renderer: CPointer + private val cells: CPointer + private val texts: CPointer + + init { + if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { + //println("SDL_Init error: ${SDL_GetError()}") + print("SDL_CreateWindow Error: ") + print_SDL_Error() + println() + throw Error() + } + + fieldWidth = width * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 + fieldHeight = height * (CELL_SIZE + MARGIN) + MARGIN + BORDER_WIDTH * 2 + val win = SDL_CreateWindow("Tetris", 100, 100, fieldWidth + INFO_SPACE_WIDTH, + fieldHeight, SDL_WindowFlags.SDL_WINDOW_SHOWN.value) + if (win == null) { + //println("SDL_CreateWindow Error: ${SDL_GetError()!!.asCString()}") + print("SDL_CreateWindow Error: ") + print_SDL_Error() + println() + SDL_Quit() + throw Error() + } + window = win + + val ren = SDL_CreateRenderer(win, -1, (SDL_RendererFlags.SDL_RENDERER_ACCELERATED or SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC).value) + if (ren == null) { + SDL_DestroyWindow(win) + //println("SDL_CreateRenderer Error: ${SDL_GetError()!!.asCString()}") + println("SDL_CreateRenderer Error: ") + print_SDL_Error() + println() + SDL_Quit() + throw Error() + } + renderer = ren + + // TODO: merge together. + cells = loadImage(win, ren, "tetris_all.bmp") + texts = loadImage(win, ren, "tetris_cells_texts.bmp") +// if (SDL_SetTextureAlphaMod(tex, 63) != 0) { +// println("Unable to set alpha mod") +// print_SDL_Error() +// println() +// } +// if (SDL_SetTextureColorMod(tex, 127, 127, 127) != 0) { +// println("Unable to set color mod") +// print_SDL_Error() +// println() +// } + } + + private fun loadImage(win: CPointer, ren: CPointer, imagePath: String): CPointer { + val bmp = SDL_LoadBMP_RW(SDL_RWFromFile(imagePath, "rb"), 1); + if (bmp == null) { + SDL_DestroyRenderer(ren) + SDL_DestroyWindow(win) + //println("SDL_LoadBMP Error: ${SDL_GetError()!!.asCString()}") + println("SDL_LoadBMP Error: ") + print_SDL_Error() + println() + SDL_Quit() + throw Error() + } + + val tex = SDL_CreateTextureFromSurface(ren, bmp) + SDL_FreeSurface(bmp) + if (tex == null) { + SDL_DestroyRenderer(ren) + SDL_DestroyWindow(win) + //println("SDL_CreateTextureFromSurface Error: ${SDL_GetError()!!.asCString()}") + println("SDL_CreateTextureFromSurface Error: ") + print_SDL_Error() + println() + SDL_Quit() + throw Error() + } + return tex + } + + override fun drawCell(x: Int, y: Int, cell: Byte) { + field[x][y] = cell + } + + override fun drawNextPieceCell(x: Int, y: Int, cell: Byte) { + nextPieceField[x][y] = cell + } + + override fun setInfo(linesCleared: Int, level: Int, score: Int, tetrises: Int) { + this.linesCleared = linesCleared + this.level = level + this.score = score + this.tetrises = tetrises + } + + override fun refresh() { + SDL_RenderClear(renderer) + drawBorder() + drawField() + drawInfo() + drawNextPiece() + SDL_RenderPresent(renderer) + } + + private fun drawBorder() { + memScoped { + val rect = alloc() + rect.w.value = fieldWidth + rect.h.value = fieldHeight + rect.x.value = 0 + rect.y.value = 0 + SDL_SetRenderDrawColor(renderer, -128, 0, -128, -128) + SDL_RenderFillRect(renderer, rect.ptr.reinterpret()) + rect.w.value = fieldWidth - BORDER_WIDTH * 2 + rect.h.value = fieldHeight - BORDER_WIDTH * 2 + rect.x.value = BORDER_WIDTH + rect.y.value = BORDER_WIDTH + SDL_SetRenderDrawColor(renderer, 0, 0, 0, -128) + SDL_RenderFillRect(renderer, rect.ptr.reinterpret()) + } + } + + private fun drawField() { + drawField(field, width, height, MARGIN + BORDER_WIDTH, MARGIN + BORDER_WIDTH) + } + + private fun drawNextPiece() { + drawInt(103, 60 + SYMBOL_SIZE, fieldWidth + SYMBOL_SIZE, SYMBOL_SIZE * 11 + INFO_MARGIN * 6, 85, 0, 0) + drawField(nextPieceField, 4, 4, + fieldWidth + SYMBOL_SIZE + MARGIN + CELL_SIZE + MARGIN, + SYMBOL_SIZE * 12 + INFO_MARGIN * 7 + MARGIN) + } + + private fun drawField(f: Field, w: Int, h: Int, x: Int, y: Int) { + memScoped { + val srcRect = alloc() + val destRect = alloc() + srcRect.w.value = CELL_SIZE + srcRect.h.value = CELL_SIZE + destRect.w.value = CELL_SIZE + destRect.h.value = CELL_SIZE + for (i in 0..h - 1) + for (j in 0..w - 1) { + val cell = f[i][j].toInt() + if (cell == 0) continue + srcRect.x.value = (cell - 1) * CELL_SIZE + srcRect.y.value = (level % 10) * CELL_SIZE + destRect.x.value = x + j * (CELL_SIZE + MARGIN) + destRect.y.value = y + i * (CELL_SIZE + MARGIN) + SDL_RenderCopy(renderer, cells, srcRect.ptr.reinterpret(), destRect.ptr.reinterpret()) + } + } + } + + private fun drawInfo() { + drawInt(104, 60, fieldWidth + SYMBOL_SIZE, SYMBOL_SIZE, 107, 6, score) + drawInt(0, 60, fieldWidth + SYMBOL_SIZE, SYMBOL_SIZE * 3 + INFO_MARGIN, 104, 3, linesCleared) + drawInt(0, 60 + SYMBOL_SIZE, fieldWidth + SYMBOL_SIZE, SYMBOL_SIZE * 5 + INFO_MARGIN * 2, 103, 2, level) + drawInt(0, 60 + SYMBOL_SIZE * 2, fieldWidth + SYMBOL_SIZE, SYMBOL_SIZE * 7 + INFO_MARGIN * 3, 162, 2, tetrises) + } + + private fun drawInt(labelSrcX: Int, labelSrcY: Int, labelDestX: Int, labelDestY: Int, + labelWidth: Int, totalDigits: Int, value: Int) { + memScoped { + val srcRect = alloc() + val destRect = alloc() + + srcRect.w.value = labelWidth + srcRect.h.value = SYMBOL_SIZE + srcRect.x.value = labelSrcX + srcRect.y.value = labelSrcY + destRect.w.value = labelWidth + destRect.h.value = SYMBOL_SIZE + destRect.x.value = labelDestX + destRect.y.value = labelDestY + + SDL_RenderCopy(renderer, texts, srcRect.ptr.reinterpret(), destRect.ptr.reinterpret()) + + val digits = IntArray(totalDigits) + var x = value + for (i in 0..totalDigits - 1) { + digits[totalDigits - 1 - i] = x % 10 + x = x / 10 + } + srcRect.w.value = SYMBOL_SIZE + srcRect.h.value = SYMBOL_SIZE + destRect.w.value = SYMBOL_SIZE + destRect.h.value = SYMBOL_SIZE + for (i in 0..totalDigits - 1) { + srcRect.x.value = digits[i] * SYMBOL_SIZE + srcRect.y.value = 123 // TODO: constant. + destRect.x.value = labelDestX + SYMBOL_SIZE + i * SYMBOL_SIZE + destRect.y.value = labelDestY + SYMBOL_SIZE + SDL_RenderCopy(renderer, texts, srcRect.ptr.reinterpret(), destRect.ptr.reinterpret()) + } + } + } + + private val LEFT_PRESSED = 1 + private val RIGHT_PRESSED = 2 + private val DOWN_PRESSED = 4 + private val UP_PRESSED = 8 + private val Z_PRESSED = 16 + private val ESC_PRESSED = 32 + private var pressedKeys = 0 + private var stickedKeys = 0 + + private fun keyToCommand(key: Int): UserCommand? = + when (key) { + LEFT_PRESSED -> (UserCommand.LEFT) + RIGHT_PRESSED -> (UserCommand.RIGHT) + DOWN_PRESSED -> (UserCommand.DOWN) + Z_PRESSED -> (UserCommand.ROTATE) + UP_PRESSED -> (UserCommand.RELEASE) + ESC_PRESSED -> (UserCommand.EXIT) + else -> null + } + + override fun readCommands(): List { + val commands = mutableListOf() + memScoped { + val event = alloc() + var currentCommands = 0 + while (SDL_PollEvent(event.ptr.reinterpret()) != 0) { + if (event.type.value == SDL_EventType.SDL_KEYDOWN.value + || event.type.value == SDL_EventType.SDL_KEYUP.value) { + val keyboardEvent = event.ptr.reinterpret().pointed + val scancode = when (keyboardEvent.keysym.scancode.value) { + SDL_Scancode.SDL_SCANCODE_LEFT -> LEFT_PRESSED + SDL_Scancode.SDL_SCANCODE_RIGHT -> RIGHT_PRESSED + SDL_Scancode.SDL_SCANCODE_DOWN -> DOWN_PRESSED + SDL_Scancode.SDL_SCANCODE_Z -> Z_PRESSED + SDL_Scancode.SDL_SCANCODE_UP -> UP_PRESSED + SDL_Scancode.SDL_SCANCODE_ESCAPE -> ESC_PRESSED + else -> 0 + } + if (keyboardEvent.state.value.toInt() == SDL_PRESSED) { + if (pressedKeys and scancode != 0) + stickedKeys = stickedKeys or scancode + currentCommands = currentCommands or scancode + pressedKeys = pressedKeys or scancode + } + else if (keyboardEvent.state.value.toInt() == SDL_RELEASED) { + pressedKeys = pressedKeys and scancode.inv() + stickedKeys = stickedKeys and scancode.inv() + } + } + } + currentCommands = currentCommands or stickedKeys + var temp = currentCommands + while (temp != 0) { + val next = temp and (temp - 1) + val curKey = temp - next + when (curKey) { + LEFT_PRESSED -> commands.add(UserCommand.LEFT) + RIGHT_PRESSED -> commands.add(UserCommand.RIGHT) + DOWN_PRESSED -> commands.add(UserCommand.DOWN) + Z_PRESSED -> commands.add(UserCommand.ROTATE) + UP_PRESSED -> commands.add(UserCommand.RELEASE) + ESC_PRESSED -> commands.add(UserCommand.EXIT) + } + temp = next + } + } + return commands + } + + fun destroy() { + SDL_DestroyTexture(cells) + SDL_DestroyRenderer(renderer) + SDL_DestroyWindow(window) + SDL_Quit() + } +} + +@ExportForCppRuntime("SDL_main") +fun SDL_main(args: Array) { + var startLevel = 0 + var width = 10 + var height = 20 + when (args.size) { + 1 -> startLevel = atoi(args[0]) + 2 -> { + width = atoi(args[0]) + height = atoi(args[1]) + } + 3 -> { + width = atoi(args[0]) + height = atoi(args[1]) + startLevel = atoi(args[2]) + } + } + val visualizer = SDL_Visualizer(width, height) + val game = Game(width, height, visualizer, visualizer) + game.startNewGame(startLevel) + + return +} \ No newline at end of file diff --git a/sdl_test/tetris_all.bmp b/sdl_test/tetris_all.bmp new file mode 100755 index 0000000000000000000000000000000000000000..ae4d33ba51cdd6c6b21284ee0a7a1282df6aedd7 GIT binary patch literal 36054 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 literal 0 HcmV?d00001 diff --git a/sdl_test/tetris_cells_texts.bmp b/sdl_test/tetris_cells_texts.bmp new file mode 100755 index 0000000000000000000000000000000000000000..058d090e350dfe846ad626524e4b18b9349e514e GIT binary patch literal 99126 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

64m< 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 literal 0 HcmV?d00001