Skip to content

Instantly share code, notes, and snippets.

@y2bd
Last active May 6, 2019 00:56
Show Gist options
  • Save y2bd/97fa9e8975c78f69ed9920dcf05593f8 to your computer and use it in GitHub Desktop.
Save y2bd/97fa9e8975c78f69ed9920dcf05593f8 to your computer and use it in GitHub Desktop.
SCRIPT-8
// board specs
const BOARD_WIDTH = 10
const BOARD_HEIGHT = 24
const BOARD_X = 0
const BOARD_Y = 0
// board states
const EMPTY = 0
const FULL = 1
// blok specs
const BLOK_TYPES = 7
const BLOK_SIZE = 4
// game states
const CHOOSE = 0
const CHOSEN = 1
const FALL = 2
const GROUND = 3
const CLEAR = 4
// FALL sub-state
const FALL_GRAV = 0
const FALL_DROP = 1
// DAS sub-states
const DAS_CHARGE = 300
const DAS_NONE = 0
const DAS_LEFT = 1
const DAS_RIGHT = 2
// game speed (ms)
const TURN_LENGTH = 200
const GROUND_LIMIT = 500
// bloks
const bloks = [
// I
[[0,0,0,0],
[1,1,1,1],
[0,0,0,0],
[0,0,0,0]],
// T
[[0,1,0],
[1,1,1],
[0,0,0]],
// L
[[0,0,1],
[1,1,1],
[0,0,0]],
// J
[[1,0,0],
[1,1,1],
[0,0,0]],
// S
[[0,1,1],
[1,1,0],
[0,0,0]],
// Z
[[1,1,0],
[0,1,1],
[0,0,0]],
// 0
[[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0]]
]
const initialBoard = () => {
const board = []
range(BOARD_HEIGHT).forEach(i => {
const row = []
range(BOARD_WIDTH).forEach(j => row.push(EMPTY))
board.push(row)
})
return board
}
const drawBoard = board => {
range(BOARD_WIDTH).forEach(x => {
range(BOARD_HEIGHT).forEach(y => {
const square = board[y][x]
if (square === EMPTY) {
rectFill(
BOARD_X + BLOK_SIZE * x,
BOARD_Y + BLOK_SIZE * y,
BLOK_SIZE,
BLOK_SIZE,
4
)
} else {
rectFill(
BOARD_X + BLOK_SIZE * x,
BOARD_Y + BLOK_SIZE * y,
BLOK_SIZE,
BLOK_SIZE
)
}
})
})
}
const chooseBlok = () => {
const blokChoice = Math.floor(Math.random() * BLOK_TYPES)
return bloks[blokChoice]
}
const cloneMatrix = matrix => {
return matrix.map(row => [...row])
}
const insertIntoMatrix = (base, piece, lx, ly) => {
const baseWidth = base[0].length
const baseHeight = base.length
const pieceWidth = piece[0].length
const pieceHeight = piece.length
const result = cloneMatrix(base)
range(lx, lx + pieceWidth).forEach(x => {
range(ly, ly + pieceHeight).forEach(y => {
if (x < 0 || x >= baseWidth || y < 0 || y >= baseHeight) {
return
}
const square = piece[y - ly][x - lx]
if (square === EMPTY) {
return
}
result[y][x] = piece[y - ly][x - lx]
})
})
return result
}
const invalidInsert = (base, piece, lx, ly) => {
const baseWidth = base[0].length
const baseHeight = base.length
const pieceWidth = piece[0].length
const pieceHeight = piece.length
let invalid = false
range(lx, lx + pieceWidth).forEach(x => {
if (invalid === true) {
return
}
range(ly, ly + pieceHeight).forEach(y => {
if (invalid === true) {
return
}
const psquare = piece[y - ly][x - lx]
if (x < 0 || x >= baseWidth || y < 0 || y >= baseHeight) {
// basically, we can actually extend beyond the board if it's an empty space on the inserted
// but if we want to insert a solid piece beyond the board, then it's bad
if (psquare !== EMPTY) {
invalid = true
}
return
}
const bsquare = base[y][x]
if (bsquare !== EMPTY && psquare !== EMPTY) {
invalid = true
}
})
})
return invalid
}
const rotateMatrix = (piece, clockwise) => {
const width = piece[0].length
const height = piece.length
const result = cloneMatrix(piece)
range(width).forEach(x => {
range(height).forEach(y => {
const square = piece[y][x];
if (clockwise) {
result[x][height-y+1] = square;
} else {
result[width-x+1][y] = square;
}
})
})
return result
}
const handleHorizontals = ({
input,
elapsed,
nextDasMode,
nextDasCharge,
nextBlokX
}) => {
// first handle inputs
// don't let new inputs override old ones
if (input.left && !(input.right && nextDasMode === DAS_RIGHT)) {
if (nextDasMode === DAS_LEFT) {
nextDasCharge += elapsed
if (nextDasCharge > DAS_CHARGE) {
nextBlokX -= 1
}
} else {
nextBlokX -= 1
nextDasMode = DAS_LEFT
nextDasCharge = 0
}
} else if (input.right && !(input.left && nextDasMode === DAS_LEFT)) {
if (nextDasMode === DAS_RIGHT) {
nextDasCharge += elapsed
if (nextDasCharge > DAS_CHARGE) {
nextBlokX += 1
}
} else {
nextBlokX += 1
nextDasMode = DAS_RIGHT
nextDasCharge = 0
}
} else if (!input.left && !input.right) {
nextDasMode = DAS_NONE
nextDasCharge = 0
}
return { nextDasMode, nextDasCharge, nextBlokX }
}
init = state => {
state.board = initialBoard()
state.gameState = CHOOSE
state.fallState = FALL_GRAV
state.turnElapsed = 0
state.currentBlok = undefined
state.blokX = 4
state.blokY = 0
state.dasCharge = 0
state.dasMode = DAS_NONE
state.groundTime = 0
}
update = (state, input, elapsed) => {
let nextGameState = state.gameState
let nextBlokX = state.blokX
let nextBlokY = state.blokY
let nextBoard = state.board
let nextBlok = state.currentBlok
let nextDasCharge = state.dasCharge
let nextDasMode = state.dasMode
let nextGroundTime = state.groundTime
state.turnElapsed += elapsed
let endOfTurn = false
if (state.turnElapsed >= TURN_LENGTH) {
state.turnElapsed = 0
endOfTurn = true
}
if (state.gameState === CHOOSE) {
nextBlok = chooseBlok()
nextBlokX = 4
nextBlokY = 0
nextGameState = CHOSEN
} else if (state.gameState === CHOSEN) {
//if (endOfTurn) {
nextGameState = FALL
//}
} else if (state.gameState === FALL) {
const nextH = handleHorizontals({
input,
elapsed,
nextDasMode,
nextDasCharge,
nextBlokX
})
nextDasMode = nextH.nextDasMode
nextDasCharge = nextH.nextDasCharge
nextBlokX = nextH.nextBlokX
// don't let us slide off the board
if (invalidInsert(state.board, nextBlok, nextBlokX, nextBlokY)) {
nextBlokX = state.blokX
}
// spins are pretty hard
if (input.aPressed) {
console.log("yay")
nextBlok = rotateMatrix(nextBlok, false)
}
// then handle falling
if (state.fallState === FALL_GRAV && endOfTurn) {
nextBlokY += 1
}
// check if we're gonna fall too far
if (
invalidInsert(state.board, nextBlok, nextBlokX, nextBlokY + 1)
) {
// TODO go to ground mode for ground spins
nextGameState = GROUND
nextGroundTime = 0
}
} else if (state.gameState === GROUND) {
if (nextGroundTime >= GROUND_LIMIT) {
nextGameState = CHOOSE
nextBoard = insertIntoMatrix(
nextBoard,
nextBlok,
nextBlokX,
nextBlokY
)
} else {
const nextH = handleHorizontals({
input,
elapsed,
nextDasMode,
nextDasCharge,
nextBlokX
})
nextDasMode = nextH.nextDasMode
nextDasCharge = nextH.nextDasCharge
nextBlokX = nextH.nextBlokX
// don't let us slide off the board
if (invalidInsert(state.board, nextBlok, nextBlokX, nextBlokY)) {
nextBlokX = state.blokX
}
if (nextBlokX === state.blokX) {
nextGroundTime += elapsed
} else {
nextGroundTime = 0
}
// check if we can start falling again
if (
!invalidInsert(state.board, nextBlok, nextBlokX, nextBlokY + 1)
) {
// TODO go to ground mode for ground spins
nextGameState = FALL
}
}
}
if (nextGameState !== state.gameState) {
state.turnElapsed = 0
state.gameState = nextGameState
}
state.blokX = nextBlokX
state.blokY = nextBlokY
state.board = nextBoard
state.currentBlok = nextBlok
state.dasCharge = nextDasCharge
state.dasMode = nextDasMode
state.groundTime = nextGroundTime
}
draw = state => {
clear()
const {
board,
currentBlok,
blokX,
blokY
} = state
const currentBoard = insertIntoMatrix(board, currentBlok, blokX, blokY)
drawBoard(currentBoard)
}
{
"iframeVersion": "0.1.254",
"lines": [
74,
41,
87,
0,
0,
0,
41,
154
]
}
{
"0": [
" 0 ",
" ",
" 1 ",
" 1 0",
"0 1 ",
" 1 ",
" ",
" 0 "
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment