solitaire-c64/cardtests.c65

878 lines
20 KiB
Text

#IFNDEF __lib_cardtests
#DEFINE __lib_cardtests 1
#INCLUDE "cardrender.c65"
#INCLUDE "piles.c65"
#INCLUDE "carddeck.c65"
#INCLUDE "cardmoves.c65"
GOTO __skip_lib_cardtests
FUNC show_charset
WORD i
BYTE b
b = 0
FOR i = $0400 TO $0400+999
POKE i , b
b++
NEXT
FEND
// Demo: fill $c000-$c1ff with 512 random bytes
FUNC rand_demo
WORD ptr @ $fa
WORD count
BYTE r
ptr = $c000
FOR count = 0 TO 511
//rand(r)
rand_max(52, r)
POKE ptr , r
ptr++
NEXT
FEND
FUNC render_all_cards_test
// Test render_card - render all cards by ID
BYTE i
WORD wi
wi = 0
FOR i = 0 TO 12
render_card($0404, wi, i)
wi = wi + 2
NEXT
wi = 0
FOR i = 0+13 TO 12+13
render_card(7*40+$0404, wi, i)
wi = wi + 2
NEXT
wi = 0
FOR i = 13*2+0 TO 13*2+12
render_card(2*7*40+$0404, wi, i)
wi = wi + 2
NEXT
wi = 0
FOR i = 13*3+0 TO 13*3+12
render_card(3*7*40+$0404, wi, i)
wi = wi + 2
NEXT
FEND
// Test face-down stack rendering (1-6 cards)
FUNC render_facedown_test
BYTE rows
// Column 0: 1 face-down
render_facedown_stack($0400, 0, 1, rows)
// Column 1: 2 face-down
render_facedown_stack($0400, 6, 2, rows)
// Column 2: 3 face-down
render_facedown_stack($0400, 12, 3, rows)
// Column 3: 4 face-down
render_facedown_stack($0400, 18, 4, rows)
// Column 4: 5 face-down
render_facedown_stack($0400, 24, 0, rows)
// Column 5: 6 face-down
render_facedown_stack($0400, 30, 51, rows)
FEND
// Test stacked face-up cards
FUNC render_faceup_stack_test
BYTE rows
BYTE i
WORD pos
// Column 0: 1 face-down, 1 face-up (full card)
pos = 0
render_facedown_stack($0400, pos, 1, rows)
FOR i = 1 TO rows
pos = pos + 40
NEXT
render_card_body_full($0400, pos, 0) // Ace of Hearts
// Column 1: 2 face-down, 2 face-up
pos = 6
render_facedown_stack($0400, pos, 2, rows)
FOR i = 1 TO rows
pos = pos + 40
NEXT
render_card_body_partial($0400, pos, 13) // Ace of Diamonds
pos = pos + 40
render_connecting_border($0400, pos)
pos = pos + 40
render_card_body_full($0400, pos, 26) // Ace of Spades
// Column 2: 1 face-down, 3 face-up
pos = 12
render_facedown_stack($0400, pos, 1, rows)
FOR i = 1 TO rows
pos = pos + 40
NEXT
render_card_body_partial($0400, pos, 1) // 2 of Hearts
pos = pos + 40
render_connecting_border($0400, pos)
pos = pos + 40
render_card_body_partial($0400, pos, 14) // 2 of Diamonds
pos = pos + 40
render_connecting_border($0400, pos)
pos = pos + 40
render_card_body_full($0400, pos, 27) // 2 of Spades
// Column 3: 0 face-down, 2 face-up (no face-down cards)
pos = 18
render_facedown_stack($0400, pos, 0, rows)
FOR i = 1 TO rows
pos = pos + 40
NEXT
render_card_body_partial($0400, pos, 39) // Ace of Clubs
pos = pos + 40
render_connecting_border($0400, pos)
pos = pos + 40
render_card_body_full($0400, pos, 40) // 2 of Clubs
// Column 4: 3 face-down, 1 face-up
pos = 24
render_facedown_stack($0400, pos, 3, rows)
FOR i = 1 TO rows
pos = pos + 40
NEXT
render_card_body_full($0400, pos, 12) // King of Hearts
// Column 5: Standalone card (foundation style)
render_card($0400, 30, 51) // King of Clubs
FEND
// Test rendering actual dealt tableau piles
FUNC render_tableaus_test
WORD ptr @ $f8
// Render all 7 tableau piles
// Each pile is 6 chars wide (5 card + 1 space)
POINTER ptr -> pile_tab0
render_tableau_pile($0400, 0, ptr)
POINTER ptr -> pile_tab1
render_tableau_pile($0400, 5, ptr)
POINTER ptr -> pile_tab2
render_tableau_pile($0400, 10, ptr)
POINTER ptr -> pile_tab3
render_tableau_pile($0400, 15, ptr)
POINTER ptr -> pile_tab4
render_tableau_pile($0400, 20, ptr)
POINTER ptr -> pile_tab5
render_tableau_pile($0400, 25, ptr)
POINTER ptr -> pile_tab6
render_tableau_pile($0400, 30, ptr)
FEND
// Setup mid-game tableau piles for demo (Klondike rules)
// Card IDs: Hearts 0-12 (red), Diamonds 13-25 (red), Spades 26-38 (black), Clubs 39-51 (black)
// Rank: A=0, 2=1, 3=2, 4=3, 5=4, 6=5, 7=6, 8=7, 9=8, 10=9, J=10, Q=11, K=12
// Klondike: alternating colors, descending rank
FUNC setup_midgame_piles
WORD ptr @ $f8
// Tab0: K♥(red) → Q♠(black) → J♦(red) → 10♣(black)
POINTER ptr -> pile_tab0
POKE ptr[0] , 4
POKE ptr[1] , 12 // King of Hearts (red)
POKE ptr[2] , 37 // Queen of Spades (black)
POKE ptr[3] , 23 // Jack of Diamonds (red)
POKE ptr[4] , 48 // 10 of Clubs (black)
// Tab1: 1 face-down, Q♣(black) → J♥(red) → 10♠(black)
POINTER ptr -> pile_tab1
POKE ptr[0] , 4
POKE ptr[1] , 0|CARD_FACEDOWN
POKE ptr[2] , 50 // Queen of Clubs (black)
POKE ptr[3] , 10 // Jack of Hearts (red)
POKE ptr[4] , 35 // 10 of Spades (black)
// Tab2: 2 face-down, 7♦(red)
POINTER ptr -> pile_tab2
POKE ptr[0] , 3
POKE ptr[1] , 1|CARD_FACEDOWN
POKE ptr[2] , 2|CARD_FACEDOWN
POKE ptr[3] , 19 // 7 of Diamonds (red)
// Tab3: K♠(black) → Q♥(red) → J♣(black) → 10♦(red) → 9♠(black)
POINTER ptr -> pile_tab3
POKE ptr[0] , 5
POKE ptr[1] , 38 // King of Spades (black)
POKE ptr[2] , 11 // Queen of Hearts (red)
POKE ptr[3] , 49 // Jack of Clubs (black)
POKE ptr[4] , 22 // 10 of Diamonds (red)
POKE ptr[5] , 34 // 9 of Spades (black)
// Tab4: 3 face-down, K♦(red) → Q♣(black)
POINTER ptr -> pile_tab4
POKE ptr[0] , 5
POKE ptr[1] , 3|CARD_FACEDOWN
POKE ptr[2] , 4|CARD_FACEDOWN
POKE ptr[3] , 5|CARD_FACEDOWN
POKE ptr[4] , 25 // King of Diamonds (red)
POKE ptr[5] , 50 // Queen of Clubs (black)
// Tab5: 4 face-down, 5♥(red)
POINTER ptr -> pile_tab5
POKE ptr[0] , 5
POKE ptr[1] , 6|CARD_FACEDOWN
POKE ptr[2] , 7|CARD_FACEDOWN
POKE ptr[3] , 8|CARD_FACEDOWN
POKE ptr[4] , 9|CARD_FACEDOWN
POKE ptr[5] , 4 // 5 of Hearts (red)
// Tab6: 5 face-down, 8♣(black) → 7♥(red)
POINTER ptr -> pile_tab6
POKE ptr[0] , 7
POKE ptr[1] , 10|CARD_FACEDOWN
POKE ptr[2] , 11|CARD_FACEDOWN
POKE ptr[3] , 12|CARD_FACEDOWN
POKE ptr[4] , 13|CARD_FACEDOWN
POKE ptr[5] , 14|CARD_FACEDOWN
POKE ptr[6] , 46 // 8 of Clubs (black)
POKE ptr[7] , 6 // 7 of Hearts (red)
FEND
// Test mid-game tableau rendering
FUNC render_midgame_test
setup_midgame_piles()
render_tableaus_test()
FEND
// Setup foundation piles in different states for testing
FUNC setup_foundation_test_piles
WORD ptr @ $f8
// Foundation 0: empty (Hearts)
POINTER ptr -> pile_found0
POKE ptr[0] , 0
// Foundation 1: Ace only (Diamonds)
POINTER ptr -> pile_found1
POKE ptr[0] , 1
POKE ptr[1] , 13 // A♦
// Foundation 2: A-2-3 (Spades)
POINTER ptr -> pile_found2
POKE ptr[0] , 3
POKE ptr[1] , 26 // A♠
POKE ptr[2] , 27 // 2♠
POKE ptr[3] , 28 // 3♠
// Foundation 3: full A-K (Clubs)
POINTER ptr -> pile_found3
POKE ptr[0] , 13
BYTE i
BYTE card
card = 39
ptr++
FOR i = 0 TO 12
POKE ptr , card
ptr++
card++
NEXT
FEND
// Test foundation pile rendering
FUNC render_foundation_test
WORD ptr @ $f8
setup_foundation_test_piles()
// Render 4 foundations side by side
POINTER ptr -> pile_found0
render_foundation_pile($0400, 0, ptr)
POINTER ptr -> pile_found1
render_foundation_pile($0400, 6, ptr)
POINTER ptr -> pile_found2
render_foundation_pile($0400, 12, ptr)
POINTER ptr -> pile_found3
render_foundation_pile($0400, 18, ptr)
FEND
// Test waste pile rendering with different card counts
FUNC render_waste_test
WORD ptr @ $f8 // Use $f8 to avoid conflict with $fa used by sub-functions
// Test 0 cards
POINTER ptr -> pile_waste
POKE ptr[0] , 0
render_waste_pile($0400, 0, ptr, 3)
// Test 1 card
POKE ptr[0] , 1
POKE ptr[1] , 0 // A♥
render_waste_pile($0400, 10, ptr, 3)
// Test 2 cards
POKE ptr[0] , 2
POKE ptr[1] , 13 // A♦
POKE ptr[2] , 26 // A♠
render_waste_pile($0400, 20, ptr, 3)
// Test 3 cards
POKE ptr[0] , 3
POKE ptr[1] , 39 // A♣
POKE ptr[2] , 1 // 2♥
POKE ptr[3] , 14 // 2♦
render_waste_pile($0400, 8*40, ptr, 3)
// Test 5 cards (should show only top 3)
POKE ptr[0] , 5
POKE ptr[1] , 10 // J♥
POKE ptr[2] , 11 // Q♥
POKE ptr[3] , 12 // K♥
POKE ptr[4] , 25 // K♦
POKE ptr[5] , 38 // K♠
render_waste_pile($0400, 8*40+15, ptr, 3)
FEND
// Test all pile renderers together - Klondike layout
FUNC render_all_piles_test
WORD ptr @ $f8
// Setup stock with some cards
POINTER ptr -> pile_stock
POKE ptr[0] , 10
// Setup waste with 3 cards
POINTER ptr -> pile_waste
POKE ptr[0] , 3
POKE ptr[1] , 5 // 6♥
POKE ptr[2] , 18 // 6♦
POKE ptr[3] , 31 // 6♠
// Setup foundations
POINTER ptr -> pile_found0
POKE ptr[0] , 0 // empty
POINTER ptr -> pile_found1
POKE ptr[0] , 1
POKE ptr[1] , 13 // A♦
POINTER ptr -> pile_found2
POKE ptr[0] , 2
POKE ptr[1] , 26 // A♠
POKE ptr[2] , 27 // 2♠
POINTER ptr -> pile_found3
POKE ptr[0] , 3
POKE ptr[1] , 39 // A♣
POKE ptr[2] , 40 // 2♣
POKE ptr[3] , 41 // 3♣
// Setup tableaus using midgame piles
setup_midgame_piles()
// Row 0: Stock, Waste, gap, 4 Foundations
// Stock at col 0
POINTER ptr -> pile_stock
render_stock_pile($0400, 0, ptr)
// Waste at col 6 (fanned takes 9 cols)
POINTER ptr -> pile_waste
render_waste_pile($0400, 6, ptr, 3)
// Foundations at cols 16, 21, 26, 31
POINTER ptr -> pile_found0
render_foundation_pile($0400, 16, ptr)
POINTER ptr -> pile_found1
render_foundation_pile($0400, 21, ptr)
POINTER ptr -> pile_found2
render_foundation_pile($0400, 26, ptr)
POINTER ptr -> pile_found3
render_foundation_pile($0400, 31, ptr)
// Row 8: 7 Tableaus
POINTER ptr -> pile_tab0
render_tableau_pile($0400, 8*40, ptr)
POINTER ptr -> pile_tab1
render_tableau_pile($0400, 8*40+5, ptr)
POINTER ptr -> pile_tab2
render_tableau_pile($0400, 8*40+10, ptr)
POINTER ptr -> pile_tab3
render_tableau_pile($0400, 8*40+15, ptr)
POINTER ptr -> pile_tab4
render_tableau_pile($0400, 8*40+20, ptr)
POINTER ptr -> pile_tab5
render_tableau_pile($0400, 8*40+25, ptr)
POINTER ptr -> pile_tab6
render_tableau_pile($0400, 8*40+30, ptr)
FEND
// ============================================================================
// Move Function Tests
// ============================================================================
// Clear all piles to known empty state
FUNC clear_all_piles
WORD ptr @ $f8
POINTER ptr -> pile_stock
POKE ptr[0] , 0
POINTER ptr -> pile_waste
POKE ptr[0] , 0
POINTER ptr -> pile_tab0
POKE ptr[0] , 0
POINTER ptr -> pile_tab1
POKE ptr[0] , 0
POINTER ptr -> pile_tab2
POKE ptr[0] , 0
POINTER ptr -> pile_tab3
POKE ptr[0] , 0
POINTER ptr -> pile_tab4
POKE ptr[0] , 0
POINTER ptr -> pile_tab5
POKE ptr[0] , 0
POINTER ptr -> pile_tab6
POKE ptr[0] , 0
POINTER ptr -> pile_found0
POKE ptr[0] , 0
POINTER ptr -> pile_found1
POKE ptr[0] , 0
POINTER ptr -> pile_found2
POKE ptr[0] , 0
POINTER ptr -> pile_found3
POKE ptr[0] , 0
FEND
// Helper: Render stock and waste side by side for move tests
FUNC render_stock_waste_test
WORD ptr @ $f8
POINTER ptr -> pile_stock
render_stock_pile($0400, 0, ptr)
POINTER ptr -> pile_waste
render_waste_pile($0400, 6, ptr, 3)
FEND
// Test move_stock_to_waste with draw-1
FUNC test_stock_to_waste_draw1
WORD ptr @ $f8
BYTE success
clear_all_piles()
// Setup stock with 5 cards (face-down)
POINTER ptr -> pile_stock
POKE ptr[0] , 5
POKE ptr[1] , 0|CARD_FACEDOWN // A♥
POKE ptr[2] , 13|CARD_FACEDOWN // A♦
POKE ptr[3] , 26|CARD_FACEDOWN // A♠
POKE ptr[4] , 39|CARD_FACEDOWN // A♣
POKE ptr[5] , 12|CARD_FACEDOWN // K♥
// Render BEFORE
render_stock_waste_test()
wait_key()
// Draw 1 card three times
move_stock_to_waste(1, success) // K♥ to waste
move_stock_to_waste(1, success) // A♣ to waste
move_stock_to_waste(1, success) // A♠ to waste
// Render AFTER: stock should have 2, waste should have 3
fill_mem($0400, $0400+999, 0)
render_stock_waste_test()
FEND
// Test move_stock_to_waste with draw-3
FUNC test_stock_to_waste_draw3
WORD ptr @ $f8
BYTE success
clear_all_piles()
// Setup stock with 7 cards (face-down)
POINTER ptr -> pile_stock
POKE ptr[0] , 7
POKE ptr[1] , 0|CARD_FACEDOWN // A♥
POKE ptr[2] , 1|CARD_FACEDOWN // 2♥
POKE ptr[3] , 2|CARD_FACEDOWN // 3♥
POKE ptr[4] , 3|CARD_FACEDOWN // 4♥
POKE ptr[5] , 4|CARD_FACEDOWN // 5♥
POKE ptr[6] , 5|CARD_FACEDOWN // 6♥
POKE ptr[7] , 6|CARD_FACEDOWN // 7♥
// Draw 3 cards
move_stock_to_waste(3, success)
// Render result: stock should have 4, waste should have 3
render_stock_waste_test()
FEND
// Test move_reset_stock
FUNC test_reset_stock
WORD ptr @ $f8
BYTE success
clear_all_piles()
// Setup waste with 4 cards (face-up)
POINTER ptr -> pile_waste
POKE ptr[0] , 4
POKE ptr[1] , 0 // A♥
POKE ptr[2] , 13 // A♦
POKE ptr[3] , 26 // A♠
POKE ptr[4] , 39 // A♣
// Reset stock
move_reset_stock(success)
// Render result: stock should have 4 (face-down), waste empty
render_stock_waste_test()
FEND
// Test move_waste_to_tab - valid move
FUNC test_waste_to_tab_valid
WORD ptr @ $f8
WORD tab_ptr @ $f6
BYTE success
clear_all_piles()
// Setup waste with 8♥ (red, rank 7)
POINTER ptr -> pile_waste
POKE ptr[0] , 1
POKE ptr[1] , 7 // 8♥
// Setup tab0 with 9♠ (black, rank 8) - valid target for red 8
POINTER tab_ptr -> pile_tab0
POKE tab_ptr[0] , 1
POKE tab_ptr[1] , 34 // 9♠
// Render BEFORE
render_tableau_pile($0400, 0, tab_ptr)
render_waste_pile($0400, 10, ptr, 3)
wait_key()
// Move waste to tab
move_waste_to_tab(tab_ptr, success)
// Render AFTER
fill_mem($0400, $0400+999, 0)
POINTER tab_ptr -> pile_tab0
render_tableau_pile($0400, 0, tab_ptr)
POINTER ptr -> pile_waste
render_waste_pile($0400, 10, ptr, 3)
FEND
// Test move_waste_to_tab - King to empty tableau
FUNC test_waste_to_tab_king_empty
WORD ptr @ $f8
WORD tab_ptr @ $fc
BYTE success
clear_all_piles()
// Setup waste with K♠ (black, rank 12)
POINTER ptr -> pile_waste
POKE ptr[0] , 1
POKE ptr[1] , 38 // K♠
// Tab0 is empty
POINTER tab_ptr -> pile_tab0
// Move King to empty tableau
move_waste_to_tab(tab_ptr, success)
// Render tableau - should show K♠
render_tableau_pile($0400, 0, tab_ptr)
FEND
// Test move_waste_to_tab - invalid move (same color)
FUNC test_waste_to_tab_invalid
WORD ptr @ $f8
WORD tab_ptr @ $fc
BYTE success
clear_all_piles()
// Setup waste with 8♥ (red)
POINTER ptr -> pile_waste
POKE ptr[0] , 1
POKE ptr[1] , 7 // 8♥
// Setup tab0 with 9♦ (red) - invalid target (same color)
POINTER tab_ptr -> pile_tab0
POKE tab_ptr[0] , 1
POKE tab_ptr[1] , 21 // 9♦
// Try move - should fail
move_waste_to_tab(tab_ptr, success)
// Render - waste should still have card, tableau unchanged
render_tableau_pile($0400, 0, tab_ptr)
POINTER ptr -> pile_waste
render_waste_pile($0400, 10, ptr, 3)
FEND
// Test move_waste_to_found - build Ace to foundation
FUNC test_waste_to_found_ace
WORD ptr @ $f8
WORD found_ptr @ $fc
BYTE success
clear_all_piles()
// Setup waste with A♥
POINTER ptr -> pile_waste
POKE ptr[0] , 1
POKE ptr[1] , 0 // A♥
// Foundation 0 is empty
POINTER found_ptr -> pile_found0
// Move Ace to foundation
move_waste_to_found(found_ptr, success)
// Render foundation - should show A♥
render_foundation_pile($0400, 0, found_ptr)
FEND
// Test move_waste_to_found - build sequence
FUNC test_waste_to_found_sequence
WORD ptr @ $f8
WORD found_ptr @ $fc
BYTE success
clear_all_piles()
// Setup foundation with A♠, 2♠
POINTER found_ptr -> pile_found2
POKE found_ptr[0] , 2
POKE found_ptr[1] , 26 // A♠
POKE found_ptr[2] , 27 // 2♠
// Setup waste with 3♠
POINTER ptr -> pile_waste
POKE ptr[0] , 1
POKE ptr[1] , 28 // 3♠
// Move 3♠ to foundation
move_waste_to_found(found_ptr, success)
// Render foundation - should show 3♠
render_foundation_pile($0400, 0, found_ptr)
FEND
// Test move_tab_to_found
FUNC test_tab_to_found
WORD tab_ptr @ $f6
WORD found_ptr @ $f8
BYTE success
clear_all_piles()
// Setup tab0 with face-down card + A♦
POINTER tab_ptr -> pile_tab0
POKE tab_ptr[0] , 2
POKE tab_ptr[1] , 5|CARD_FACEDOWN // 6♥ face-down
POKE tab_ptr[2] , 13 // A♦ face-up
// Foundation 1 empty
POINTER found_ptr -> pile_found1
// Render BEFORE
render_foundation_pile($0400, 0, found_ptr)
render_tableau_pile($0400, 10, tab_ptr)
wait_key()
// Move A♦ to foundation
move_tab_to_found(tab_ptr, found_ptr, success)
// Render AFTER - foundation should have A♦, tableau should show flipped 6♥
fill_mem($0400, $0400+999, 0)
POINTER found_ptr -> pile_found1
POINTER tab_ptr -> pile_tab0
render_foundation_pile($0400, 0, found_ptr)
render_tableau_pile($0400, 10, tab_ptr)
FEND
// Test move_tab_to_tab - move single card
FUNC test_tab_to_tab_single
WORD src_ptr @ $f6
WORD dst_ptr @ $f8
BYTE success
clear_all_piles()
// Setup src with 8♦ (red)
POINTER src_ptr -> pile_tab0
POKE src_ptr[0] , 1
POKE src_ptr[1] , 20 // 8♦
// Setup dst with 9♠ (black)
POINTER dst_ptr -> pile_tab1
POKE dst_ptr[0] , 1
POKE dst_ptr[1] , 34 // 9♠
// Move 1 card from tab0 to tab1
move_tab_to_tab(src_ptr, dst_ptr, 1, success)
// Render both tableaus
render_tableau_pile($0400, 0, src_ptr)
render_tableau_pile($0400, 10, dst_ptr)
FEND
// Test move_tab_to_tab - move stack of 3 cards
FUNC test_tab_to_tab_stack
WORD src_ptr @ $f6
WORD dst_ptr @ $f8
BYTE success
clear_all_piles()
// Setup src with: face-down, Q♠(black), J♦(red), 10♣(black)
POINTER src_ptr -> pile_tab0
POKE src_ptr[0] , 4
POKE src_ptr[1] , 0|CARD_FACEDOWN // hidden card
POKE src_ptr[2] , 37 // Q♠ (black)
POKE src_ptr[3] , 23 // J♦ (red)
POKE src_ptr[4] , 48 // 10♣ (black)
// Setup dst with K♥ (red) - valid for Q♠
POINTER dst_ptr -> pile_tab1
POKE dst_ptr[0] , 1
POKE dst_ptr[1] , 12 // K♥
// Render BEFORE state
render_tableau_pile($0400, 0, src_ptr)
render_tableau_pile($0400, 10, dst_ptr)
// Wait for keypress
wait_key()
// Move 3 cards (Q♠, J♦, 10♣) from tab0 to tab1
move_tab_to_tab(src_ptr, dst_ptr, 3, success)
// Clear screen before redraw
fill_mem($0400, $0400+999, 0)
// Render AFTER state - src should show flipped card, dst should have 4 cards
render_tableau_pile($0400, 0, src_ptr)
render_tableau_pile($0400, 10, dst_ptr)
FEND
// Test move_tab_to_tab - King to empty tableau
FUNC test_tab_to_tab_king_empty
WORD src_ptr @ $f6
WORD dst_ptr @ $f8
BYTE success
clear_all_piles()
// Setup src with K♣ (black)
POINTER src_ptr -> pile_tab0
POKE src_ptr[0] , 1
POKE src_ptr[1] , 51 // K♣
// dst is empty
POINTER dst_ptr -> pile_tab1
// Move King to empty tableau
move_tab_to_tab(src_ptr, dst_ptr, 1, success)
// Render
render_tableau_pile($0400, 0, src_ptr)
render_tableau_pile($0400, 10, dst_ptr)
FEND
// Test move_found_to_tab - undo move from foundation
FUNC test_found_to_tab
WORD found_ptr @ $f6
WORD tab_ptr @ $f8
BYTE success
clear_all_piles()
// Setup foundation with A♥, 2♥, 3♥
POINTER found_ptr -> pile_found0
POKE found_ptr[0] , 3
POKE found_ptr[1] , 0 // A♥
POKE found_ptr[2] , 1 // 2♥
POKE found_ptr[3] , 2 // 3♥
// Setup tableau with 4♠ (black) - valid for 3♥ (red)
POINTER tab_ptr -> pile_tab0
POKE tab_ptr[0] , 1
POKE tab_ptr[1] , 29 // 4♠
// Move 3♥ from foundation to tableau
move_found_to_tab(found_ptr, tab_ptr, success)
// Render
render_foundation_pile($0400, 0, found_ptr)
render_tableau_pile($0400, 10, tab_ptr)
FEND
// Run all move tests sequentially (for visual inspection)
// Each test clears screen area and renders result
FUNC run_all_move_tests
BYTE dummy
// Test 1: Stock to Waste draw-1
test_stock_to_waste_draw1()
// Wait for keypress or delay here if needed
// To run individual tests, call them directly:
// test_stock_to_waste_draw3()
// test_reset_stock()
// test_waste_to_tab_valid()
// test_waste_to_tab_king_empty()
// test_waste_to_tab_invalid()
// test_waste_to_found_ace()
// test_waste_to_found_sequence()
// test_tab_to_found()
// test_tab_to_tab_single()
// test_tab_to_tab_stack()
// test_tab_to_tab_king_empty()
// test_found_to_tab()
FEND
LABEL __skip_lib_cardtests
#IFEND