From b202acb958f5b0d03145eff33935b50e94b3199a Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Sun, 29 Aug 2021 01:27:18 -0400 Subject: [PATCH] fix another bug, add GameConfig object --- src/gamepkg/gui.nim | 73 ++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/src/gamepkg/gui.nim b/src/gamepkg/gui.nim index faf7a50..799a0f9 100644 --- a/src/gamepkg/gui.nim +++ b/src/gamepkg/gui.nim @@ -7,13 +7,30 @@ from times import getTime, toUnix, nanosecond let now = getTime() randomize(now.toUnix * 1_000_000_000 + now.nanosecond) -# constants -const rowSize = 15 # How many tiles per row of the board -const boxStride: int = (900 * (1/rowSize)).int # How much space does a tile take up -const borderWidth: float32 = 6.float32 # How wide are the borders between tiles -const sideSize = (boxStride-borderWidth.int).float32 # How long is a side of a tile -const averageMineCount = ((rowSize*rowSize) * 0.10).int # How many mines should be placed on average? -const boardOffset: int = 90 # How far is the board from the top of the window +type GameConfig = object + rowSize: int + boxStride: int + borderWidth: float32 + sideSize: float32 + boardOffset: int + averageMineCount: int + +proc makeConfig(rowSize: int, + borderWidth: float32, + boardOffset: int, + minePercentage: float32 = 0.15) : GameConfig = + let boxStride: int = (900 * (1/rowSize)).int # How much space does a tile take up + let sideSize = (boxStride-borderWidth.int).float32 # How long is a side of a tile + let averageMineCount = (rowSize*rowSize) * minePercentage.int # How many mines should be placed on average? + + GameConfig(rowSize: rowSize, + boxStride: boxStride, + borderWidth: borderWidth, + sideSize: sideSize, + boardOffset: boardOffset, + averageMineCount: if averageMineCount > 0: averageMineCount else: 5) + +const gameConf = makeConfig(10, 6, 90) type GameState = enum unfinished, @@ -46,11 +63,11 @@ proc isWinning(board: Board): bool = proc getTile(board: Board, x: int, y: int): Option[Tile] = # Given x, y coords, get tile if it exists - if x > (rowSize - 1) or y > (rowSize - 1) or x < 0 or y < 0: + if x > (gameConf.rowSize - 1) or y > (gameConf.rowSize - 1) or x < 0 or y < 0: return none(Tile) let l = board.tiles.len - let pos = (rowSize * y) + x + let pos = (gameConf.rowSize * y) + x if pos >= 0 and pos < l: return some(board.tiles[pos]) @@ -114,7 +131,7 @@ proc revealBoard(board: Board, tile: Tile) = q.push(neighbour) proc setMine(numMines: int): bool = - let maxR: float = rowSize*rowSize + let maxR: float = gameConf.rowSize*gameConf.rowSize return rand(max_r) < (numMines.float) proc comparator(a: tuple[l: float32, h: float32], k: int): int = @@ -130,23 +147,23 @@ proc getTilePos(mouseX: int, mouseY: int, board: Board): int = # Do search for the tile x and y coordinates using intervals # Return position in the set of tiles - const boardLength = (boxStride+boardOffset.int) * (rowSize - 1) # How long is a side of the board - if mouseX.float32 > (boardLength + borderWidth) or mouseY.float32 > (boardLength + borderWidth): + const boardLength = (gameConf.boxStride+gameConf.boardOffset.int) * (gameConf.rowSize - 1) # How long is a side of the board + if mouseX.float32 > (boardLength + gameConf.borderWidth) or mouseY.float32 > (boardLength + gameConf.borderWidth): return -1 - if mouseX < boardOffset or mouseY < boardOffset: + if mouseX < gameConf.boardOffset or mouseY < gameConf.boardOffset: return -1 let x: int = board.xIntervals.binarySearch(mouseX, comparator) - 1 let y: int = board.yIntervals.binarySearch(mouseY, comparator) - 1 - return (y*rowSize) + x + return (y*gameConf.rowSize) + x proc drawTile(heightPos: int, widthPos: int, state: TileState, reveal: bool = false): Tile = let edge = 1.float32 # How far from the edge is the X - let y = boardOffset+(boxStride*heightPos) - let x = boardOffset+(boxStride*widthPos) + let y = gameConf.boardOffset+(gameConf.boxStride*heightPos) + let x = gameConf.boardOffset+(gameConf.boxStride*widthPos) - let boxRect = Rectangle(x: x.float32, y: y.float32, width: sideSize, height: sideSize) + let boxRect = Rectangle(x: x.float32, y: y.float32, width: gameConf.sideSize, height: gameConf.sideSize) let c1 = Color(r: 2, g: 91, b: 36, a: 255) let c2 = Color(r: 0, g: 0, b: 0, a: 255) @@ -158,7 +175,7 @@ proc drawTile(heightPos: int, widthPos: int, state: TileState, reveal: bool = fa elif state.revealed: DrawRectangleRec(boxRect, GREEN) if state.mineNeighbours > 0: - DrawText($state.mineNeighbours, x+(sideSize/4).int, y, sideSize.int, BLACK) + DrawText($state.mineNeighbours, x+(gameConf.sideSize/4).int, y, gameConf.sideSize.int, BLACK) # show everything if `reveal` is true elif reveal: @@ -167,12 +184,12 @@ proc drawTile(heightPos: int, widthPos: int, state: TileState, reveal: bool = fa DrawRectangleGradientEx(boxRect, c1, c2, c3, c4) let start1 = Vector2(x: x.float32+edge, y: y.float32+edge) - let end1 = Vector2(x: (x+boxStride).float32-borderWidth-edge, y: (y+boxStride).float32-borderWidth-edge) + let end1 = Vector2(x: (x+gameConf.boxStride).float32-gameConf.borderWidth-edge, y: (y+gameConf.boxStride).float32-gameConf.borderWidth-edge) let start2 = Vector2(x: (x).float32+edge, - y: (y+boxStride).float32-borderWidth-edge) + y: (y+gameConf.boxStride).float32-gameConf.borderWidth-edge) - let end2 = Vector2(x: (x+boxStride).float32-borderWidth-edge, + let end2 = Vector2(x: (x+gameConf.boxStride).float32-gameConf.borderWidth-edge, y: y.float32+edge) if state.marked: @@ -182,7 +199,7 @@ proc drawTile(heightPos: int, widthPos: int, state: TileState, reveal: bool = fa return Tile(state: state, x: widthPos, y: heightPos, pos: boxRect) proc drawBoardWindow() = - DrawRectangle(boardOffset, boardOffset, boxStride*rowSize, boxStride*rowSize, BLACK) + DrawRectangle(gameConf.boardOffset, gameConf.boardOffset, gameConf.boxStride*gameConf.rowSize, gameConf.boxStride*gameConf.rowSize, BLACK) proc generateBoard(screenWidth: int, screenHeight: int, rowSize: int): Board = # Draw the initial board @@ -199,7 +216,7 @@ proc generateBoard(screenWidth: int, screenHeight: int, rowSize: int): Board = state.marked = false state.revealed = false - state.mine = setMine(averageMineCount) # average number of mines + state.mine = setMine(gameConf.averageMineCount) # average number of mines state.mineNeighbours = 0 let tile = drawTile(heightPos, widthPos, state) @@ -293,7 +310,7 @@ proc guiLoop*() = if not tile.state.marked: revealBoard(board.get, tile) - if isWinning(board.get): + if isWinning(board.get) and gameState != lost: gameState = won if IsMouseButtonPressed(MOUSE_RIGHT_BUTTON): @@ -321,20 +338,20 @@ proc guiLoop*() = exitWindow = GuiWindowBox(Rectangle(x: 0.float32, y: 0.float32, width: screenWidth.float32, height: screenHeight.float32), "#198# Minesweeper".cstring) - restartButton = GuiButton(Rectangle(x: boardOffset.float32-10, y: boardOffset.float32-20, width: 80.float32, height: 20.float32), "Restart") + restartButton = GuiButton(Rectangle(x: gameConf.boardOffset.float32-10, y: gameConf.boardOffset.float32-20, width: 80.float32, height: 20.float32), "Restart") if board.isNone or restartButton: # Generate the initial board if there isn't one - board = some(generateBoard(screenWidth, screenHeight, rowSize)) + board = some(generateBoard(screenWidth, screenHeight, gameConf.rowSize)) gameState = unfinished else: if gameState == won and board.isSome: showBoard(screenWidth, screenHeight, board.get) - DrawText("You won! :)", (screenWidth.float32/2.5).int, (boardOffset/2).int, 30, GREEN) + DrawText("You won! :)", (screenWidth.float32/2.5).int, (gameConf.boardOffset/2).int, 30, GREEN) elif gameState == lost and board.isSome: showBoard(screenWidth, screenHeight, board.get) - DrawText("You lost! :(", (screenWidth.float32/2.5).int, (boardOffset/2).int, 30, RED) + DrawText("You lost! :(", (screenWidth.float32/2.5).int, (gameConf.boardOffset/2).int, 30, RED) # Otherwise update the state of the abstract board with the window else: