Author Topic: Gin Rummy Variations with Computer  (Read 7170 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Gin Rummy Variations with Computer
« on: May 04, 2020, 08:58:19 am »
Here is a very fast playing variation of Gin Rummy, I call Grim Rummy because "It's all about the Deadwood."

A brief help file is included in zip, very simple game against computer with 0 images or sound effects.

Code: QB64: [Select]
  1. _TITLE "Grim Rummy" 'b+ started 2020-04-26 post 2020-05-04  wo dev notes
  2.  
  3. DEFINT A-Z
  4. CONST xmax = 800, ymax = 400 'screen to be expanded when start card images
  5.  
  6. 'y Constants for locating and displaying
  7. CONST deckY = 128 ' deck status line
  8. CONST messageY = 160 '2 lines down from deckY
  9. CONST cardOffsetX = 20
  10. CONST cCardsOffsetY = 16
  11. CONST pCardsOffsetY = 288 ' now in pixels
  12. ' for current and future card images
  13. CONST cardW = 32 'pixels
  14. CONST cardH = 16 'pixels
  15. CONST black = &HFF000000, white = &HFFFFFFFF, bColor = &HFF220606
  16. 'some colors
  17.  
  18. clr(0) = &HFF00AA00 'mid green  clubs
  19. clr(1) = &HFF0088CC 'cyan       diamonds
  20. clr(2) = &HFFF80000 'red        hearts
  21. clr(3) = &HFF0000AA 'mid blue   spades
  22. ' card "s_vv" format color coded Suits 0 to 3 = C, D, H, S and _ to separate Suit from number: A, 1, 2, 3,... 10, J, Q, K
  23.  
  24. DIM SHARED deck$(0 TO 51), deckPointer AS INTEGER ' contains shuffled cards, deckpointer points to last card out
  25. DIM SHARED discard$, turn$ 'discard$ is card always face up that both players see
  26. DIM SHARED p$(12, 3), c$(12, 3)
  27. DIM SHARED pDeadPts, cDeadPts, pScore, cScore, laydown, showComputerHand ' p = human or c = computer
  28.  
  29. 'local variables for main loop of game round and laydown section
  30. DIM clicked 'human's button choice
  31. DIM card$ ' used often for passing back and forth with routines
  32. DIM message$ ' used for reporting results of laydown
  33. DIM deadDiff ' used for reporting results of laydown
  34. DIM pick$(2), pick2$(3)
  35. pick$(0) = "Quit": pick$(1) = "Draw Discard": pick$(2) = "Draw from Deck"
  36. pick2$(0) = "Quit": pick2$(1) = "Gin - all cards melded": pick2$(2) = "Knock - Deadwood <= 10": pick2$(3) = "Pass to Computer"
  37.  
  38. SCREEN _NEWIMAGE(xmax, ymax, 32)
  39. _SCREENMOVE 300, 150
  40. setupGame 'create deck, human is first up
  41. restart:
  42. resetRound
  43.     IF turn$ = "p" THEN 'player's turn
  44.         clicked = getButtonNumberChoice%(pick$())
  45.         IF clicked = 0 THEN
  46.             SYSTEM
  47.         ELSEIF clicked = 1 THEN '      Human draws discard
  48.             addCard p$(), discard$ '   put the discard into the humans hand
  49.             discard$ = "" '            show the discard missing because in human hand
  50.         ELSEIF clicked = 2 THEN '      Human draws from deck if there are enough cards
  51.             IF 52 - deckPointer < 2 THEN laydown = 5: GOTO skip ELSE addCard p$(), dealCard$
  52.         END IF
  53.         updateStatus '                 display all this
  54.         card$ = getDiscardClick$ '     get human's discard
  55.         removeCard p$(), card$ '       take this card out of human hand
  56.         discard$ = card$ '             put into discard catagory
  57.         updateStatus '                 show the changes
  58.         clicked = getButtonNumberChoice%(pick2$())
  59.         SELECT CASE clicked
  60.             CASE 0: SYSTEM ' quit
  61.             CASE 1: laydown = 1 ' Gin
  62.             CASE 2: laydown = 2 ' Knock
  63.             CASE 3: turn$ = "c" ' pass
  64.         END SELECT
  65.     ELSEIF turn$ = "c" THEN '     computer's turn
  66.         card$ = discard$
  67.         cardDiscard card$ '       decision made here usu if deadwood is reduced by 10 points then yes
  68.         IF card$ = discard$ THEN 'computer passed on the discard by passing it back
  69.             'draw from the deck if there are enough cards remaining
  70.             IF 52 - deckPointer < 2 THEN laydown = 5: GOTO skip ELSE card$ = dealCard$
  71.             cardDiscard card$
  72.             discard$ = card$
  73.             updateStatus
  74.             yCP messageY, "Computer drew from Deck and discarded."
  75.             _DELAY 2
  76.             IF cDeadPts = 0 THEN
  77.                 laydown = 3
  78.             ELSEIF cDeadPts <= 10 THEN
  79.                 laydown = 4
  80.             ELSE
  81.                 turn$ = "p"
  82.             END IF
  83.         ELSE 'computer kept discard
  84.             discard$ = card$
  85.             updateStatus
  86.             yCP messageY, "Computer kept Discard and discarded another."
  87.             _DELAY 2
  88.             IF cDeadPts = 0 THEN
  89.                 laydown = 3
  90.             ELSEIF cDeadPts <= 10 THEN
  91.                 laydown = 4
  92.             ELSE
  93.                 turn$ = "p"
  94.             END IF
  95.         END IF
  96.     END IF
  97.     skip:
  98. LOOP UNTIL laydown
  99.  
  100. ' if players points exceed 100 after laydown results they win
  101. showComputerHand = 1 'to show computer hand
  102. SELECT CASE laydown
  103.     CASE 1 ' human gin
  104.         IF pDeadPts <> 0 THEN
  105.             message$ = "Human lost 10 points calling Gin and not having it."
  106.             pScore = pScore - 10
  107.         ELSE
  108.             message$ = "Human: 25 points Gin + " + ts$(cDeadPts) + " Computer's Deadwood."
  109.             pScore = pScore + 25 + cDeadPts
  110.         END IF
  111.         turn$ = "c"
  112.     CASE 2, 4 ' human knock or computer
  113.         IF cDeadPts > pDeadPts THEN
  114.             deadDiff = cDeadPts - pDeadPts
  115.             message$ = "Human: 30 - " + ts$(52 - deckPointer) + " deck + " + ts$(deadDiff) + " deadwood = " + ts$(30 - (52 - deckPointer) + deadDiff)
  116.             pScore = pScore + 30 - (52 - deckPointer) + deadDiff: turn$ = "c"
  117.         ELSEIF pDeadPts > cDeadPts THEN
  118.             deadDiff = pDeadPts - cDeadPts
  119.             message$ = "Computer: 30 - " + ts$(52 - deckPointer) + " deck + " + ts$(deadDiff) + " deadwood = " + ts$(30 - (52 - deckPointer) + deadDiff)
  120.             cScore = cScore + 30 - (52 - deckPointer) + deadDiff: turn$ = "p"
  121.         ELSEIF cDeadPts = pDeadPts THEN
  122.             message$ = "A Knockout tie! no score was advanced this round." 'turn is whatever it was
  123.         END IF
  124.     CASE 3 ' computer gin
  125.         message$ = "Computer: 25 points Gin + " + ts$(pDeadPts) + " Human's deadwood."
  126.         cScore = cScore + 25 + pDeadPts: turn$ = "p"
  127.     CASE 5
  128.         message$ = "The deck has < 2 cards, this round is Null!" ' turn is same as was
  129. updateStatus
  130. IF cScore >= 100 OR pScore >= 100 THEN message$ = message$ + "  Winner!"
  131. yCP messageY, message$ + "  press any..."
  132. IF INSTR(message$, "Winner!") THEN pScore = 0: cScore = 0
  133. GOTO restart
  134.  
  135. SUB setupGame 'Intro to this version, create deck of cards, set turn to human
  136.     DIM suit, value, i, bn
  137.     DIM m$(2): m$(0) = "Quit": m$(1) = "Load Grim Rummy.txt": m$(2) = "Lets play Grim Rummy!"
  138.     COLOR white, bColor 'once and for all on bColor
  139.     CLS
  140.     yCP 160, "'Load Grim Rummy.txt' Button will call up"
  141.     yCP 180, "'Grim Rummy Variation.txt' into your favorite editor"
  142.     yCP 200, "for you to refer to now or during play of Grim Rummy."
  143.     yCP 300, "Cool now the coder of this game can edit es notes"
  144.     yCP 320, "as e develops the game!"
  145.     bn = getButtonNumberChoice(m$())
  146.     IF bn = 0 THEN SYSTEM
  147.     IF bn = 1 THEN SHELL _DONTWAIT "Grim Rummy Variation.txt" 'oh nice! don't have to load and show!
  148.     IF deck$(0) = "" THEN 'create deck
  149.         FOR suit = 1 TO 4
  150.             FOR value = 1 TO 13
  151.                 deck$(i) = MID$("CDHS", suit, 1) + "_" + MID$("A 2 3 4 5 6 7 8 9 10J Q K ", 2 * (value - 1) + 1, 2) 'Suit_Value
  152.                 i = i + 1
  153.             NEXT
  154.         NEXT
  155.     END IF
  156.     turn$ = "p" 'player always starts game
  157.  
  158. SUB resetRound
  159.     ERASE p$, c$ 'clear hands  and rest the other globals
  160.     pDeadPts = 0: cDeadPts = 0: laydown = 0: showComputerHand = 0 '< 1 for debug or cheating
  161.     DIM i, r 'locals
  162.     FOR i = 51 TO 1 STEP -1 'shuffle deck
  163.         r = INT(RND * i)
  164.         SWAP deck$(i), deck$(r)
  165.     NEXT
  166.     deckPointer = 0 'deal some cards out
  167.     FOR i = 1 TO 10
  168.         addCard p$(), dealCard$
  169.         addCard c$(), dealCard$
  170.     NEXT
  171.     discard$ = deck$(deckPointer): deckPointer = deckPointer + 1 'set first discard$
  172.     updateStatus
  173.  
  174. SUB updateStatus
  175.     COLOR white, bColor
  176.     CLS
  177.     show "p" '                    show updates pDeadPts  cardDiscard updates cDeadPts
  178.     IF showComputerHand THEN show "c"
  179.     COLOR clr(INSTR("CDHS", LEFT$(discard$, 1)) - 1) 'display discard$ in it's suit color
  180.     _PRINTSTRING (411, deckY), discard$
  181.     COLOR white
  182.     yCP deckY, "Cards remaining: " + ts$(52 - deckPointer) + "  Discard: "
  183.     yCP deckY + 128, "Human: " + ts$(pScore) + "   Computer: " + ts$(cScore)
  184.  
  185. SUB show (player$) 'players hand is displayed 5 lines above bottom of screen in 4 lines
  186.     DIM r, c, d$
  187.     FOR r = 0 TO 3
  188.         COLOR clr(r)
  189.         FOR c = 0 TO 12
  190.             IF player$ = "p" THEN
  191.                 IF p$(c, r) = "" THEN
  192.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + pCardsOffsetY), "   "
  193.                 ELSE
  194.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + pCardsOffsetY), p$(c, r)
  195.                 END IF
  196.  
  197.             ELSE
  198.                 IF c$(c, r) = "" THEN
  199.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + cCardsOffsetY), "   "
  200.                 ELSE
  201.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + cCardsOffsetY), c$(c, r)
  202.                 END IF
  203.             END IF
  204.         NEXT
  205.     NEXT
  206.     COLOR &HFFCCDD00 'dark brown sort a like deadwood?
  207.     IF player$ = "p" THEN
  208.         pDeadPts = deadwood(p$(), d$)
  209.         yCP 80 + pCardsOffsetY, ts$(LEN(d$) \ 5) + " Deadwood Cards = " + ts$(pDeadPts) + " points"
  210.     ELSE
  211.         cDeadPts = deadwood(c$(), d$)
  212.         yCP 80 + cCardsOffsetY, ts$(LEN(d$) \ 5) + " Deadwood Cards = " + ts$(cDeadPts) + " points"
  213.     END IF
  214.     COLOR white
  215.  
  216. 'player reviews card rec'd and discards through mouse click
  217. FUNCTION getDiscardClick$ 'this has to be reworked
  218.     DIM oldMouse, mCol, mRow, mb
  219.     yCP messageY, "Click Discard"
  220.     oldMouse = -1
  221.     DO
  222.         WHILE _MOUSEINPUT: WEND 'convert mouse positions to array row and col
  223.         mCol = INT((_MOUSEX - cardOffsetX) / (cardW + 8) + .25)
  224.         mRow = INT((_MOUSEY - pCardsOffsetY) / (cardH))
  225.         mb = _MOUSEBUTTON(1)
  226.         'LOCATE 13, 2: PRINT mCol, mRow
  227.         IF mb AND oldMouse = 0 THEN
  228.             IF mRow >= 0 AND mRow <= 3 THEN
  229.                 IF mCol >= 0 AND mCol <= 12 THEN
  230.                     IF p$(mCol, mRow) <> "" THEN getDiscardClick$ = p$(mCol, mRow): EXIT FUNCTION
  231.                 END IF
  232.             END IF
  233.         END IF
  234.         oldMouse = mb
  235.         _LIMIT 200
  236.     LOOP
  237.  
  238. 'computer gets card and discards through this AI
  239. SUB cardDiscard (card$) 'for AI
  240.     DIM ci, r, c, low, d$, saveI, i
  241.     DIM cds$(1 TO 11), dw(1 TO 11)
  242.     ci = 1
  243.     FOR r = 0 TO 3
  244.         FOR c = 0 TO 12
  245.             IF c$(c, r) <> "" THEN cds$(ci) = c$(c, r): ci = ci + 1
  246.         NEXT
  247.     NEXT
  248.     cds$(11) = card$
  249.     low = 200
  250.     dw(11) = deadwood(c$(), d$)
  251.     IF dw(11) < low THEN saveI = 11: low = dw(11)
  252.     addCard c$(), card$
  253.     FOR i = 1 TO 10
  254.         removeCard c$(), cds$(i)
  255.         dw(i) = deadwood(c$(), d$)
  256.         IF dw(i) < low THEN saveI = i: low = dw(i)
  257.         addCard c$(), cds$(i)
  258.     NEXT
  259.     ' 11 cards are in c$()
  260.     IF card$ = discard$ THEN 'we dont want to take discard unless it makes significant difference
  261.         IF dw(11) - low > 10 THEN 'take discard$ 'it's already in hand
  262.             removeCard c$(), cds$(saveI)
  263.             card$ = cds$(saveI) 'discard
  264.         ELSE 'don't take discard$
  265.             removeCard c$(), card$ 'reject the discard
  266.         END IF
  267.     ELSE 'have to remove something?
  268.         removeCard c$(), cds$(saveI) ' remove from c$() to get it to 10
  269.         card$ = cds$(saveI) ' pass it back in card variable
  270.     END IF
  271.     cDeadPts = deadwood(c$(), d$)
  272.  
  273. ' This is key to Gin Rummy Game. This is a C for crosswords version of Deadwood.
  274. ' Crosswords means a card can be used both in a group set and straight set in making meld.
  275. ' Since Grim Rummy is based on Deadwood points there is no extra credit for using a card twice,
  276. ' it just makes it easier to clear deadwood for players and calculate deadwood points for coder.
  277. FUNCTION deadwood (a$(), dead$)
  278.     REDIM sSets$(0), gSets$(0) 'although 0 based these sets have first element at 1 as they are added in by sAppend SUB
  279.     DIM r, c, quit, cStart, cEnd, set$, ci, count 'finding meld sets
  280.  
  281.     ' checking for card intersets between gSet and sSet
  282.     DIM si, gi '           index for each of these arrays of sets
  283.     DIM nsCards, ngCards ' number of cards in the single set
  284.     DIM place '            where in set a card is
  285.  
  286.     'sets with card intersects removed now time to count deadwood
  287.     DIM nCards, cardI, n 'card Count, card index and another index
  288.  
  289.     FOR r = 0 TO 3 'look for straights
  290.         c = 0: quit = 0
  291.         DO WHILE quit = 0 AND c < 13
  292.             WHILE a$(c, r) = ""
  293.                 c = c + 1
  294.                 IF c > 11 THEN quit = 1: EXIT WHILE
  295.             WEND
  296.             IF c < 11 THEN
  297.                 cStart = c
  298.                 WHILE a$(c, r) <> ""
  299.                     c = c + 1
  300.                     IF c = 13 THEN quit = 1: EXIT WHILE
  301.                 WEND
  302.                 IF c = 13 THEN cEnd = 12 ELSE cEnd = c - 1
  303.                 IF cEnd - cStart + 1 > 2 THEN
  304.                     set$ = ""
  305.                     FOR ci = cStart TO cEnd
  306.                         set$ = set$ + a$(ci, r)
  307.                     NEXT
  308.                     sAppend sSets$(), set$
  309.                 END IF
  310.                 IF c > 11 THEN quit = 1
  311.             ELSE
  312.                 EXIT DO
  313.             END IF
  314.         LOOP
  315.     NEXT
  316.     FOR c = 0 TO 12 ' now for the groups
  317.         count = 0
  318.         FOR ci = 0 TO 3
  319.             IF a$(c, ci) <> "" THEN count = count + 1
  320.         NEXT
  321.         IF count > 2 THEN
  322.             set$ = ""
  323.             FOR ci = 0 TO 3
  324.                 IF a$(c, ci) <> "" THEN set$ = set$ + a$(c, ci)
  325.             NEXT
  326.             sAppend gSets$(), set$
  327.         END IF
  328.     NEXT
  329.     ' now it's time to calculate the deadwood number ======================================
  330.     REDIM cards$(0) '<<< why is this at 11? hack fix for cardDiscard call
  331.     FOR r = 0 TO 3
  332.         FOR c = 0 TO 12
  333.             IF a$(c, r) <> "" THEN sAppend cards$(), a$(c, r)
  334.         NEXT
  335.     NEXT
  336.     nCards = UBOUND(cards$)
  337.     FOR si = 1 TO UBOUND(sSets$)
  338.         IF sSets$(si) <> "" THEN
  339.             nsCards = LEN(sSets$(si)) / 4
  340.             FOR cardI = 1 TO nsCards
  341.                 FOR n = 1 TO nCards
  342.                     IF cards$(n) = MID$(sSets$(si), cardI * 4 - 3, 4) THEN cards$(n) = ""
  343.                 NEXT
  344.             NEXT
  345.         END IF
  346.     NEXT
  347.     FOR gi = 1 TO UBOUND(gSets$)
  348.         IF gSets$(gi) <> "" THEN
  349.             ngCards = LEN(gSets$(gi)) / 4
  350.             FOR cardI = 1 TO ngCards
  351.                 FOR n = 1 TO nCards
  352.                     IF cards$(n) = MID$(gSets$(gi), cardI * 4 - 3, 4) THEN cards$(n) = ""
  353.                 NEXT
  354.             NEXT
  355.         END IF
  356.     NEXT
  357.     'ok melded cards cleaned out
  358.     dead$ = "": count = 0
  359.     FOR n = 1 TO nCards
  360.         IF cards$(n) <> "" THEN
  361.             dead$ = dead$ + " " + cards$(n)
  362.             place = INSTR("A 2 3 4 5 6 7 8 9 10J Q K ", MID$(cards$(n), 3, 2))
  363.             IF (place + 1) / 2 < 10 THEN count = count + (place + 1) / 2 ELSE count = count + 10
  364.         END IF
  365.     NEXT
  366.     deadwood = count
  367.  
  368. FUNCTION dealCard$
  369.     dealCard$ = deck$(deckPointer): deckPointer = deckPointer + 1
  370.  
  371. SUB addCard (a$(), card$)
  372.     DIM r, c
  373.     r = INSTR("CDHS", LEFT$(card$, 1)) - 1: c = (INSTR("A 2 3 4 5 6 7 8 9 10J Q K ", MID$(card$, 3, 2)) - 1) / 2
  374.     a$(c, r) = card$
  375.  
  376. SUB removeCard (a$(), card$)
  377.     DIM r, c
  378.     r = INSTR("CDHS", LEFT$(card$, 1)) - 1: c = (INSTR("A 2 3 4 5 6 7 8 9 10J Q K ", MID$(card$, 3, 2)) - 1) / 2
  379.     a$(c, r) = ""
  380.  
  381. 'modified for this app
  382. SUB yCP (y, s$) 'for xmax pixel wide graphics screen Center Print at pixel y row
  383.     _PRINTSTRING ((_WIDTH - 220 - LEN(s$) * 8) / 2, y), s$
  384.  
  385. 'this sub uses drwBtn
  386. FUNCTION getButtonNumberChoice% (choice$()) 'developed for this app but likely can use as is elsewhere
  387.     DIM ub, b, oldmouse, mx, my, mb
  388.  
  389.     ub = UBOUND(choice$)
  390.     FOR b = 0 TO ub
  391.         drwBtn xmax - 210, b * 60 + 90, choice$(b)
  392.     NEXT
  393.     oldmouse = -1
  394.     DO
  395.         WHILE _MOUSEINPUT: WEND
  396.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  397.         IF mb AND oldmouse = 0 THEN
  398.             IF mx > xmax - 210 AND mx <= xmax - 10 THEN
  399.                 FOR b = 0 TO ub
  400.                     IF my >= b * 60 + 90 AND my <= b * 60 + 140 THEN
  401.                         LINE (xmax - 210, 0)-(xmax, ymax), bColor, BF
  402.                         getButtonNumberChoice% = b: EXIT FUNCTION
  403.                     END IF
  404.                 NEXT
  405.                 BEEP
  406.             ELSE
  407.                 BEEP
  408.             END IF
  409.         END IF
  410.         oldmouse = _MOUSEBUTTON(1)
  411.         _LIMIT 200
  412.     LOOP
  413.  
  414. SUB drwBtn (x, y, s$) '200 x 50
  415.     DIM th, tw, gray~&
  416.     th = 16: tw = 8 * LEN(s$): gray~& = _RGB32(190, 190, 190)
  417.     LINE (x, y)-STEP(204, 54), _RGB32(0, 0, 0), BF
  418.     LINE (x - 2, y - 2)-STEP(201, 51), _RGB32(255, 255, 255), BF
  419.     LINE (x, y)-STEP(200, 50), gray~&, BF
  420.     COLOR _RGB32(0, 0, 0), gray~&
  421.     _PRINTSTRING (x + 100 - 4 * LEN(s$), y + 17), s$
  422.     COLOR white, bColor
  423.  
  424. SUB sAppend (arr() AS STRING, addItem$)
  425.     REDIM _PRESERVE arr(LBOUND(arr) TO UBOUND(arr) + 1) AS STRING
  426.     arr(UBOUND(arr)) = addItem$
  427.  
  428. FUNCTION ts$ (number)
  429.     ts$ = _TRIM$(STR$(number))
  430.  

