Author Topic: Blackjack  (Read 5318 times)

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #225 on: July 08, 2020, 08:27:00 PM »
By the way @George McGinn  if you want to try your hand at an AI, I'd be glad to test it in my Tester #3

Here is a snap of a current run:
 


Hi @johnno56  I have gone a full loop at testing layouts and decided one row of players with Dealer at top, pretty much as you said ;-))

To all,  Still have openings for AI Functions to test, here is current Tester:
Code: QB64: [Select]
  1. ' No suits shown for cards A is Ace, J, Q, K are Jack, Queen, King, X is for 10
  2. '2020-07-05 fix hit (it wasn't broken), delete line chose$ = inkey$ before loop
  3. ' force dealer to hit on 16 stay 17
  4. ' ties are push
  5. ' bring in double down option
  6. ' fix dealer has Blackjack should tell also fix exposing 2nd card
  7. ' work this towards converting to multiple AI players, so players stats are all located in PlayerType
  8. ' 2020-07-06 Installed AI and mods for it
  9. ' 2020-07-06 new Compact Tester with 2nd AI
  10. ' 2020-07-06 start Blackjack Multi AI Tester off of Compact Tester
  11. '            add in allot of code worked out in Blackjack with Bots 2019-06-07
  12. '            Yes, major overhaul of last year bot code which was/is neat!
  13. '            Thanks Johnno and Steve for some interesting AI ideas to try!
  14. ' 2020-07-07 for Blackjack Multi AI Tester #2, I hope to do something kind of interesting with displaying players
  15. '            Yes Mouse over a player you want to check on but try and stay out of way of updating.
  16. ' 2020-07-08 No overlapping players, sucks, get rid of timer stuff, removed.
  17. '            Screen Size depends on how many players go against Dealer from 1 to 6 maximum.
  18. '            1 row of players with screen width < 1024, Dealer at top.
  19. '            Added more items to Player type  to display status solely from it's array contents.
  20. '            Also forbid player to double down if es chips can't cover loss.
  21. '            Display round number in Title Bar
  22.  
  23. '=================================================================================================================
  24. ' Blackjack Multi-Tester Notes: (removed from screening at start)
  25.  
  26. '                              *** Blackjack Multi AI Tester #3 ***
  27. '
  28. '                     Each AI bot starts with 100 chips and bets 2 each round.
  29. '                                Dealer must hit on 16 or less.
  30. '                                 Blackjack pays 1.5 X the bet.
  31. '                       Double down option available when you get 2 cards.
  32. '                         It Doubles the bet and you get one more card.
  33. '
  34. '====================================================================================================================
  35.  
  36. DEFINT A-Z
  37.  
  38. CONST nPlayers = 7 '            2 to 7 only! Dealer counts as the last player Screen size is adjusted to this!
  39. CONST rank$ = "A23456789XJQK" ' for building deck and figuring Totals
  40. CONST bH = 12, bW = 20 '        box height and box width in rows and columns
  41. CONST bc = &HFF008822, fc = &HFFCCCCFF ' screen back and fore colors , no printing though
  42.  
  43. TYPE PlayerType
  44.     ID AS STRING '        name of bot including dealer bot
  45.     Col AS INTEGER '      left corner column
  46.     Row AS INTEGER '      top row
  47.     FC AS _UNSIGNED LONG 'player colors are assigned in init FC are alternating Black and White
  48.     BC AS _UNSIGNED LONG 'random light and dark opposite print FC
  49.     Hand AS STRING '      cards are 1 char strings 10 is X
  50.     Ace AS INTEGER '      flag has ace for totalling hand
  51.     Bust AS INTEGER '     flag for final reckoning
  52.     BJ AS INTEGER '       flag for final reckoning
  53.     Total AS INTEGER '    card total of hand
  54.     Chips AS _INTEGER64 ' players status
  55.     SetBet AS _INTEGER64 'regular bet amount
  56.     Bet AS _INTEGER64 '   players bet each round
  57.     Tell AS STRING '      Hit, Stay Double or Win Push Loss Amt goal to put everything in PlayerType that showPlayer needs for display
  58.  
  59. DIM SHARED xmax, deck$(1 TO 52), p(1 TO nPlayers) AS PlayerType, deckIndex, round, allOut, player, blockDealer
  60.  
  61. DIM i, chose$
  62. initGame
  63. 'FOR i = 1 TO nPlayers
  64. '    showPlayer i
  65. 'NEXT
  66. 'SLEEP
  67. 'END
  68. DO 'start a round
  69.     startRound 'clears screen too and shuffles deck
  70.  
  71.     FOR i = 1 TO 2
  72.         FOR player = 1 TO nPlayers 'each Player is dealt 2 cards
  73.             IF player <> nPlayers THEN
  74.                 IF p(player).Chips > 0 THEN
  75.                     allOut = 0 'signal everyone is out of chips is false
  76.                     PlayerAddCard player
  77.                 END IF
  78.             ELSE
  79.                 IF allOut THEN
  80.                     EXIT DO
  81.                 ELSE
  82.                     PlayerAddCard player
  83.                 END IF
  84.             END IF
  85.         NEXT
  86.     NEXT
  87.  
  88.     IF p(nPlayers).BJ = 0 THEN 'dealer does not have BJ
  89.         FOR player = 1 TO nPlayers - 1
  90.             showPlayer player
  91.             WHILE p(player).Total < 21
  92.                 SELECT CASE player ' this has to be coded for exactly all nPlayers - 1
  93.                     CASE 1: chose$ = Johnno$(player)
  94.                     CASE 2: chose$ = Steve$(player)
  95.                     CASE 3: chose$ = bplusAI$(player)
  96.                     CASE 4: chose$ = bplusAI$(player)
  97.                     CASE 5: chose$ = bplusAI2$(player)
  98.                     CASE 6: chose$ = bplusAI2$(player) 'no more than 6 bots
  99.                 END SELECT
  100.                 IF chose$ = "h" THEN p(player).Tell = "Hit"
  101.                 IF chose$ = "d" THEN p(player).Tell = "Double Down"
  102.                 IF chose$ <> "h" AND chose$ <> "d" THEN p(player).Tell = "Stay"
  103.                 showPlayer player
  104.                 _DELAY 2
  105.                 IF chose$ = "h" THEN
  106.                     PlayerAddCard player
  107.                 ELSEIF chose$ = "d" AND LEN(p(player).Hand) = 2 THEN
  108.                     p(player).Bet = 2 * p(player).Bet
  109.                     PlayerAddCard player
  110.                     EXIT WHILE
  111.                 ELSE 'stayed
  112.                     EXIT WHILE
  113.                 END IF
  114.             WEND
  115.         NEXT
  116.     END IF
  117.  
  118.     blockDealer = 0
  119.     showPlayer nPlayers
  120.     WHILE p(nPlayers).Total < 17
  121.         p(nPlayers).Tell = "Dealer takes a card."
  122.         showPlayer nPlayers
  123.         PlayerAddCard nPlayers
  124.     WEND
  125.     p(nPlayers).Tell = "Reckoning"
  126.     showPlayer nPlayers
  127.  
  128.     '    final Reckoning
  129.     FOR player = 1 TO nPlayers - 1
  130.         showPlayer player
  131.         IF p(player).BJ AND p(nPlayers).BJ THEN
  132.             p(player).Tell = "Push"
  133.         ELSEIF p(player).Total > 21 OR (p(player).Total < p(nPlayers).Total AND p(nPlayers).Total < 22) THEN
  134.             p(player).Tell = "Lost" + STR$(p(player).Bet)
  135.             p(player).Chips = p(player).Chips - p(player).Bet
  136.             p(nPlayers).Chips = p(nPlayers).Chips + p(player).Bet
  137.         ELSEIF p(player).Total = p(nPlayers).Total AND p(player).BJ = 0 THEN
  138.             p(player).Tell = "Push"
  139.         ELSE
  140.             IF p(player).BJ THEN
  141.                 p(player).Tell = "Win!" + STR$(p(player).Bet + .5 * p(player).Bet)
  142.                 p(player).Chips = p(player).Chips + p(player).Bet + .5 * p(player).Bet
  143.                 p(nPlayers).Chips = p(nPlayers).Chips - p(player).Bet - .5 * p(player).Bet
  144.             ELSE
  145.                 p(player).Tell = "Win!" + STR$(p(player).Bet)
  146.                 p(player).Chips = p(player).Chips + p(player).Bet
  147.                 p(nPlayers).Chips = p(nPlayers).Chips - p(player).Bet
  148.             END IF
  149.         END IF
  150.         showPlayer player
  151.         _DELAY 1 'an extra delay
  152.         IF p(player).Chips = 0 THEN
  153.             p(player).Tell = "Out of chips!":
  154.             showPlayer player
  155.             _DELAY 2 ' an extra delay
  156.         END IF
  157.     NEXT
  158. LOOP UNTIL allOut
  159.  
  160. SUB startRound
  161.     DIM i
  162.     COLOR fc, bc: CLS
  163.     round = round + 1: allOut = -1
  164.     FOR i = 1 TO nPlayers
  165.         p(i).Hand = ""
  166.         p(i).Ace = 0
  167.         p(i).Total = 0
  168.         p(i).BJ = 0
  169.         p(i).Bust = 0
  170.         p(i).Tell = ""
  171.         'because of double down option I have to reset bet during play and set it back at each new round
  172.         'make sure we aren't betting more than our chips count at least to start
  173.         IF p(i).Chips < p(i).SetBet THEN p(i).Bet = p(i).Chips ELSE p(i).Bet = p(i).SetBet
  174.     NEXT
  175.     FOR i = 52 TO 2 STEP -1 'shuffle
  176.         SWAP deck$(INT(RND * i) + 1), deck$(i)
  177.     NEXT
  178.     'deck$(5) = "A": deck$(10) = "J"  'check immediate show of Blackjack for dealer
  179.     deckIndex = 0: blockDealer = -1
  180.     _TITLE "BJ AI Tester Round:" + STR$(round)
  181.  
  182. FUNCTION bplusAI$ (pn) ' first try
  183.     SELECT CASE p(pn).Total
  184.         CASE IS < 10: bplusAI$ = "h" 'no caps!
  185.         CASE 10, 11
  186.             IF LEN(p(pn).Hand) = 2 THEN bplusAI$ = "d" ELSE bplusAI$ = "h"
  187.         CASE IS < 15
  188.             IF RND < .5 THEN bplusAI$ = "h" ELSE bplusAI$ = "whatever"
  189.         CASE ELSE: bplusAI$ = "Show me the money!"
  190.     END SELECT
  191.  
  192. FUNCTION bplusAI2$ (pN) 'after trying first want to try this make it more likely to hit on 12 than 13, 14...
  193.     SELECT CASE p(pN).Total
  194.         CASE IS < 10: bplusAI2$ = "h" 'no caps!
  195.         CASE 10, 11 'double down unless dealer showing an Ace which is like insurance for dealer
  196.             IF LEN(p(pN).Hand) = 2 AND LEFT$(p(nPlayers).Hand, 1) <> "A" THEN bplusAI2$ = "d" ELSE bplusAI2$ = "h"
  197.         CASE 12: IF RND < .75 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  198.         CASE 13: IF RND < .5 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  199.         CASE 14: IF RND < .25 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  200.         CASE ELSE: bplusAI2$ = "Show me the money!"
  201.     END SELECT
  202.  
  203. FUNCTION Johnno$ (pN)
  204.     IF p(pN).Total = 10 OR p(pN).Total = 11 AND LEN(p(pN).Hand) = 2 THEN
  205.         Johnno$ = "d"
  206.     ELSEIF p(pN).Total = 10 OR p(pN).Total = 11 AND LEN(p(pN).Hand) <> 2 THEN
  207.         Johnno$ = "h"
  208.     ELSEIF 12 <= p(pN).Total AND p(pN).Total <= 15 THEN
  209.         SELECT CASE LEFT$(p(nPlayers).Hand, 1)
  210.             CASE "A", "K", "Q", "J", "X", "9": Johnno$ = "h"
  211.             CASE "7", "8": IF RND < .5 THEN Johnno$ = "h"
  212.             CASE ELSE: Johnno$ = "Hope to Bust em"
  213.         END SELECT
  214.     ELSEIF p(pN).Total < 12 THEN
  215.         Johnno$ = "h"
  216.     ELSE
  217.         Johnno$ = "Stay"
  218.     END IF
  219.  
  220. FUNCTION Steve$ (pN) 'how simple is this! never bust make dealer work for it
  221.     IF p(pN).Total < 12 THEN Steve$ = "h"
  222.  
  223. SUB PlayerAddCard (rec) 'updates player's hand and total
  224.     DIM i AS INTEGER, cv AS INTEGER
  225.     deckIndex = deckIndex + 1
  226.     p(rec).Hand = p(rec).Hand + deck$(deckIndex)
  227.     IF deck$(deckIndex) = "A" THEN p(rec).Ace = -1
  228.     p(rec).Total = 0
  229.     FOR i = 1 TO LEN(p(rec).Hand)
  230.         IF INSTR(rank$, MID$(p(rec).Hand, i, 1)) > 10 THEN cv = 10 ELSE cv = INSTR(rank$, MID$(p(rec).Hand, i, 1))
  231.         p(rec).Total = p(rec).Total + cv
  232.     NEXT
  233.     IF p(rec).Total < 12 AND p(rec).Ace THEN p(rec).Total = p(rec).Total + 10
  234.     IF LEN(p(rec).Hand) = 2 AND p(rec).Total = 21 THEN p(rec).BJ = -1
  235.     IF p(rec).Total > 21 THEN p(rec).Bust = -1
  236.     showPlayer rec 'when ever add card show update
  237.  
  238. SUB showPlayer (nPlayer) '
  239.     DIM i AS INTEGER, S$
  240.     COLOR p(nPlayer).FC, p(nPlayer).BC
  241.     FOR i = 0 TO bH - 1 'clear our block
  242.         LOCATE p(nPlayer).Row + i, p(nPlayer).Col: PRINT SPACE$(bW);
  243.     NEXT
  244.     cp nPlayer, 1, p(nPlayer).ID
  245.     cp nPlayer, 3, "Chips:" + STR$(p(nPlayer).Chips)
  246.     IF nPlayer <> nPlayers THEN cp nPlayer, 4, "Bet:" + STR$(p(nPlayer).Bet)
  247.     FOR i = 1 TO LEN(p(nPlayer).Hand)
  248.         S$ = S$ + MID$(p(nPlayer).Hand, i, 1) + " "
  249.     NEXT
  250.     IF nPlayer = nPlayers AND LEN(p(nPlayer).Hand) = 2 AND p(nPlayer).Total <> 21 AND blockDealer THEN
  251.         S$ = LEFT$(S$, 2) + "?"
  252.         cp nPlayer, 6, S$
  253.         cp nPlayer, 7, "Total: ??"
  254.     ELSE
  255.         cp nPlayer, 6, S$
  256.         cp nPlayer, 7, "Total:" + STR$(p(nPlayer).Total)
  257.     END IF
  258.     IF p(nPlayer).Bust THEN cp nPlayer, 8, "Busted"
  259.     IF p(nPlayer).BJ THEN cp nPlayer, 8, "Blackjack"
  260.     cp nPlayer, 10, p(nPlayer).Tell ' last action of player or dealer or final win lost push
  261.     _DELAY 1 'when ever showPlayer  need a delay to read
  262.  
  263. SUB initGame 'the stuff that never changes
  264.     DIM i
  265.     ' 1+13*2 rows = 27*16 = 432 ymax
  266.     xmax = ((nPlayers - 1) * 21 + 1) * 8
  267.     SCREEN _NEWIMAGE(xmax, 432, 32)
  268.     _DELAY .25
  269.  
  270.     'dealer on top row then max 2 rows of 5 players
  271.     FOR i = 1 TO nPlayers
  272.         IF i <> nPlayers THEN
  273.             SELECT CASE i 'vvvvvvvvvvvvvvvvvvvvvvvvvvvv plug in ai names here
  274.                 CASE 1: p(i).ID = "Johnno"
  275.                 CASE 2: p(i).ID = "Steve"
  276.                 CASE 3: p(i).ID = "AI 1"
  277.                 CASE 4: p(i).ID = "AI 2"
  278.                 CASE 5: p(i).ID = "2nd AI 1"
  279.                 CASE 6: p(i).ID = "2nd AI 2"
  280.             END SELECT
  281.             p(i).Col = 2 + (i - 1) * 21
  282.             p(i).Row = 15
  283.             p(i).Chips = 100
  284.             p(i).SetBet = 2
  285.             IF i MOD 2 THEN
  286.                 p(i).BC = _RGB32(RND * 128, RND * 60, RND * 128)
  287.             ELSE
  288.                 p(i).BC = _RGB32(RND * 128 + 127, 255 - RND * 95, RND * 128 + 127)
  289.             END IF
  290.             IF i MOD 2 THEN p(i).FC = &HFFFFFFFF ELSE p(i).FC = &HFF000000
  291.         ELSE
  292.             p(i).ID = "Dealer"
  293.             p(i).Col = (xmax \ 8 - 20) \ 2 + 1
  294.             p(i).Row = 2
  295.             p(i).Chips = -100 * (nPlayers - 1)
  296.             p(i).BC = &HFF000000
  297.             p(i).FC = &HFFFFFFFF
  298.         END IF
  299.     NEXT
  300.     FOR i = 1 TO 52 'get deck ready
  301.         deck$(i) = MID$(rank$ + rank$ + rank$ + rank$, i, 1)
  302.     NEXT
  303.  
  304.     COLOR fc, bc: CLS
  305.  
  306. SUB cp (nPlayer, row, s AS STRING) 'center print a string on the given row
  307.     IF nPlayer THEN
  308.         COLOR p(nPlayer).FC, p(nPlayer).BC
  309.         LOCATE p(nPlayer).Row + row, p(nPlayer).Col + (bW - LEN(s)) / 2: PRINT s;
  310.     ELSE
  311.         COLOR fc, bc
  312.         PRINT s, row, (xmax \ 8 - LEN(s)) / 2 + 1
  313.         LOCATE row, (xmax \ 8 - LEN(s)) / 2 + 1: PRINT s;
  314.     END IF
  315.  
  316.  



