binmat
Version:
binmat simulator
170 lines (169 loc) • 6.19 kB
JavaScript
import { shuffle } from "@samual/lib/shuffle"
import { Role, CardModifier, StatusCode } from "./shared.js"
const PowersOfTwo = [2, 4, 8, 16, 32, 64, 128, 256]
function doCombat(state, lane) {
const roleTurn = (state.turn % 2) + 1,
laneDeck = state.laneDecks[lane],
laneDiscardPile = state.laneDiscardPiles[lane],
defenderStack = state.defenderStacks[lane].cards,
attackerStack = state.attackerStacks[lane],
defenderStackWasFaceUp = state.defenderStacks[lane].isFaceUp,
defenderStackBeforeCombat = [...defenderStack],
attackerStackBeforeCombat = [...attackerStack],
attackerCardsTrapped = [],
defenderCardsTrapped = []
roleTurn == Role.Defender ? (flipDefenderStack(), flipAttackerStack()) : (flipAttackerStack(), flipDefenderStack())
let cardsDrawnToDiscard,
defenderSum = 0,
defenderWildCards = 0,
breakPresent = !1
const defenderBounceIndexes = []
for (const [index, card] of defenderStack.entries())
switch (card[0]) {
case CardModifier.Trap:
break
case CardModifier.Wild:
defenderWildCards++
break
case CardModifier.Bounce:
defenderBounceIndexes.push(index)
break
case CardModifier.Break:
breakPresent = !0
break
case "a":
defenderSum += 10
break
default:
defenderSum += Number(card[0])
}
const attackerBounceIndexes = []
let attackerSum = 0,
attackerWildCards = 0
for (const [index, card] of attackerStack.entries())
switch (card[0]) {
case CardModifier.Trap:
break
case CardModifier.Wild:
attackerWildCards++
break
case CardModifier.Bounce:
attackerBounceIndexes.push(index)
break
case CardModifier.Break:
breakPresent = !0
break
case "a":
attackerSum += 10
break
default:
attackerSum += Number(card[0])
}
let attackerAttackPower = 0
if (attackerWildCards) {
for (; attackerSum >= PowersOfTwo[attackerAttackPower]; ) attackerAttackPower++
attackerAttackPower += attackerWildCards
} else attackerAttackPower = PowersOfTwo.indexOf(attackerSum) + 1
let cardsDrawn,
defenderAttackPower = 0
if (defenderWildCards) {
for (; defenderSum >= PowersOfTwo[defenderAttackPower]; ) defenderAttackPower++
defenderAttackPower += defenderWildCards
} else defenderAttackPower = PowersOfTwo.indexOf(defenderSum) + 1
let attackerStackDiscarded,
damageValue = 0
const defenderBouncesDiscarded = [],
attackerBouncesDiscarded = []
if (
attackerBounceIndexes.length ||
defenderBounceIndexes.length ||
(!attackerAttackPower && !defenderAttackPower)
) {
for (const index of defenderBounceIndexes.reverse()) {
const bounceDiscarded = defenderStack.splice(index, 1)[0]
defenderBouncesDiscarded.push(bounceDiscarded), state.attackerDiscardPile.push(bounceDiscarded)
}
for (const index of attackerBounceIndexes.reverse()) {
const bounceDiscarded = attackerStack.splice(index, 1)[0]
attackerBouncesDiscarded.push(bounceDiscarded), laneDiscardPile.push(bounceDiscarded)
}
;(attackerStackDiscarded = [...attackerStack]), (cardsDrawnToDiscard = []), (cardsDrawn = [])
} else if (defenderAttackPower > attackerAttackPower)
(attackerStackDiscarded = [...attackerStack]),
laneDiscardPile.push(...attackerStack.splice(0)),
(cardsDrawnToDiscard = []),
(cardsDrawn = [])
else if (
((attackerStackDiscarded = [...attackerStack]),
(damageValue =
breakPresent ?
Math.max(attackerAttackPower, defenderStack.length)
: attackerAttackPower - defenderAttackPower + 1),
damageValue > defenderStack.length)
) {
const cardsToDraw = damageValue - defenderStack.length
if (cardsToDraw > laneDeck.length + laneDiscardPile.length)
return {
status: StatusCode.AttackerWin,
attackerStack: attackerStackBeforeCombat,
defenderStack: defenderStackBeforeCombat,
attackerAttackPower: attackerAttackPower,
defenderAttackPower: defenderAttackPower,
damageValue: damageValue,
cardsDrawn: [...laneDeck, ...laneDiscardPile],
attackerCardsTrapped: attackerCardsTrapped,
defenderCardsTrapped: defenderCardsTrapped,
attackerBouncesDiscarded: attackerBouncesDiscarded,
defenderBouncesDiscarded: defenderBouncesDiscarded,
attackerStackDiscarded: attackerStackDiscarded,
defenderStackWasFaceUp: defenderStackWasFaceUp,
cardsDrawnToDiscard: [...defenderStack].reverse()
}
;(cardsDrawnToDiscard = defenderStack.splice(0).reverse()),
state.attackerDiscardPile.push(...cardsDrawnToDiscard),
cardsToDraw > laneDeck.length && laneDeck.push(...shuffle(laneDiscardPile.splice(0))),
(cardsDrawn = laneDeck.splice(-cardsToDraw)),
state.attackerHand.push(...cardsDrawn)
} else
(cardsDrawnToDiscard = defenderStack.splice(-damageValue).reverse()),
state.attackerDiscardPile.push(...cardsDrawnToDiscard),
(cardsDrawn = [])
return (
state.attackerDiscardPile.push(...attackerStack.splice(0)),
(state.defenderStacks[lane].isFaceUp = Boolean(defenderStack.length)),
{
status: StatusCode.Ok,
attackerStack: attackerStackBeforeCombat,
defenderStack: defenderStackBeforeCombat,
attackerAttackPower: attackerAttackPower,
defenderAttackPower: defenderAttackPower,
damageValue: damageValue,
cardsDrawn: cardsDrawn,
attackerBouncesDiscarded: attackerBouncesDiscarded,
attackerCardsTrapped: attackerCardsTrapped,
attackerStackDiscarded: attackerStackDiscarded,
defenderBouncesDiscarded: defenderBouncesDiscarded,
defenderCardsTrapped: defenderCardsTrapped,
defenderStackWasFaceUp: defenderStackWasFaceUp,
cardsDrawnToDiscard: cardsDrawnToDiscard
}
)
function flipDefenderStack() {
if (!state.defenderStacks[lane].isFaceUp)
for (const card of defenderStack) {
if (!attackerStack.length) break
if (card[0] != CardModifier.Trap) continue
const trappedCard = attackerStack.pop()
attackerCardsTrapped.push(trappedCard), laneDiscardPile.push(trappedCard)
}
}
function flipAttackerStack() {
for (const card of attackerStack) {
if (!defenderStack.length) break
if (card[0] != CardModifier.Trap) continue
const trappedCard = defenderStack.pop()
defenderCardsTrapped.push(trappedCard), state.attackerDiscardPile.push(trappedCard)
}
}
}
export { PowersOfTwo, doCombat }