Until I can figure out how to code it otherwise, a card may be used both in a Straight set (3 or more sequence of same suit) and a Group set (3 or 4 of a kind).

It's quite a challenge to figure optimum Deadwood of 10 or 11 cards when, like in a regular game of Gin Rummy, a card may be used either in a Straight set or a Group set but not both. I've been at it for a few days now and haven't figured it out yet. Maybe one of you guys can get it?

The zip is just the source (above) and a helper txt file.
* Grim Rummy v1.zip (Filesize: 8.06 KB, Downloads: 193)
« Last Edit: May 04, 2020, 03:14:21 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #1 on: October 12, 2020, 12:12:49 am »
I have finally found the way to optimize a Gin Rummy hand and have revised Grim Rummy with the new code. It plays very well. Now you can use a card for a Straight set or a Group set but not both.

Grin Rummy variation coming next but might need even more AI.



* Grim Rummy 2020-10 Update.zip (Filesize: 13.67 KB, Downloads: 149)

Offline johnno56

  • Forum Resident
  • Posts: 1270
  • Live long and prosper.
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #2 on: October 12, 2020, 02:34:21 am »
Another card game?... A glutton for punishment... lol

As I have never played this game before, I seriously doubt, that I can help you with the coding... If you ever get to the point of adding sound and graphics, as long as it's not too difficult, let me know...
Logic is the beginning of wisdom.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #3 on: October 12, 2020, 10:26:45 am »
Another card game?... A glutton for punishment... lol

