878 lines
20 KiB
Text
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
|