Exit Full View

Games Cupboard / gamescupboard-server / src / main / kotlin / uk / co / nickthecoder / gamescupboard / server / games / Qwirkle.kt

package uk.co.nickthecoder.gamescupboard.server.games

import uk.co.nickthecoder.gamescupboard.common.*
import uk.co.nickthecoder.gamescupboard.server.*
import uk.co.nickthecoder.gamescupboard.server.commands.DealCommand
import uk.co.nickthecoder.gamescupboard.server.commands.ShuffleCommand
import uk.co.nickthecoder.gamescupboard.server.commands.TakeCommand

private const val pieceSize = 24
private const val margin = 10
private const val left = margin
private const val top = margin

/**
 * The point where the "bag" of tiles is located.
 */
private val bagPoint = SpecialPoint("bag", 101, playingAreaHeight - 21)

/**
 * Avatars are at the top of the screen.
 */
private val avatarPositions = HorizontalAvatarPositions(26)

/**
 * The area containing each player's hand of tiles.
 * Each player only sees their own tiles (PRIVATE).
 */
private val handArea = SpecialArea("hand", AreaType.PRIVATE, 150, playingAreaHeight - 40, playingAreaWidth - 150, 40)

/**
 * The main playing area. Tiles are always face up here.
 */
private val playArea = SpecialArea(
    "tileGrid",
    AreaType.PUBLIC,
    left,
    top,
    playingAreaWidth,
    playingAreaHeight - top - handArea.height,
    changeZOrder = ChangeZOrder.TOP,
    snap = RectangularSnapToGrid(pieceSize, pieceSize),
    warnUsingTint = false
)


private val pieces =
    Grid("pieces", "rummyCrossPieces.png", across = 7, down = 6, itemWidth = pieceSize, itemHeight = pieceSize)

/**
 * Creates 108 tiles. 6 copies of each type of tile. There are 6 different shapes, each in 6 different colors.
 */
private fun createTiles(): List<GameObject> {
    val result = mutableListOf<GameObject>()
    var id = 0

    // Place all pieces on the "bag" SpecialPoint. These are unsorted!
    for (duplicatePieces in 0..2) {
        for (shape in 0..5) {
            for (color in 0..5) {
                result.add(
                    FlippableImageObject(
                        id ++,
                        bagPoint.x,
                        bagPoint.y,
                        grid = pieces, gx = shape + 1, gy = color,
                        altX = 0, altY = 0, isFaceUp = false
                    )
                )
            }
        }
    }
    return result
}

private val rules = """
    _Qwirkle_
    
    See the [Wikipedia article for details|https://en.wikipedia.org/wiki/Qwirkle].
    
    Each player is dealt 6 tiles.
    The player with the highest number of same-colour, or same-shape tiles goes first.
    
    Each player takes turns placing tiles on the board in a single horizontal or vertical line.
    All tiles in the line(s) formed must be the same colour or the same shape, with no duplicates.
    
    Points are awarded based on the length of the lines created or extended.
    A bonus of 6 points are awarded for lines of length 6 (the maximum possible length).
    Unlike scrabble, there is no bonus for using all of your tiles.
    
    The player takes additional tiles from the bag, to make the total back up to 6.
    
    A player may choose to swap 1 or more of their tiles instead a placing tiles on the board.
    No points are awarded, and the game continues to the next player.
    
    The game ends when the bag is empty, and a player has no more tiles left.
    This player is awarded a finishing bonus : the total number of tiles
    owned by all other players.
    
    The winner is the player with the highest score.
    
    """.trimIndent()

private val regularQwirkle = GameVariation(
    "qwirkle",
    "Qwirkle",
    minPlayers = 2,
    maxPlayers = 6,

    grids = listOf(pieces),
    specialAreas = listOf(playArea, handArea),
    specialPoints = listOf(bagPoint),

    playingObjects = createTiles(),
    backgroundObjects = listOf(
        ImageObject(- 1, 400, 300, path = "backgrounds/rummyCross.jpg", draggable = false)
    ),
    foregroundObjects = listOf(
        PieceAtPointCounter(0, bagPoint.x + 30, bagPoint.y, bagPoint.name)
    ),

    avatarPositions = avatarPositions,
    commands = listOf(
        ShuffleCommand(bagPoint),
        DealCommand(bagPoint, handArea, 50),
        TakeCommand(bagPoint, handArea, 50)
    ),
    commandPrototypes = listOf(
        CommandPrototype("Deal", "deal", parameters = listOf("6"), isComplete = true),
        CommandPrototype("Take", "take"),
        CommandPrototype("Shuffle", "shuffle", isComplete = true)
    ),
    rules = rules
)


val qwirkle = GameType(
    "qwirkle", "Qwirkle", "rummyCross.png",
    listOf(regularQwirkle)
)