As I have never played this game before, I seriously doubt, that I can help you with the coding... If you ever get to the point of adding sound and graphics, as long as it's not too difficult, let me know...

The idea behind all Gin Games is to match cards into sets, either a Group Set = all of a kind like 3 Jacks or 4 Nines or a Straight Set eg, Ace, 2, 3 of Spades or 5, 6, 7, 8, 9 of Harts... a sequence of of same suit. Minimum 3 cards to a set. So for group sets, the maximum can be 4 of a kind but theoretically a Gin hand can be one big Straight set! (Should maybe be extra points for that, hmm... )

Meld are all the cards matched to a set or the Points of those cards, Ace counts only as 1 and Face cards are 10 points the rest are their number value.

Now in my own invention, Grim Rummy Variation,  the only thing that matters is Deadwood. Deadwood are the cards or their point value of cards not matched into sets. When you have 10 or less points in Deadwood you "Knock" and player with least Deadwood Points wins the difference in Deadwood points PLUS 30 - number of cards remaining in deck (this almost guarantees at least 10 points won in a round).

The focus on Deadwood only seems kind of Grim hence the name of this variation.

Now the next Variation of my invention is Grin Rummy. The complete opposite of Grim it focuses entirely on Meld, Deadwood only matters for "Knocking" or calling Gin = 0 Deadwood cards or Points. I haven't worked out details for game scoring yet because I hadn't had a decent Gin hand Optimizer until Saturday.