Offline George McGinn

  • Newbie
  • Posts: 11
Re: Blackjack
« Reply #226 on: July 08, 2020, 09:28:07 PM »
When I run the BJ Dealer Test program on macOS, I get the following errors (I'm running v1.4 of QB64:



In file included from qbx.cpp:2226:
./../temp/main.txt:100:33: error: arithmetic on a pointer to void
qbs_set(*((qbs**)((__UDT_DEALER)+(8))),qbs_new_txt_len("",0));
                  ~~~~~~~~~~~~~~^
./../temp/main.txt:135:46: error: arithmetic on a pointer to void
qbs_set(tqbs,qbs_right(*((qbs**)(__UDT_DEALER+(8))), 1 ));
                                 ~~~~~~~~~~~~^
./../temp/main.txt:304:33: error: arithmetic on a pointer to void
qbs_set(*((qbs**)((__UDT_DEALER)+(8))),qbs_add(*((qbs**)(__UDT_DEALER+(8))),((qbs*)(((uint64*)(__ARRAY_STRING_DECK[0]))[array_check((*__INTEGER_DECKINDEX)-__ARRAY_STRING_DECK[4],__ARRAY_STRING_DECK[5])]))));
                  ~~~~~~~~~~~~~~^
./../temp/main.txt:304:70: error: arithmetic on a pointer to void
qbs_set(*((qbs**)((__UDT_DEALER)+(8))),qbs_add(*((qbs**)(__UDT_DEALER+(8))),((qbs*)(((uint64*)(__ARRAY_STRING_DECK[0]))[array_check((*__INTEGER_DECKINDEX)-__ARRAY_STRING_DECK[4],__ARRAY_STRING_DECK[5])]))));
                                                         ~~~~~~~~~~~~^
./../temp/main.txt:337:116: error: arithmetic on a pointer to void
if ((qbs_cleanup(qbs_tmp_base,-(func_instr(NULL,qbs_new_txt_len("A23456789XJQK",13),func_mid(*((qbs**)(__UDT_DEALER+(8))),*_SUB_PLAYERADDCARD_INTEGER_I, 1 ,1),0)> 10 )))||new_error){
                                                                                                       ~~~~~~~~~~~~^
./../temp/main.txt:344:115: error: arithmetic on a pointer to void
*_SUB_PLAYERADDCARD_INTEGER_CV=func_instr(NULL,qbs_new_txt_len("A23456789XJQK",13),func_mid(*((qbs**)(__UDT_DEALER+(8))),*_SUB_PLAYERADDCARD_INTEGER_I, 1 ,1),0);
                                                                                                      ~~~~~~~~~~~~^
6 errors generated.

Offline George McGinn

  • Newbie
  • Posts: 11
Re: Blackjack
« Reply #227 on: July 08, 2020, 09:32:57 PM »
@bplus - I might take you up on creating a playing AI.

Give me about a month. I'm waiting to hear if I have been approved to buy a house, and may have to move quickly, by July 31. This means I'll be spending my time packing most of July.

Offline George McGinn

  • Newbie
  • Posts: 11
Re: Blackjack
« Reply #228 on: July 08, 2020, 09:46:08 PM »
WOW!

Who Knew? I sure didn't. I just thought it was the most expedient way to do a random sort without having a SWAP statement.

I tested it with 8 decks (without all the print statements) and it still finished in hundreds or milliseconds.

I guess you should add my name to the WIKI, as I just co-invented it!!!

George

Hi @George McGinn

I see you come from Steve McNeil's camp of swapping each card with any of the other 52 cards.

There is a math proof that this is not ideal and leaves slightly less than perfect random distribution (given perfect random generator but who has that?)

"https://en.wikipedia.org/wiki/Fisher–Yates_shuffle"  <<copy/paste between quotes this in browser because underline link usually fails.

Look under Naive Shuffle:
 


Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #229 on: July 08, 2020, 10:25:18 PM »
Quote
When I run the BJ Dealer Test program on macOS, I get the following errors (I'm running v1.4 of QB64:

@George McGinn

Copy Paste test of code from forum to double check in my Windows 10 laptop, works fine!

Looks like macOS doesn't like QB64 so much?

Online FellippeHeitor

  • QB64 Developer
  • Forum Resident
  • Posts: 2215
  • LET IT = BE
    • QB64.org
Re: Blackjack
« Reply #230 on: July 08, 2020, 11:33:33 PM »
The bug with variable width strings in UDTs on macOS is already under investigation: https://github.com/QB64Team/qb64/issues/64

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #231 on: July 09, 2020, 12:00:22 AM »
@Qwerkey

As promised the Blackjack Game, BJ v2020-07-08 updated with more or better comments:
(Nothing has been changed in the code, for those who have already downloaded the July 4th version.)

I have updated this game with a more enjoyable playing game, not exactly casino rules...

see Best answer for download.

« Last Edit: July 15, 2020, 03:35:47 PM by bplus »

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #232 on: July 09, 2020, 12:25:58 AM »
Here is another little update to the Multi-AI Tester #3, I moved all the AI's to the bottom of the subs area and added a bunch of simple ones to test different Stay numbers side by side, I suppose it'd take a very, very long run to actually distinguish the different Stay strategies and just plain luck of the cards.

I named the Stay 16 limit after George because he spoke of it sorta, and I named Stay 18 after Steve2 because he might have been meaning to Stay one more card over what the Dealer has to stay at, preliminary tests suggest they are all better than Stay 12 (so you can never be busted). B3 is Stay 16 plus Double Down only at 11.

Code: QB64: [Select]
  1. ' No suits shown for cards A is Ace, J, Q, K are Jack, Queen, King, X is for 10
  2. '2020-07-05 fix hit (it wasn't broken), delete line chose$ = inkey$ before loop
  3. ' force dealer to hit on 16 stay 17
  4. ' ties are push
  5. ' bring in double down option
  6. ' fix dealer has Blackjack should tell also fix exposing 2nd card
  7. ' work this towards converting to multiple AI players, so players stats are all located in PlayerType
  8. ' 2020-07-06 Installed AI and mods for it
  9. ' 2020-07-06 new Compact Tester with 2nd AI
  10. ' 2020-07-06 start Blackjack Multi AI Tester off of Compact Tester
  11. '            add in allot of code worked out in Blackjack with Bots 2019-06-07
  12. '            Yes, major overhaul of last year bot code which was/is neat!
  13. '            Thanks Johnno and Steve for some interesting AI ideas to try!
  14. ' 2020-07-07 for Blackjack Multi AI Tester #2, I hope to do something kind of interesting with displaying players
  15. '            Yes Mouse over a player you want to check on but try and stay out of way of updating.
  16. ' 2020-07-08 No overlapping players, sucks, get rid of timer stuff, removed.
  17. '            Screen Size depends on how many players go against Dealer from 1 to 6 maximum.
  18. '            1 row of players with screen width < 1024, Dealer at top.
  19. '            Added more items to Player type  to display status solely from it's array contents.
  20. '            Also forbid player to double down if es chips can't cover loss.
  21. '            Display round number in Title Bar
  22. ' 2020-07-08 added some basic stay strategies
  23. '=================================================================================================================
  24. ' Blackjack Multi-Tester Notes: (removed from screening at start)
  25.  
  26. '                              *** Blackjack Multi AI Tester #3 ***
  27. '
  28. '                     Each AI bot starts with 100 chips and bets 2 each round.
  29. '                                Dealer must hit on 16 or less.
  30. '                                 Blackjack pays 1.5 X the bet.
  31. '                       Double down option available when you get 2 cards.
  32. '                         It Doubles the bet and you get one more card.
  33. '
  34. '====================================================================================================================
  35.  
  36. DEFINT A-Z
  37.  
  38. CONST nPlayers = 7 '            2 to 7 only! Dealer counts as the last player Screen size is adjusted to this!
  39. CONST rank$ = "A23456789XJQK" ' for building deck and figuring Totals
  40. CONST bH = 12, bW = 20 '        box height and box width in rows and columns
  41. CONST bc = &HFF008822, fc = &HFFCCCCFF ' screen back and fore colors , no printing though
  42.  
  43. TYPE PlayerType
  44.     ID AS STRING '        name of bot including dealer bot
  45.     Col AS INTEGER '      left corner column
  46.     Row AS INTEGER '      top row
  47.     FC AS _UNSIGNED LONG 'player colors are assigned in init FC are alternating Black and White
  48.     BC AS _UNSIGNED LONG 'random light and dark opposite print FC
  49.     Hand AS STRING '      cards are 1 char strings 10 is X
  50.     Ace AS INTEGER '      flag has ace for totalling hand
  51.     Bust AS INTEGER '     flag for final reckoning
  52.     BJ AS INTEGER '       flag for final reckoning
  53.     Total AS INTEGER '    card total of hand
  54.     Chips AS _INTEGER64 ' players status
  55.     SetBet AS _INTEGER64 'regular bet amount
  56.     Bet AS _INTEGER64 '   players bet each round
  57.     Tell AS STRING '      Hit, Stay Double or Win Push Loss Amt goal to put everything in PlayerType that showPlayer needs for display
  58.  
  59. DIM SHARED xmax, deck$(1 TO 52), p(1 TO nPlayers) AS PlayerType, deckIndex, round, allOut, player, blockDealer
  60.  
  61. DIM i, chose$
  62. initGame
  63. 'FOR i = 1 TO nPlayers
  64. '    showPlayer i
  65. 'NEXT
  66. 'SLEEP
  67. 'END
  68. DO 'start a round
  69.     startRound 'clears screen too and shuffles deck
  70.  
  71.     FOR i = 1 TO 2
  72.         FOR player = 1 TO nPlayers 'each Player is dealt 2 cards
  73.             IF player <> nPlayers THEN
  74.                 IF p(player).Chips > 0 THEN
  75.                     allOut = 0 'signal everyone is out of chips is false
  76.                     PlayerAddCard player
  77.                 END IF
  78.             ELSE
  79.                 IF allOut THEN
  80.                     EXIT DO
  81.                 ELSE
  82.                     PlayerAddCard player
  83.                 END IF
  84.             END IF
  85.         NEXT
  86.     NEXT
  87.  
  88.     IF p(nPlayers).BJ = 0 THEN 'dealer does not have BJ
  89.         FOR player = 1 TO nPlayers - 1
  90.             showPlayer player
  91.             WHILE p(player).Total < 21
  92.                 SELECT CASE player ' this has to be coded for exactly all nPlayers - 1
  93.                     CASE 1: chose$ = Johnno$(player)
  94.                     CASE 2: chose$ = Steve$(player)
  95.                     CASE 3: chose$ = stay16$(player)
  96.                     CASE 4: chose$ = stay17$(player)
  97.                     CASE 5: chose$ = stay18$(player)
  98.                     CASE 6: chose$ = bplusAI3$(player) 'no more than 6 bots
  99.                 END SELECT
  100.                 IF chose$ = "h" THEN p(player).Tell = "Hit"
  101.                 IF chose$ = "d" THEN p(player).Tell = "Double Down"
  102.                 IF chose$ <> "h" AND chose$ <> "d" THEN p(player).Tell = "Stay"
  103.                 showPlayer player
  104.                 _DELAY 2
  105.                 IF chose$ = "h" THEN
  106.                     PlayerAddCard player
  107.                 ELSEIF chose$ = "d" AND LEN(p(player).Hand) = 2 THEN
  108.                     p(player).Bet = 2 * p(player).Bet
  109.                     PlayerAddCard player
  110.                     EXIT WHILE
  111.                 ELSE 'stayed
  112.                     EXIT WHILE
  113.                 END IF
  114.             WEND
  115.         NEXT
  116.     END IF
  117.  
  118.     blockDealer = 0
  119.     showPlayer nPlayers
  120.     WHILE p(nPlayers).Total < 17
  121.         p(nPlayers).Tell = "Dealer takes a card."
  122.         showPlayer nPlayers
  123.         PlayerAddCard nPlayers
  124.     WEND
  125.     p(nPlayers).Tell = "Reckoning"
  126.     showPlayer nPlayers
  127.  
  128.     '    final Reckoning
  129.     FOR player = 1 TO nPlayers - 1
  130.         showPlayer player
  131.         IF p(player).BJ AND p(nPlayers).BJ THEN
  132.             p(player).Tell = "Push"
  133.         ELSEIF p(player).Total > 21 OR (p(player).Total < p(nPlayers).Total AND p(nPlayers).Total < 22) THEN
  134.             p(player).Tell = "Lost" + STR$(p(player).Bet)
  135.             p(player).Chips = p(player).Chips - p(player).Bet
  136.             p(nPlayers).Chips = p(nPlayers).Chips + p(player).Bet
  137.         ELSEIF p(player).Total = p(nPlayers).Total AND p(player).BJ = 0 THEN
  138.             p(player).Tell = "Push"
  139.         ELSE
  140.             IF p(player).BJ THEN
  141.                 p(player).Tell = "Win!" + STR$(p(player).Bet + .5 * p(player).Bet)
  142.                 p(player).Chips = p(player).Chips + p(player).Bet + .5 * p(player).Bet
  143.                 p(nPlayers).Chips = p(nPlayers).Chips - p(player).Bet - .5 * p(player).Bet
  144.             ELSE
  145.                 p(player).Tell = "Win!" + STR$(p(player).Bet)
  146.                 p(player).Chips = p(player).Chips + p(player).Bet
  147.                 p(nPlayers).Chips = p(nPlayers).Chips - p(player).Bet
  148.             END IF
  149.         END IF
  150.         showPlayer player
  151.         _DELAY 1 'an extra delay
  152.         IF p(player).Chips = 0 THEN
  153.             p(player).Tell = "Out of chips!":
  154.             showPlayer player
  155.             _DELAY 2 ' an extra delay
  156.         END IF
  157.     NEXT
  158. LOOP UNTIL allOut
  159.  
  160. SUB startRound
  161.     DIM i
  162.     COLOR fc, bc: CLS
  163.     round = round + 1: allOut = -1
  164.     FOR i = 1 TO nPlayers
  165.         p(i).Hand = ""
  166.         p(i).Ace = 0
  167.         p(i).Total = 0
  168.         p(i).BJ = 0
  169.         p(i).Bust = 0
  170.         p(i).Tell = ""
  171.         'because of double down option I have to reset bet during play and set it back at each new round
  172.         'make sure we aren't betting more than our chips count at least to start
  173.         IF p(i).Chips < p(i).SetBet THEN p(i).Bet = p(i).Chips ELSE p(i).Bet = p(i).SetBet
  174.     NEXT
  175.     FOR i = 52 TO 2 STEP -1 'shuffle
  176.         SWAP deck$(INT(RND * i) + 1), deck$(i)
  177.     NEXT
  178.     'deck$(5) = "A": deck$(10) = "J"  'check immediate show of Blackjack for dealer
  179.     deckIndex = 0: blockDealer = -1
  180.     _TITLE "BJ AI Tester Round:" + STR$(round)
  181.  
  182. SUB PlayerAddCard (rec) 'updates player's hand and total
  183.     DIM i AS INTEGER, cv AS INTEGER
  184.     deckIndex = deckIndex + 1
  185.     p(rec).Hand = p(rec).Hand + deck$(deckIndex)
  186.     IF deck$(deckIndex) = "A" THEN p(rec).Ace = -1
  187.     p(rec).Total = 0
  188.     FOR i = 1 TO LEN(p(rec).Hand)
  189.         IF INSTR(rank$, MID$(p(rec).Hand, i, 1)) > 10 THEN cv = 10 ELSE cv = INSTR(rank$, MID$(p(rec).Hand, i, 1))
  190.         p(rec).Total = p(rec).Total + cv
  191.     NEXT
  192.     IF p(rec).Total < 12 AND p(rec).Ace THEN p(rec).Total = p(rec).Total + 10
  193.     IF LEN(p(rec).Hand) = 2 AND p(rec).Total = 21 THEN p(rec).BJ = -1
  194.     IF p(rec).Total > 21 THEN p(rec).Bust = -1
  195.     showPlayer rec 'when ever add card show update
  196.  
  197. SUB showPlayer (nPlayer) '
  198.     DIM i AS INTEGER, S$
  199.     COLOR p(nPlayer).FC, p(nPlayer).BC
  200.     FOR i = 0 TO bH - 1 'clear our block
  201.         LOCATE p(nPlayer).Row + i, p(nPlayer).Col: PRINT SPACE$(bW);
  202.     NEXT
  203.     cp nPlayer, 1, p(nPlayer).ID
  204.     cp nPlayer, 3, "Chips:" + STR$(p(nPlayer).Chips)
  205.     IF nPlayer <> nPlayers THEN cp nPlayer, 4, "Bet:" + STR$(p(nPlayer).Bet)
  206.     FOR i = 1 TO LEN(p(nPlayer).Hand)
  207.         S$ = S$ + MID$(p(nPlayer).Hand, i, 1) + " "
  208.     NEXT
  209.     IF nPlayer = nPlayers AND LEN(p(nPlayer).Hand) = 2 AND p(nPlayer).Total <> 21 AND blockDealer THEN
  210.         S$ = LEFT$(S$, 2) + "?"
  211.         cp nPlayer, 6, S$
  212.         cp nPlayer, 7, "Total: ??"
  213.     ELSE
  214.         cp nPlayer, 6, S$
  215.         cp nPlayer, 7, "Total:" + STR$(p(nPlayer).Total)
  216.     END IF
  217.     IF p(nPlayer).Bust THEN cp nPlayer, 8, "Busted"
  218.     IF p(nPlayer).BJ THEN cp nPlayer, 8, "Blackjack"
  219.     cp nPlayer, 10, p(nPlayer).Tell ' last action of player or dealer or final win lost push
  220.     _DELAY 1 'when ever showPlayer  need a delay to read
  221.  
  222. SUB initGame 'the stuff that never changes
  223.     DIM i
  224.     ' 1+13*2 rows = 27*16 = 432 ymax
  225.     xmax = ((nPlayers - 1) * 21 + 1) * 8
  226.     SCREEN _NEWIMAGE(xmax, 432, 32)
  227.     _DELAY .25
  228.  
  229.     'dealer on top row then max 2 rows of 5 players
  230.     FOR i = 1 TO nPlayers
  231.         IF i <> nPlayers THEN
  232.             SELECT CASE i 'vvvvvvvvvvvvvvvvvvvvvvvvvvvv plug in ai names here
  233.                 CASE 1: p(i).ID = "Johnno"
  234.                 CASE 2: p(i).ID = "Steve Stay 12"
  235.                 CASE 3: p(i).ID = "George Stay 16"
  236.                 CASE 4: p(i).ID = "Dealer Stay 17"
  237.                 CASE 5: p(i).ID = "Steve2 Stay 18"
  238.                 CASE 6: p(i).ID = "b3 stay16 dd11"
  239.             END SELECT
  240.             p(i).Col = 2 + (i - 1) * 21
  241.             p(i).Row = 15
  242.             p(i).Chips = 100
  243.             p(i).SetBet = 2
  244.             IF i MOD 2 THEN
  245.                 p(i).BC = _RGB32(RND * 128, RND * 60, RND * 128)
  246.             ELSE
  247.                 p(i).BC = _RGB32(RND * 128 + 127, 255 - RND * 95, RND * 128 + 127)
  248.             END IF
  249.             IF i MOD 2 THEN p(i).FC = &HFFFFFFFF ELSE p(i).FC = &HFF000000
  250.         ELSE
  251.             p(i).ID = "Dealer"
  252.             p(i).Col = (xmax \ 8 - 20) \ 2 + 1
  253.             p(i).Row = 2
  254.             p(i).Chips = -100 * (nPlayers - 1)
  255.             p(i).BC = &HFF000000
  256.             p(i).FC = &HFFFFFFFF
  257.         END IF
  258.     NEXT
  259.     FOR i = 1 TO 52 'get deck ready
  260.         deck$(i) = MID$(rank$ + rank$ + rank$ + rank$, i, 1)
  261.     NEXT
  262.  
  263.     COLOR fc, bc: CLS
  264.  
  265. SUB cp (nPlayer, row, s AS STRING) 'center print a string on the given row
  266.     IF nPlayer THEN
  267.         COLOR p(nPlayer).FC, p(nPlayer).BC
  268.         LOCATE p(nPlayer).Row + row, p(nPlayer).Col + (bW - LEN(s)) / 2: PRINT s;
  269.     ELSE
  270.         COLOR fc, bc
  271.         PRINT s, row, (xmax \ 8 - LEN(s)) / 2 + 1
  272.         LOCATE row, (xmax \ 8 - LEN(s)) / 2 + 1: PRINT s;
  273.     END IF
  274.  
  275. ' ======================================= AI storage Area #51
  276.  
  277. FUNCTION bplusAI$ (pn) ' first try
  278.     SELECT CASE p(pn).Total
  279.         CASE IS < 10: bplusAI$ = "h" 'no caps!
  280.         CASE 10, 11
  281.             IF LEN(p(pn).Hand) = 2 THEN bplusAI$ = "d" ELSE bplusAI$ = "h"
  282.         CASE IS < 15
  283.             IF RND < .5 THEN bplusAI$ = "h" ELSE bplusAI$ = "whatever"
  284.         CASE ELSE: bplusAI$ = "Show me the money!"
  285.     END SELECT
  286.  
  287. FUNCTION bplusAI2$ (pN) 'after trying first want to try this make it more likely to hit on 12 than 13, 14...
  288.     SELECT CASE p(pN).Total
  289.         CASE IS < 10: bplusAI2$ = "h" 'no caps!
  290.         CASE 10, 11 'double down unless dealer showing an Ace which is like insurance for dealer
  291.             IF LEN(p(pN).Hand) = 2 AND LEFT$(p(nPlayers).Hand, 1) <> "A" THEN bplusAI2$ = "d" ELSE bplusAI2$ = "h"
  292.         CASE 12: IF RND < .75 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  293.         CASE 13: IF RND < .5 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  294.         CASE 14: IF RND < .25 THEN bplusAI2$ = "h" ELSE bplusAI2$ = "whatever"
  295.         CASE ELSE: bplusAI2$ = "Show me the money!"
  296.     END SELECT
  297.  
  298. FUNCTION bplusAI3$ (pn) ' first try modified to stay 16 plus dd on 11 only
  299.     SELECT CASE p(pn).Total
  300.         CASE 11
  301.             IF LEN(p(pn).Hand) = 2 THEN bplusAI3$ = "d" ELSE bplusAI3$ = "h"
  302.         CASE IS < 16: bplusAI3$ = "h"
  303.     END SELECT
  304.  
  305. FUNCTION Johnno$ (pN)
  306.     IF p(pN).Total = 10 OR p(pN).Total = 11 AND LEN(p(pN).Hand) = 2 THEN
  307.         Johnno$ = "d"
  308.     ELSEIF p(pN).Total = 10 OR p(pN).Total = 11 AND LEN(p(pN).Hand) <> 2 THEN
  309.         Johnno$ = "h"
  310.     ELSEIF 12 <= p(pN).Total AND p(pN).Total <= 15 THEN
  311.         SELECT CASE LEFT$(p(nPlayers).Hand, 1)
  312.             CASE "A", "K", "Q", "J", "X", "9": Johnno$ = "h"
  313.             CASE "7", "8": IF RND < .5 THEN Johnno$ = "h"
  314.             CASE ELSE: Johnno$ = "Hope to Bust em"
  315.         END SELECT
  316.     ELSEIF p(pN).Total < 12 THEN
  317.         Johnno$ = "h"
  318.     ELSE
  319.         Johnno$ = "Stay"
  320.     END IF
  321.  
  322. FUNCTION Steve$ (pN) 'how simple is this! never bust make dealer work for it
  323.     IF p(pN).Total < 12 THEN Steve$ = "h"
  324.  
  325. FUNCTION stay16$ (pN) ' calling this George because he seems to agree, might want to do more about what Dealer is showing
  326.     IF p(pN).Total < 16 THEN stay16$ = "h"
  327. FUNCTION stay17$ (pN)
  328.     IF p(pN).Total < 17 THEN stay17$ = "h"
  329. FUNCTION stay18$ (pN) 'this might have been what Steve was talking about so calling it Steve2
  330.     IF p(pN).Total < 18 THEN stay18$ = "h"
  331.  
  332.  
  333.  

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #233 on: July 09, 2020, 01:12:22 AM »
The bug with variable width strings in UDTs on macOS is already under investigation: https://github.com/QB64Team/qb64/issues/64

Hey it's not one of those CHR$(0) at the end of the string things is it?

Offline codeguy

  • Forum Regular
  • Posts: 180
Re: Blackjack
« Reply #234 on: July 09, 2020, 03:16:08 AM »
I would choose Knuth Shuffle for shuffling cards or for any randomization of order.
Code: QB64: [Select]
  1. TYPE card
  2.     cardVAL AS _UNSIGNED _BYTE
  3.     CARDsuit AS STRING * 7
  4. DIM NSUITSMIN AS _UNSIGNED INTEGER: NSUITSMIN = 1
  5. DIM NSUITSMAX AS _UNSIGNED INTEGER: NSUITSMAX = 4
  6. DIM NCARDSMIN AS _UNSIGNED INTEGER: NCARDSMIN = 1
  7. DIM NCARDSMAX AS _UNSIGNED INTEGER: NCARDSMAX = 13
  8. REDIM Deck(1 TO (NSUITSMAX - NSUITSMIN + 1) * (NCARDSMAX - NCARDSMIN + 1)) AS card
  9.  
  10. FOR S = NSUITSMIN TO NSUITSMAX
  11.     READ SUIT
  12.     FOR T = NCARDSMIN TO NCARDSMAX
  13.         Deck(X).CARDsuit = SUIT
  14.         Deck(X).cardVAL = T
  15.         X = X + 1
  16.     NEXT
  17. DATA DIAMOND,SPADE,HEART,CLUB
  18. KnuthShuffle Deck(), LBOUND(DECK), UBOUND(DECK)
  19. SUB KnuthShuffle (a() AS card, start AS _INTEGER64, finish AS _INTEGER64)
  20.     DIM KNUTHSHUFFLE_AX AS _INTEGER64
  21.     DIM KNUTHSHUFFLE_BX AS _INTEGER64
  22.     KNUTHSHUFFLE_BX = start
  23.     DO
  24.         KNUTHSHUFFLE_AX = KNUTHSHUFFLE_BX
  25.         KNUTHSHUFFLE_BX = KNUTHSHUFFLE_AX + 1
  26.         SWAP a(KNUTHSHUFFLE_AX), a(KNUTHSHUFFLE_BX + INT(RND * (finish - KNUTHSHUFFLE_BX)))
  27.     LOOP UNTIL KNUTHSHUFFLE_AX > finish - 1
  28.  

Online FellippeHeitor

  • QB64 Developer
  • Forum Resident
  • Posts: 2215
  • LET IT = BE
    • QB64.org
Re: Blackjack
« Reply #235 on: July 09, 2020, 08:12:42 AM »
Hey it's not one of those CHR$(0) at the end of the string things is it?
No, it isn't.

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #236 on: July 09, 2020, 11:16:53 AM »
Quote
I would choose Knuth Shuffle for shuffling cards or for any randomization of order.

Yep! AKA Fisher-Yates shuffle, don't leave home without it 👍

Offline George McGinn

  • Newbie
  • Posts: 11
Re: Blackjack
« Reply #237 on: July 09, 2020, 11:41:05 AM »
Are there any specific coding for windows?

Since I have been coded in windows since the mid-1990s, plus one project I did in 2000–2001, I very rarely use windows because it always bothered to down my computer where macOS and Linux does not.

In macOS and Linux I very rarely get errors, unless there’s code for a specific operation system.


@George McGinn

Copy Paste test of code from forum to double check in my Windows 10 laptop, works fine!

Looks like macOS doesn't like QB64 so much?

Offline George McGinn

  • Newbie
  • Posts: 11
Re: Blackjack
« Reply #238 on: July 09, 2020, 11:52:08 AM »
That makes sense. I do not think macOS can handle CHR$(0) at end–of–line. Internally only requires a linefeed character which I believe is CHR$(13).

Later on today I’m gonna fire up my Linux machine and give it a try on that (I have Linux Mint LMDE4 version installed, with version 1.4 of QB64)

Also there is another area that may not be related to this and I like someone else to check it Because I’m now cross side trying to count all the open and closing brackets, but this error that happened I believe is a separate bug in QB64 in that there is not enough closing brackets in the statement generated below:

./../temp/main.txt:304:70: error: arithmetic on a pointer to void
qbs_set(*((qbs**)((__UDT_DEALER)+(8))),qbs_add(*((qbs**)(__UDT_DEALER+(8))),((qbs*)(((uint64*)(__ARRAY_STRING_DECK[0]))[array_check((*__INTEGER_DECKINDEX)-__ARRAY_STRING_DECK[4],__ARRAY_STRING_DECK[5])]))));
                                                         ~~~~~~~~~~~~^
George

Hey it's not one of those CHR$(0) at the end of the string things is it?
« Last Edit: July 09, 2020, 11:54:32 AM by George McGinn »

Offline bplus

  • Forum Resident
  • Posts: 4564
  • B+ nots
Re: Blackjack
« Reply #239 on: July 09, 2020, 11:58:35 AM »
Quote
Are there any specific coding for windows?

I think QB64 is mainly developed in Windows and ported to other OS, logical because QB was started by MS from GW Basic for DOS and/or something else in between.

So Shell stuff certainly is Windows only and anything that might involve a call to Windows API has to be translated to other OS if there is equivalent services.

So QB64 might run most trouble free with all commands in Windows.

But being portable to other OS is very important to The Team I think and endorse.
« Last Edit: July 09, 2020, 12:05:41 PM by bplus »