#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 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 @ $86 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 @ $a2} out:{BYTE result}) WORD seen_ptr @ $b2 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 @ $98 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