Funny Saturday morning I woke up early and sketched out a new and different plan of attack for building the Optimizer code. It wasn't quite as easy as originally imagined but it turned out far more elegant than a rules or conditions based system that was so complex you get lost in handling all the possible cases that could happen but most aren't likely, like having to split a big Straight set without loosing more than 1 card for meld.

You know you can put together only 3 sets maximum for Gin Rummy yet the code it takes to establish the best 3 sets is quite involved! And cards that intersect both a Group set and a Straight set, they have to go in one or the other; trouble is all the combinations of which set the intersecting card should go. So finally Saturday I put together code that tests each combination and saves the first one that uses the most cards or has the highest points.
« Last Edit: October 12, 2020, 10:38:40 am by bplus »

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #4 on: October 12, 2020, 06:36:26 pm »
I've always wanted to recreate Intellivision's "Royal Dealer" version of Gin Rummy. Also has Hearts, Crazy 8s and one more thats not poppin in at the moment.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #5 on: October 12, 2020, 07:06:19 pm »
I've always wanted to recreate Intellivision's "Royal Dealer" version of Gin Rummy. Also has Hearts, Crazy 8s and one more thats not poppin in at the moment.

Rummy is #4, these days when it's not poppin try popping Google :) I had never even heard of Royal Dealer:
http://www.thevgatv.com/resources/Intellivision/Royal-Dealer-Intv.pdf

