289 lines
5.4 KiB
Text
289 lines
5.4 KiB
Text
|
|
#IFNDEF __lib_carddeck
|
|
#DEFINE __lib_carddeck 1
|
|
|
|
#INCLUDE "random.c65"
|
|
|
|
GOTO __skip_lib_carddeck
|
|
|
|
// Validation error codes
|
|
BYTE CONST VALIDATE_OK = 0
|
|
BYTE CONST VALIDATE_DUPLICATE = 1
|
|
BYTE CONST VALIDATE_MISSING = 2
|
|
BYTE CONST VALIDATE_INVALID = 3
|
|
|
|
// Temporary array to track seen cards (52 bytes)
|
|
LABEL validate_seen
|
|
ASM
|
|
!fill 52, 0
|
|
ENDASM
|
|
|
|
// Initialize stock with all 52 cards (face down)
|
|
// Cards stored as $80-$B3 (card value OR'd with CARD_FACEDOWN)
|
|
FUNC stock_init
|
|
WORD ptr @ $fa
|
|
POINTER ptr -> pile_stock
|
|
BYTE card
|
|
|
|
// Set count to 52
|
|
POKE ptr[0] , 52
|
|
|
|
// Fill with cards 0-51, all face down ($80 = CARD_FACEDOWN)
|
|
ptr++
|
|
FOR card = $80 TO $80+51
|
|
POKE ptr , card
|
|
ptr++
|
|
NEXT
|
|
FEND
|
|
|
|
// Shuffle stock pile using Fisher-Yates algorithm
|
|
FUNC stock_shuffle
|
|
WORD ptr @ $fa
|
|
POINTER ptr -> pile_stock
|
|
BYTE i
|
|
BYTE j
|
|
BYTE temp_a
|
|
BYTE temp_b
|
|
|
|
// Fisher-Yates: swap each card with a random card from remaining deck
|
|
i = 52
|
|
WHILE i >= 2
|
|
rand_max(i, j)
|
|
j++
|
|
// Swap cards at positions i and j (1-indexed in pile)
|
|
IF i <> j
|
|
temp_a = PEEK ptr[i]
|
|
temp_b = PEEK ptr[j]
|
|
POKE ptr[i] , temp_b
|
|
POKE ptr[j] , temp_a
|
|
ENDIF
|
|
i--
|
|
WEND
|
|
FEND
|
|
|
|
// Deal cards from stock to a single tableau pile
|
|
// num_cards: how many cards to deal
|
|
// Top card is flipped face up
|
|
FUNC deal_to_tableau({WORD tab_ptr @ $fc} {BYTE num_cards})
|
|
WORD stock_ptr @ $fa
|
|
POINTER stock_ptr -> pile_stock
|
|
BYTE stock_count
|
|
BYTE card
|
|
BYTE i
|
|
|
|
// Set tableau count
|
|
POKE tab_ptr[0] , num_cards
|
|
|
|
// Deal cards from stock to tableau
|
|
stock_count = PEEK stock_ptr[0]
|
|
FOR i = 1 TO num_cards
|
|
card = PEEK stock_ptr[stock_count]
|
|
POKE tab_ptr[i] , card
|
|
stock_count--
|
|
NEXT
|
|
|
|
// Update stock count
|
|
POKE stock_ptr[0] , stock_count
|
|
|
|
// Flip top card face up (clear CARD_FACEDOWN bit)
|
|
card = PEEK tab_ptr[num_cards]
|
|
card = card & CARD_MASK
|
|
POKE tab_ptr[num_cards] , card
|
|
FEND
|
|
|
|
// Deal cards to all 7 tableau piles (Klondike layout)
|
|
// Tab0=1, Tab1=2, Tab2=3, Tab3=4, Tab4=5, Tab5=6, Tab6=7 cards
|
|
// Top card of each tableau is face up
|
|
FUNC deal_tableaus
|
|
WORD ptr @ $fc
|
|
|
|
POINTER ptr -> pile_tab0
|
|
deal_to_tableau(ptr, 1)
|
|
|
|
POINTER ptr -> pile_tab1
|
|
deal_to_tableau(ptr, 2)
|
|
|
|
POINTER ptr -> pile_tab2
|
|
deal_to_tableau(ptr, 3)
|
|
|
|
POINTER ptr -> pile_tab3
|
|
deal_to_tableau(ptr, 4)
|
|
|
|
POINTER ptr -> pile_tab4
|
|
deal_to_tableau(ptr, 5)
|
|
|
|
POINTER ptr -> pile_tab5
|
|
deal_to_tableau(ptr, 6)
|
|
|
|
POINTER ptr -> pile_tab6
|
|
deal_to_tableau(ptr, 7)
|
|
FEND
|
|
|
|
// Clear the seen array
|
|
FUNC validate_clear_seen
|
|
WORD ptr @ $fa
|
|
POINTER ptr -> validate_seen
|
|
BYTE i
|
|
FOR i = 0 TO 51
|
|
POKE ptr[i] , 0
|
|
NEXT
|
|
FEND
|
|
|
|
// Check cards in a pile, mark as seen
|
|
// Returns 0 if OK, 1 if duplicate found
|
|
FUNC validate_pile({WORD pile_ptr @ $fa} out:{BYTE result})
|
|
WORD seen_ptr @ $fc
|
|
POINTER seen_ptr -> validate_seen
|
|
|
|
BYTE count
|
|
BYTE i
|
|
BYTE card
|
|
BYTE card_val
|
|
BYTE already_seen
|
|
|
|
result = VALIDATE_OK
|
|
count = PEEK pile_ptr[0]
|
|
|
|
FOR i = 1 TO count
|
|
card = PEEK pile_ptr[i]
|
|
card_val = card & CARD_MASK
|
|
|
|
// Check if valid card (0-51)
|
|
IF card_val >= 52
|
|
result = VALIDATE_INVALID
|
|
EXIT
|
|
ENDIF
|
|
|
|
already_seen = PEEK seen_ptr[card_val]
|
|
IF already_seen
|
|
result = VALIDATE_DUPLICATE
|
|
EXIT
|
|
ENDIF
|
|
POKE seen_ptr[card_val] , 1
|
|
NEXT
|
|
FEND
|
|
|
|
// Validate entire deck across all piles
|
|
// Returns: 0=OK, 1=duplicate, 2=missing
|
|
FUNC validate_deck(out:{BYTE result})
|
|
WORD ptr @ $fa
|
|
WORD seen_ptr @ $fc
|
|
BYTE pile_result
|
|
BYTE i
|
|
BYTE seen
|
|
|
|
// Clear seen array
|
|
validate_clear_seen()
|
|
|
|
result = VALIDATE_OK
|
|
|
|
// Check stock
|
|
POINTER ptr -> pile_stock
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Check waste
|
|
POINTER ptr -> pile_waste
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Check tableau piles
|
|
POINTER ptr -> pile_tab0
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab1
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab2
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab3
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab4
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab5
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_tab6
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Check foundation piles
|
|
POINTER ptr -> pile_found0
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_found1
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_found2
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
POINTER ptr -> pile_found3
|
|
validate_pile(ptr, pile_result)
|
|
IF pile_result
|
|
result = pile_result
|
|
EXIT
|
|
ENDIF
|
|
|
|
// Now check all 52 cards were seen
|
|
POINTER seen_ptr -> validate_seen
|
|
FOR i = 0 TO 51
|
|
seen = PEEK seen_ptr[i]
|
|
IF seen == 0
|
|
result = VALIDATE_MISSING
|
|
EXIT
|
|
ENDIF
|
|
NEXT
|
|
|
|
FEND
|
|
|
|
LABEL __skip_lib_carddeck
|
|
|
|
#IFEND
|