@johnno56  wanna try aliens for this?

 
image_2020-10-12_190607.png

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #6 on: October 12, 2020, 07:30:17 pm »
I even have the graphics already sprite sheet-ed, from a bit of work I did some time ago on it. Yeah I forgot it had Rummy and Gin Rummy.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #7 on: October 12, 2020, 07:43:37 pm »
@Cobalt

I just watched this:


This guys says straights are limited to 3-4 cards in Gin Rummy, say it aint so, say this guy has his rules screwed up.

I am allowing Straights of any length including 10 cards!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #8 on: October 12, 2020, 07:53:16 pm »
I don't know... I think I have had full straight wins before. Its been a while since I've played so I might need to give it a go again, granted getting a full straight win is not easy to pull off any how.
Granted after becoming radioactive I only have a half-life!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #9 on: October 12, 2020, 09:59:13 pm »
Yeah you can get more than straights of 3 or 4, haven't gotten to 7 or more yet but here is a double 5 straight hand that won a round.

So yeah that dude is wack.

and I had the 9 of spades that discarded when I called gin, so I could have had 6 if I would have discarded a diamond instead.
double5straight.jpg
* double5straight.jpg (Filesize: 44.28 KB, Dimensions: 800x600, Views: 183)
« Last Edit: October 12, 2020, 10:00:23 pm by Cobalt »
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #10 on: October 13, 2020, 12:02:07 am »
Ah good! Glad to see Cobalt :) I've seen a few 7 Straights myself.

Here is Grin Rummy I had going months ago. Tonight I changed look and play of game a bit. It is allowing double use of a card both in a Straight set and a Group set. For Grin Rummy, this works out great for getting some really massive Melds built up if you can only beat the computer to GRIN :) In this game you have to meld all cards before computer melds it's hand to get your meld points scored, play is to 500 points.

Code: QB64: [Select]
  1. _TITLE "Grin Rummy" 'b+ started 2020-04-28  revised 2020-10-12
  2. ' complete opposite of Grim Rummy
  3.  
  4. DEFINT A-Z
  5. CONST xmax = 800, ymax = 400 'screen to be expanded when start card images
  6.  
  7. 'y Constants for locating and displaying
  8. CONST deckY = 128 ' deck status line
  9. CONST messageY = 160 '2 lines down from deckY
  10. CONST cardOffsetX = 20
  11. CONST cCardsOffsetY = 16
  12. CONST pCardsOffsetY = 288 ' now in pixels
  13. ' for current and future card images
  14. CONST cardW = 32 'pixels
  15. CONST cardH = 16 'pixels
  16. CONST black = &HFF000000, white = &HFFFFFFFF, bColor = &HFF5566FF
  17. 'some colors
  18.  
  19. clr(0) = &HFF006644 'mid green  clubs
  20. clr(1) = &HFF00FF44 'cyan       diamonds
  21. clr(2) = &HFFCC3300 'red        hearts
  22. clr(3) = &HFF880099 'mid blue   spades
  23. ' card "##s" space or # for 10, # or Letter for digit/Face  card symbol
  24.  
  25. DIM SHARED deck$(0 TO 51), deckPointer AS INTEGER ' contains shuffled cards, deckpointer points to last card out
  26. DIM SHARED discard$, turn$ 'discard$ is card always face up that both players see
  27. DIM SHARED p$(12, 3), c$(12, 3)
  28. DIM SHARED pMeldPts, cMeldPts, pND, cND, pScore, cScore, laydown, showComputerHand ' p = human or c = computer
  29. DIM SHARED pick1$(2), pick2$(2) 'human player's choices at each play
  30. pick1$(0) = "Quit": pick1$(1) = "Draw Discard": pick1$(2) = "Draw from Deck"
  31. pick2$(0) = "Quit": pick2$(1) = "Grin - all cards melded": pick2$(2) = "Pass to Computer"
  32.  
  33. 'local variables for main loop of game round and laydown section
  34. DIM clicked 'human's button choice
  35. DIM card$ ' used often for passing back and forth with routines
  36. DIM message$ ' used for reporting results of laydown
  37. DIM meld ' used for reporting results of laydown
  38. DIM oldMouse
  39.  
  40. SCREEN _NEWIMAGE(xmax, ymax, 32)
  41. _SCREENMOVE 300, 150
  42. setupGame 'create deck, human is first up
  43. restart:
  44. resetRound
  45.     IF turn$ = "p" THEN 'player's turn
  46.         clicked = getButtonNumberChoice%(pick1$())
  47.         IF clicked = 0 THEN ' human wants to quit
  48.             SYSTEM
  49.         ELSEIF clicked = 1 THEN '            Human draws discard
  50.             addCard p$(), discard$ '   put the discard into the humans hand
  51.             discard$ = "" '            show the discard missing because in human hand
  52.         ELSEIF clicked = 2 THEN ' Human  Draws from deck if enough cards left
  53.             IF 52 - deckPointer < 2 THEN laydown = 5: GOTO skip ELSE addCard p$(), dealCard$ ' place next deck card into humans hand
  54.         END IF
  55.         updateStatus '             display all this
  56.         card$ = getDiscardClick$ ' get human's discard
  57.         removeCard p$(), card$ '   take this card out of human hand
  58.         discard$ = card$ '         put into discard catagory
  59.         updateStatus '             show the changes
  60.         IF pND = 0 THEN laydown = 1 ELSE turn$ = "c"
  61.  
  62.     ELSEIF turn$ = "c" THEN 'computer's turn
  63.         card$ = discard$
  64.         cardDiscard card$ '
  65.         IF card$ = discard$ THEN 'computer passed on the discard by passing it back
  66.             ' so draw from deck if not out of cards?
  67.             IF 52 - deckPointer < 2 THEN laydown = 5: GOTO skip ELSE card$ = dealCard$
  68.             cardDiscard card$
  69.             discard$ = card$
  70.             updateStatus
  71.             yCP messageY, "Computer drew from Deck and discarded."
  72.         ELSE 'computer kept discard
  73.             discard$ = card$
  74.             updateStatus
  75.             yCP messageY, "Computer kept Discard and discarded another."
  76.         END IF
  77.         _DELAY 2
  78.         IF cND = 0 THEN updateStatus: yCP messageY, "Grin": laydown = 3 ELSE turn$ = "p"
  79.     END IF
  80.     skip:
  81. LOOP UNTIL laydown
  82.  
  83. 'show computer's hand when not in debug mode
  84. 'remember the turn will go to loser of laydown
  85. ' if players points exceed 100 after laydown results they win
  86. showComputerHand = 1 'to show computer hand
  87. SELECT CASE laydown
  88.     IF pMeldPts > cMeldPts THEN meld = pMeldPts ELSE meld = cMeldPts
  89.     CASE 1 ' human gin
  90.         message$ = "Human: " + ts$(meld) + " has been added to your score."
  91.         pScore = pScore + meld
  92.         turn$ = "c"
  93.     CASE 3 ' computer gin
  94.         drwBtn xmax - 210, 200, "GRIN :)"
  95.         message$ = "Computer: " + ts$(meld) + " has been added to your score."
  96.         cScore = cScore + meld
  97.         turn$ = "p"
  98.     CASE 5
  99.         message$ = "The deck has < 2 cards, this round is Null!" ' turn is same as was
  100. updateStatus
  101. IF pND = 0 THEN
  102.     drwBtn xmax - 210, ymax - 100, "GRIN :)"
  103. ELSEIF cND = 0 THEN
  104.     drwBtn xmax - 210, 50, "GRIN :)"
  105. IF cScore >= 500 OR pScore >= 500 THEN message$ = message$ + "  Winner!"
  106. yCP messageY, message$ + "  click..."
  107. oldMouse = -1
  108.     ' mb = _MOUSEBUTTON(1)
  109.     IF _MOUSEBUTTON(1) AND oldMouse = 0 THEN
  110.         LINE (xmax - 210, 0)-(xmax, ymax), bColor, BF
  111.         IF INSTR(message$, "Winner!") THEN pScore = 0: cScore = 0
  112.         EXIT DO
  113.     END IF
  114.     oldMouse = _MOUSEBUTTON(1)
  115. GOTO restart
  116.  
  117. SUB setupGame 'Intro to this version, create deck of cards, set turn to human
  118.     DIM suit, value, i, bn
  119.     DIM m$(2): m$(0) = "Quit": m$(1) = "Load .txt on Grin Rummy": m$(2) = "Let's play Grin Rummy"
  120.     COLOR white, bColor 'once and for all on bColor
  121.     CLS
  122.     yCP 160, "'Load .txt of Grin Rummy' Button will call up"
  123.     yCP 180, "'Grin Rummy Variation.txt' into your favorite editor"
  124.     yCP 200, "for you to refer to now or during play of Grin Rummy."
  125.  
  126.     yCP 300, "Cool now the coder of this game can edit es notes"
  127.     yCP 320, "as e develops the game!"
  128.  
  129.     bn = getButtonNumberChoice(m$())
  130.     IF bn = 0 THEN SYSTEM
  131.     IF bn = 1 THEN SHELL _DONTWAIT "Grin Rummy Variation.txt" 'oh nice! don't have to load and show!
  132.     IF deck$(0) = "" THEN 'create deck
  133.         FOR suit = 1 TO 4
  134.             FOR value = 1 TO 13
  135.                 deck$(i) = MID$(" A 2 3 4 5 6 7 8 910 J Q K", 2 * (value - 1) + 1, 2) + MID$(CHR$(3) + CHR$(4) + CHR$(5) + CHR$(6), suit, 1) 'Suit_Value
  136.                 i = i + 1
  137.             NEXT
  138.         NEXT
  139.     END IF
  140.     turn$ = "p" 'player always starts game
  141.  
  142. SUB resetRound
  143.     DIM i, r 'locals, wow not many for all the code here
  144.     ERASE p$, c$ 'clear hands  13 cols and 4 rows arrays  copy of ordered deck
  145.     pMeldPts = 0: cMeldPts = 0: laydown = 0: showComputerHand = 0 '< 1 for debug or cheating
  146.  
  147.     'shuffle deck
  148.     FOR i = 51 TO 1 STEP -1
  149.         r = INT(RND * i)
  150.         SWAP deck$(i), deck$(r)
  151.     NEXT
  152.     deckPointer = 0 'deal some cards out
  153.     FOR i = 1 TO 10
  154.         addCard p$(), dealCard$
  155.         addCard c$(), dealCard$
  156.     NEXT
  157.     discard$ = deck$(deckPointer): deckPointer = deckPointer + 1 'set first discard$
  158.     updateStatus
  159.  
  160. SUB updateStatus
  161.     COLOR white, bColor
  162.     CLS
  163.     show "p" '                    show updates pMeldPts  cardDiscard updates cMeldPts
  164.     IF showComputerHand THEN show "c"
  165.     COLOR clr(INSTR(CHR$(3) + CHR$(4) + CHR$(5) + CHR$(6), RIGHT$(discard$, 1)) - 1) 'display discard$ in it's suit color
  166.     _PRINTSTRING (411, deckY), discard$
  167.     COLOR white
  168.     yCP deckY, "Cards remaining: " + ts$(52 - deckPointer) + "  Discard: "
  169.     yCP deckY + 128, "Human: " + ts$(pScore) + "   Computer: " + ts$(cScore)
  170.  
  171. SUB show (player$) 'players hand is displayed 5 lines above bottom of screen in 4 lines
  172.     DIM r, c, nD
  173.     FOR r = 0 TO 3
  174.         COLOR clr(r)
  175.         FOR c = 0 TO 12
  176.             IF player$ = "p" THEN
  177.                 IF p$(c, r) = "" THEN
  178.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + pCardsOffsetY), "   "
  179.                 ELSE
  180.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + pCardsOffsetY), p$(c, r)
  181.                 END IF
  182.  
  183.             ELSE
  184.                 IF c$(c, r) = "" THEN
  185.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + cCardsOffsetY), "   "
  186.                 ELSE
  187.                     _PRINTSTRING (c * 40 + cardOffsetX, r * 16 + cCardsOffsetY), c$(c, r)
  188.                 END IF
  189.             END IF
  190.         NEXT
  191.     NEXT
  192.     COLOR &HFFFFFF00 'dark brown sort a like cMeldTotal?
  193.     IF player$ = "p" THEN
  194.         pMeldPts = cMeldTotal(p$(), nD): pND = nD
  195.         yCP 80 + pCardsOffsetY, "  Player:  Meld = " + ts$(pMeldPts) + "    Deadwood Cards = " + ts$(pND)
  196.     ELSE
  197.         cMeldPts = cMeldTotal(c$(), nD): cND = nD
  198.         yCP 80 + cCardsOffsetY, "Computer:  Meld = " + ts$(cMeldPts) + "    Deadwood Cards = " + ts$(cND)
  199.     END IF
  200.     COLOR white
  201.  
  202. 'player reviews card rec'd and discards through mouse click
  203. FUNCTION getDiscardClick$ 'this has to be reworked
  204.     DIM oldMouse, mCol, mRow, mb
  205.     yCP messageY, "Click Discard"
  206.     oldMouse = -1
  207.     DO
  208.         WHILE _MOUSEINPUT: WEND 'convert mouse positions to array row and col
  209.         mCol = INT((_MOUSEX - cardOffsetX) / (cardW + 8) + .25)
  210.         mRow = INT((_MOUSEY - pCardsOffsetY) / (cardH))
  211.         mb = _MOUSEBUTTON(1)
  212.         'LOCATE 13, 2: PRINT mCol, mRow
  213.         IF mb AND oldMouse = 0 THEN
  214.             IF mRow >= 0 AND mRow <= 3 THEN
  215.                 IF mCol >= 0 AND mCol <= 12 THEN
  216.                     IF p$(mCol, mRow) <> "" THEN getDiscardClick$ = p$(mCol, mRow): EXIT FUNCTION
  217.                 END IF
  218.             END IF
  219.         END IF
  220.         oldMouse = mb
  221.         _LIMIT 200
  222.     LOOP
  223.  
  224. 'computer gets card and discards through this AI
  225. SUB cardDiscard (card$) 'for AI
  226.     DIM ci, r, c, dwStart, dwlow, nD, saveI, i
  227.     DIM cds$(1 TO 11), meld(1 TO 11)
  228.     ci = 1
  229.     FOR r = 0 TO 3
  230.         FOR c = 0 TO 12
  231.             IF c$(c, r) <> "" THEN cds$(ci) = c$(c, r): ci = ci + 1
  232.         NEXT
  233.     NEXT
  234.     cds$(11) = card$
  235.     meld(11) = cMeldTotal(c$(), nD): dwlow = nD: saveI = 11: dwStart = nD 'the hand before considering the new card
  236.     addCard c$(), card$
  237.     FOR i = 1 TO 10 'remove each card in hand and check dwLow and meld
  238.         removeCard c$(), cds$(i)
  239.         meld(i) = cMeldTotal(c$(), nD)
  240.         IF nD < dwlow THEN 'ah less dead wood it's a keeper
  241.             saveI = i: dwlow = nD
  242.         ELSEIF nD = dwlow THEN ' ah same amount of deadwood but more meld so keep this
  243.             IF meld(i) > meld(saveI) THEN saveI = i
  244.         END IF
  245.         addCard c$(), cds$(i) 'restore card back to 11
  246.     NEXT
  247.  
  248.     ' 11 cards are in c$()
  249.     IF card$ = discard$ THEN 'we dont want to take discard unless it makes significant difference
  250.         IF dwlow < dwStart THEN 'take discard$ 'it's already in hand
  251.             removeCard c$(), cds$(saveI)
  252.             card$ = cds$(saveI) 'discard
  253.         ELSE 'don't take discard$
  254.             removeCard c$(), card$ 'reject the discard
  255.         END IF
  256.     ELSE 'have to remove something?
  257.         removeCard c$(), cds$(saveI) ' remove from c$() to get it to 10
  258.         card$ = cds$(saveI) ' pass it back in card variable
  259.     END IF
  260.     cMeldPts = cMeldTotal(c$(), nD) 'update current cMeldPts
  261.     cND = nD
  262.  
  263. ' This is key to Grin Rummy Game. This is a C for crosswords version of cMeldTotal.
  264. ' Crosswords means a card can be used both in a group set and straight set in making meld.
  265. ' Since Grin Rummy is based on cMeldTotal points there is extra credit for using a card twice!
  266. FUNCTION cMeldTotal% (a$(), nDeadCards) 'return Meld Point Total and nDeadCards
  267.     REDIM sSets$(0), gSets$(0) 'although 0 based these sets have first element at 1 as they are added in by sAppend SUB
  268.     DIM r, c, quit, cStart, cEnd, set$, ci, count 'finding meld sets
  269.     REDIM cards$(0) 'make a list of cards while at it (in counting Group sets block)
  270.     ' checking for card intersets between gSet and sSet
  271.     DIM si, gi '           index for each of these arrays of sets
  272.     DIM nsCards, ngCards ' number of cards in the single set
  273.  
  274.     'sets with card intersects removed now time to count cMeldTotal
  275.     DIM nCards, cardI, n 'card Count, card index and another index
  276.  
  277.     FOR r = 0 TO 3 'look for straights
  278.         c = 0: quit = 0
  279.         DO WHILE quit = 0 AND c < 13
  280.             WHILE a$(c, r) = ""
  281.                 c = c + 1
  282.                 IF c > 11 THEN quit = 1: EXIT WHILE
  283.             WEND
  284.             IF c < 11 THEN
  285.                 cStart = c
  286.                 WHILE a$(c, r) <> ""
  287.                     c = c + 1
  288.                     IF c = 13 THEN quit = 1: EXIT WHILE
  289.                 WEND
  290.                 IF c = 13 THEN cEnd = 12 ELSE cEnd = c - 1
  291.                 IF cEnd - cStart + 1 > 2 THEN
  292.                     set$ = ""
  293.                     FOR ci = cStart TO cEnd
  294.                         set$ = set$ + a$(ci, r)
  295.                         cMeldTotal% = cMeldTotal% + points(a$(ci, r))
  296.                     NEXT
  297.                     sAppend sSets$(), set$
  298.                 END IF
  299.                 IF c > 11 THEN quit = 1
  300.             ELSE
  301.                 EXIT DO
  302.             END IF
  303.         LOOP
  304.     NEXT
  305.     FOR c = 0 TO 12 ' now for the groups and make a list of cards
  306.         count = 0
  307.         FOR ci = 0 TO 3
  308.             IF a$(c, ci) <> "" THEN count = count + 1: sAppend cards$(), a$(c, ci) 'add to card list
  309.         NEXT
  310.         IF count > 2 THEN
  311.             set$ = ""
  312.             FOR ci = 0 TO 3
  313.                 IF a$(c, ci) <> "" THEN set$ = set$ + a$(c, ci): cMeldTotal% = cMeldTotal% + points(a$(c, ci))
  314.             NEXT
  315.             sAppend gSets$(), set$
  316.         END IF
  317.     NEXT
  318.     ' meld is counted but how many dead cards left?
  319.     nCards = UBOUND(cards$)
  320.     FOR si = 1 TO UBOUND(sSets$)
  321.         IF sSets$(si) <> "" THEN
  322.             nsCards = LEN(sSets$(si)) / 3
  323.             FOR cardI = 1 TO nsCards
  324.                 FOR n = 1 TO nCards
  325.                     IF cards$(n) = MID$(sSets$(si), cardI * 3 - 2, 3) THEN cards$(n) = ""
  326.                 NEXT
  327.             NEXT
  328.         END IF
  329.     NEXT
  330.     FOR gi = 1 TO UBOUND(gSets$)
  331.         IF gSets$(gi) <> "" THEN
  332.             ngCards = LEN(gSets$(gi)) / 3
  333.             FOR cardI = 1 TO ngCards
  334.                 FOR n = 1 TO nCards
  335.                     IF cards$(n) = MID$(gSets$(gi), cardI * 3 - 2, 3) THEN cards$(n) = ""
  336.                 NEXT
  337.             NEXT
  338.         END IF
  339.     NEXT
  340.     'ok melded cards cleaned out
  341.     nDeadCards = 0
  342.     FOR n = 1 TO nCards
  343.         IF cards$(n) <> "" THEN
  344.             nDeadCards = nDeadCards + 1
  345.         END IF
  346.     NEXT
  347.  
  348. FUNCTION dealCard$
  349.     dealCard$ = deck$(deckPointer): deckPointer = deckPointer + 1
  350.  
  351. FUNCTION points% (card$)
  352.     DIM place
  353.     place = INSTR(" A 2 3 4 5 6 7 8 910 J Q K", MID$(card$, 1, 2))
  354.     IF (place + 1) / 2 < 10 THEN points% = (place + 1) / 2 ELSE points% = 10
  355.  
  356. SUB addCard (a$(), card$)
  357.     PRINT card$
  358.     DIM r, c
  359.     r = INSTR(CHR$(3) + CHR$(4) + CHR$(5) + CHR$(6), RIGHT$(card$, 1)) - 1: c = (INSTR(" A 2 3 4 5 6 7 8 910 J Q K", MID$(card$, 1, 2)) - 1) / 2
  360.     a$(c, r) = card$
  361.  
  362. SUB removeCard (a$(), card$)
  363.     DIM r, c
  364.     r = INSTR(CHR$(3) + CHR$(4) + CHR$(5) + CHR$(6), RIGHT$(card$, 1)) - 1: c = (INSTR(" A 2 3 4 5 6 7 8 910 J Q K", MID$(card$, 1, 2)) - 1) / 2
  365.     a$(c, r) = ""
  366.  
  367. 'modified for this app
  368. SUB yCP (y, s$) 'for xmax pixel wide graphics screen Center Print at pixel y row
  369.     _PRINTSTRING ((_WIDTH - 220 - LEN(s$) * 8) / 2, y), s$
  370.  
  371. 'this sub uses drwBtn
  372. FUNCTION getButtonNumberChoice% (choice$()) 'developed for this app but likely can use as is elsewhere
  373.     DIM ub, b, oldmouse, mx, my, mb
  374.  
  375.     ub = UBOUND(choice$)
  376.     FOR b = 0 TO ub
  377.         drwBtn xmax - 210, b * 60 + 90, choice$(b)
  378.     NEXT
  379.     oldmouse = -1
  380.     DO
  381.         WHILE _MOUSEINPUT: WEND
  382.         mx = _MOUSEX: my = _MOUSEY: mb = _MOUSEBUTTON(1)
  383.         IF mb AND oldmouse = 0 THEN
  384.             IF mx > xmax - 210 AND mx <= xmax - 10 THEN
  385.                 FOR b = 0 TO ub
  386.                     IF my >= b * 60 + 90 AND my <= b * 60 + 140 THEN
  387.                         LINE (xmax - 210, 0)-(xmax, ymax), bColor, BF
  388.                         getButtonNumberChoice% = b: EXIT FUNCTION
  389.                     END IF
  390.                 NEXT
  391.                 BEEP
  392.             ELSE
  393.                 BEEP
  394.             END IF
  395.         END IF
  396.         oldmouse = _MOUSEBUTTON(1)
  397.         _LIMIT 200
  398.     LOOP
  399.  
  400. SUB drwBtn (x, y, s$) '200 x 50
  401.     DIM th, tw, gray~&
  402.     th = 16: tw = 8 * LEN(s$): gray~& = _RGB32(190, 190, 190)
  403.     LINE (x, y)-STEP(204, 54), _RGB32(0, 0, 0), BF
  404.     LINE (x - 2, y - 2)-STEP(201, 51), _RGB32(255, 255, 255), BF
  405.     LINE (x, y)-STEP(200, 50), gray~&, BF
  406.     COLOR _RGB32(0, 0, 0), gray~&
  407.     _PRINTSTRING (x + 100 - 4 * LEN(s$), y + 17), s$
  408.     COLOR white, bColor
  409.  
  410. SUB sAppend (arr() AS STRING, addItem$)
  411.     REDIM _PRESERVE arr(LBOUND(arr) TO UBOUND(arr) + 1) AS STRING
  412.     arr(UBOUND(arr)) = addItem$
  413.  
  414. FUNCTION ts$ (number)
  415.     ts$ = _TRIM$(STR$(number))
  416.  

In the zip there is a txt file included you can read out of the opening screen if shell to your txt editor works for your QB64. You don't really need it but it's there for an introduction.

Oh by the way, this is all mouse so after you see a GRIN :) button just click the screen for next round or game.

Time just flies by when I am playing this one.

* Grin Runny v2020-10-12.zip (Filesize: 6.56 KB, Downloads: 139)
image_2020-10-13_004503.png
* image_2020-10-13_004503.png (Filesize: 7.81 KB, Dimensions: 800x421, Views: 152)
« Last Edit: October 13, 2020, 12:45:15 am by bplus »

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #11 on: October 14, 2020, 06:47:58 pm »
not sure just how your game handles it exactly but reading the comments seems that you can use the same card twice?. In the INTV version you can't use the same card twice, so if you had 3D,3H,3C  and you had 2H4H5H  that 3H cant be used both as a 3-of-a-kind as well as the 4 card straight of hearts too. its one or the other. you would need the 3S as well to win that hand.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #12 on: October 14, 2020, 07:16:08 pm »
not sure just how your game handles it exactly but reading the comments seems that you can use the same card twice?. In the INTV version you can't use the same card twice, so if you had 3D,3H,3C  and you had 2H4H5H  that 3H cant be used both as a 3-of-a-kind as well as the 4 card straight of hearts too. its one or the other. you would need the 3S as well to win that hand.

Yes I know in regular Gin Rummy you aren't allowed to use the same card in a straight and a group set. And that is what I did with the latest code for Grim Rummy variation and that is what hung me up for months trying to get that to work out.

BUT
For the "Grin" Rummy variation there was no way I could make the game play as well as it does enforcing 1 card 1 set rule. So I stuck to my old version for that written back in May. It just plays better IMHO, what can I say?
I explained some of this in the little txt file that I included in the zip and probably in notes at top of code.

Anyway, doing these Gin Rummy variations I have more fun inventing games than sticking strictly to old ways.

I am not done, a regular version of the game probably with regular card images are still in my plans for future. I sure as heck am not going to waste that hard won optimizer code by saying I am done with Gin Rummy with that older Grin Rummy variation.

Thanks for checking it out Cobalt.
« Last Edit: October 14, 2020, 07:18:18 pm by bplus »

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #13 on: October 17, 2020, 11:46:36 pm »
I DID IT!
I DID IT!

Finally a 10 straight! Quite possibly thee hardest way to win a hand!
10straight.jpg
* 10straight.jpg (Filesize: 78.62 KB, Dimensions: 1013x764, Views: 164)
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Gin Rummy Variations with Computer
« Reply #14 on: October 18, 2020, 10:12:32 am »
Wow! That has to be more rare than Royal Flush, well I guess you can draw more cards but a sequence of 10 is something!

Cobalt is this from a game you are working on or from Intellivision's Royal Dealer?