Author Topic: One Key Connect 4 (8x8) Halloween Style  (Read 9702 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
One Key Connect 4 (8x8) Halloween Style
« on: October 19, 2021, 08:09:18 pm »
I was curious how long this would take to convert and modify:

Code: QB64: [Select]
  1. Option _Explicit ' One Key Connect 4 (8x8) Halloween Style - bplus 2021-10-19
  2. Const SQ = 60 '       square or grid cell
  3. Const NumCols = 8 '   number of columns
  4. Const NumRows = 8 '   you guessed it
  5. Const NCM1 = NumCols - 1 ' NumCols minus 1
  6. Const NRM1 = NumRows - 1 ' you can guess surely
  7. Const SW = SQ * (NumCols + 2) '  screen width
  8. Const SH = SQ * (NumRows + 3) '  screen height
  9. Const P = 1 '       Player is 1 on grid
  10. Const AI = -1 '     AI is -1 on grid
  11. Const XO = SQ '     x offset for grid
  12. Const YO = 2 * SQ ' y offset for grid
  13.  
  14. ReDim Shared Grid(NCM1, NRM1) ' 0 = empty  P=1 for Player,  AI=-1  for AI so -4 is win for AI..
  15. ReDim Shared DX(7), DY(7) ' Directions
  16. DX(0) = 1: DY(0) = 0 ': DString$(0) = "East"
  17. DX(1) = 1: DY(1) = 1 ': DString$(1) = "South East"
  18. DX(2) = 0: DY(2) = 1 ': DString$(2) = "South"
  19. DX(3) = -1: DY(3) = 1 ': DString$(3) = "South West"
  20. DX(4) = -1: DY(4) = 0 ': DString$(4) = "West"
  21. DX(5) = -1: DY(5) = -1 ': DString$(5) = "North West"
  22. DX(6) = 0: DY(6) = -1 ': DString$(6) = "North"
  23. DX(7) = 1: DY(7) = -1 ' : DString$(7) = "North East"
  24. ReDim Shared Scores(NCM1) ' rating column for AI and displaying them
  25. ReDim Shared AIX, AIY ' last move of AI for highlighting in display
  26. ReDim Shared WinX, WinY, WinD ' display Winning Connect 4
  27. ReDim Shared GameOn, Turn, GoFirst, PlayerLastMoveCol, PlayerLastMoveRow, MoveNum ' game tracking
  28. ReDim Shared Record$(NCM1, NRM1)
  29. Dim Shared sx ' for pumpkin recursion shifty eyes
  30. Dim place, k$, t, r, s$, pr, d
  31.  
  32. Screen _NewImage(SW, SH, 32)
  33. _ScreenMove 360, 60
  34.  
  35. _Title "One Key Connect 4 (8x8) Halloween Style"
  36. d = 1
  37. While _KeyDown(32) = 0
  38.     Cls
  39.     pumpkin 0, _Width / 2, _Height / 2, _Height / 2.3, 3
  40.     sx = sx + d
  41.     If sx > 10 Then d = -d: sx = 10
  42.     If sx < -10 Then d = -d: sx = -10
  43.     Color &HFFFFFFFF, &HFF000000:
  44.     Locate 40, 33: Print "Spacebar Only"
  45.     _Display
  46.     _Limit 20
  47. GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0
  48. ShowGrid
  49. place = -1
  50. t = Timer
  51. pr = (SQ - 6) / 2
  52. While GameOn
  53.     Cls
  54.     If Turn = P Then
  55.         k$ = InKey$
  56.         If k$ = Chr$(27) Then System ' emergency exit
  57.  
  58.         If k$ = " " Then
  59.             t = Timer: place = place + 1
  60.             If place >= NumCols Then place = -1
  61.         Else ' watch out for midnight!
  62.             If Timer - t > 4 And place <> -1 Then ' col selected
  63.                 r = GetOpenRow(place)
  64.                 If r <> NumRows Then
  65.                     Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  66.                     place = -1 ' reset back to hold area
  67.                 End If
  68.             End If
  69.         End If
  70.     Else
  71.         AIMove
  72.         Turn = P: MoveNum = MoveNum + 1: t = Timer
  73.     End If
  74.     ShowGrid
  75.     If Turn = P Then
  76.         If place = -1 Then
  77.             s$ = "Holding area, press spacebar until over column to play."
  78.         Else
  79.             s$ = "Press Spacebar, if don't want to play" + Str$(place) + " column."
  80.         End If
  81.         Color &HFFFFFFFF, 0
  82.         _PrintString (XO, YO - SQ - 16), s$
  83.     End If
  84.     pumpkin 0, place * SQ + XO + SQ / 2, SQ + SQ / 2, pr, 2
  85.     sx = Rnd * 6 - 3
  86.     _Display
  87.     _Limit 15
  88.  
  89. Sub AIMove
  90.     ' What this sub does in English:
  91.     ' This sub assigns the value to playing each column, then plays the best value with following caveats:
  92.     ' + If it finds a winning move, it will play that immediately.
  93.     ' + If it finds a spoiler move, it will play that if no winning move was found.
  94.     ' + It will poisen the column's scoring, if opponent can play a winning move if AI plays this column,
  95.     '   but it might be the only legal move left.  We will have to play it if no better score was found.
  96.  
  97.     Dim c, r, d, cntA, cntP, bestScore, startR, startC, iStep, test, goodF, i
  98.     Dim openRow(NCM1) ' find open rows once
  99.     ReDim Scores(NCM1) ' evaluate each column's potential
  100.     AIX = -1: AIY = -1 ' set these when AI makes move, they are signal to display procedure AI's move.
  101.     For c = 0 To NCM1
  102.         openRow(c) = GetOpenRow(c)
  103.         r = openRow(c)
  104.         If r <> NumRows Then
  105.             For d = 0 To 3 ' 4 directions to build connect 4's that use cell c, r
  106.                 startC = c + -3 * DX(d): startR = r + -3 * DY(d)
  107.                 For i = 0 To 3 ' here we backup from the potential connect 4 in opposite build direction of c, r
  108.                     cntA = 0: cntP = 0: goodF = -1 ' reset counts and flag for good connect 4
  109.                     'from this start position run 4 steps forward to count all connects involving cell c, r
  110.                     For iStep = 0 To 3 ' process a potential connect 4
  111.                         test = GR(startC + i * DX(d) + iStep * DX(d), startR + i * DY(d) + iStep * DY(d))
  112.                         If test = NumRows Then goodF = 0: Exit For 'cant get connect4 from here
  113.                         If test = AI Then cntA = cntA + 1
  114.                         If test = P Then cntP = cntP + 1
  115.                     Next iStep
  116.                     If goodF Then 'evaluate the Legal Connect4 we could build with c, r
  117.                         If cntA = 3 Then ' we are done!  winner!
  118.                             AIX = c: AIY = r ' <<< this is the needed 4th cell to win tell ShowGrid last cell
  119.                             Grid(c, r) = AI '  <<< this is the needed 4th cell to win, add to grid this is AI move
  120.                             Scores(c) = 1000
  121.                             Exit Sub
  122.                         ElseIf cntP = 3 Then 'next best move spoiler!
  123.                             AIX = c: AIY = r 'set the move but don't exit there might be a winner
  124.                             Scores(c) = 900
  125.                         ElseIf cntA = 0 And cntP = 2 Then
  126.                             Scores(c) = Scores(c) + 8
  127.                         ElseIf cntA = 2 And cntP = 0 Then ' very good offense or defense
  128.                             Scores(c) = Scores(c) + 4 'play this to connect 3 or prevent player from Connect 3
  129.                         ElseIf cntA = 0 And cntP = 1 Then
  130.                             Scores(c) = Scores(c) + 4
  131.                         ElseIf (cntA = 1 And cntP = 0) Then 'good offense or defense
  132.                             Scores(c) = Scores(c) + 2 ' play this to connect 2 or prevent player from Connect 2
  133.                         ElseIf (cntA = 0 And cntP = 0) Then ' OK it's not a wasted move as it has potential for connect4
  134.                             Scores(c) = Scores(c) + 1 ' this is good move because this can still be a Connect 4
  135.                         End If
  136.                     End If ' in the board
  137.                 Next i
  138.             Next d
  139.             If Stupid(c, r) Then Scores(c) = -1000 + Scores(c) ' poison because if played the human can win
  140.         End If
  141.     Next
  142.     If AIX <> -1 Then ' we found a spoiler so move there since we haven't found a winner
  143.         Grid(AIX, AIY) = AI ' make move on grid and done!
  144.         Exit Sub
  145.     Else
  146.         If GetOpenRow(PlayerLastMoveCol) < NumRows Then 'all things being equal play on top of player's last move
  147.             bestScore = Scores(PlayerLastMoveCol): AIY = PlayerLastMoveRow - 1: AIX = PlayerLastMoveCol
  148.         Else
  149.             bestScore = -1000 ' a negative score indicates that the player can beat AI with their next move
  150.         End If
  151.         For c = 0 To NCM1
  152.             r = openRow(c)
  153.             If r <> NumRows Then
  154.                 If Scores(c) > bestScore Then bestScore = Scores(c): AIY = r: AIX = c
  155.             End If
  156.         Next
  157.         If AIX <> -1 Then
  158.             Grid(AIX, AIY) = AI ' make first best score move we found
  159.         Else 'We have trouble!  Oh but it could be there are no moves!!!
  160.             ' checkWin is run after every move by AI or Player if there were no legal moves left it should have caught that.
  161.             ' Just in case it didn't here is an error stop!
  162.             Beep: Locate 4, 2: Print "AI has failed to find a proper move, press any to end..."
  163.             Sleep ' <<< pause until user presses a key
  164.             End
  165.         End If
  166.     End If
  167.  
  168. Function GetOpenRow (forCol)
  169.     Dim i
  170.     GetOpenRow = NumRows 'assume none open
  171.     If forCol < 0 Or forCol > NCM1 Then Exit Function
  172.     For i = NRM1 To 0 Step -1
  173.         If Grid(forCol, i) = 0 Then GetOpenRow = i: Exit Function
  174.     Next
  175.  
  176. Function Stupid (c, r)
  177.     Dim pr
  178.     Grid(c, r) = AI
  179.     pr = GetOpenRow(c)
  180.     If pr <> NumRows Then
  181.         Grid(c, pr) = P
  182.         If CheckWin = 4 Then Stupid = -1
  183.         Grid(c, pr) = 0
  184.     End If
  185.     Grid(c, r) = 0
  186.  
  187. Function GR (c, r) ' if c, r are out of bounds returns N else returns grid(c, r)
  188.     ' need to check the grid(c, r) but only if c, r is on the board
  189.     If c < 0 Or c > NCM1 Or r < 0 Or r > NRM1 Then GR = NumRows Else GR = Grid(c, r)
  190.  
  191. Sub ShowGrid
  192.     Static lastMoveNum
  193.     Dim i, r, c, check, s$, k$
  194.     If MoveNum <> lastMoveNum Then ' file newest move
  195.         If MoveNum = 1 Then ReDim Record$(NCM1, NRM1)
  196.         If Turn = -1 Then
  197.             Record$(PlayerLastMoveCol, PlayerLastMoveRow) = _Trim$(Str$(MoveNum)) + " " + "P"
  198.         Else
  199.             Record$(AIX, AIY) = _Trim$(Str$(MoveNum)) + " " + "A"
  200.         End If
  201.         lastMoveNum = MoveNum
  202.     End If
  203.     'cls
  204.     Line (XO, YO)-Step(NumCols * SQ, NumRows * SQ), &HFF004400, BF
  205.     For i = 0 To NumCols 'grid
  206.         Line (SQ * i + XO, YO)-Step(0, NumRows * SQ), &HFFFFFFFF
  207.     Next
  208.     For i = 0 To NumRows
  209.         Line (XO, SQ * i + YO)-Step(NumCols * SQ, 0), &HFFFFFFFF
  210.     Next
  211.     For r = NRM1 To 0 Step -1 ''in grid rows are reversed 0 is top row
  212.         For c = 0 To NCM1
  213.             If Grid(c, r) = P Then
  214.                 Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF000000, BF
  215.                 pumpkin 0, c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, (SQ - 6) / 2, 2
  216.  
  217.             ElseIf Grid(c, r) = AI Then
  218.                 If c = AIX And r = AIY Then 'highlite last AI move
  219.                     Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF8888FF, BF
  220.                 Else
  221.                     Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF4444FF, BF
  222.                 End If
  223.                 drawSpinner c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, .5, _Pi(-c / 8), _RGB32(Rnd * 30 + 40, Rnd * 15 + 20, Rnd * 6 + 10)
  224.             End If
  225.             s$ = _Trim$(Str$(Scores(c)))
  226.             _PrintString (XO + c * SQ + (60 - Len(s$) * 8) / 2, YO + SQ * NumRows + 22), s$
  227.         Next
  228.     Next
  229.     '_Display
  230.     check = CheckWin
  231.     If check Then 'report end of round ad see if want to play again
  232.         If check = 4 Or check = -4 Then
  233.             For i = 0 To 3
  234.                 Line ((WinX + i * DX(WinD)) * SQ + XO + 5, (WinY + i * DY(WinD)) * SQ + YO + 5)-Step(SQ - 10, SQ - 10), &HFFFFFF00, B
  235.             Next
  236.         End If
  237.         For r = 0 To NRM1
  238.             For c = 0 To NCM1
  239.                 If Record$(c, r) <> "" Then
  240.                     s$ = Mid$(Record$(c, r), 1, InStr(Record$(c, r), " ") - 1)
  241.                     If Right$(Record$(c, r), 1) = "A" Then Color &HFFFFFFFF, &HFF000000 Else Color &HFFFFFFFF, &HFF000000
  242.                     _PrintString (SQ * c + XO + (SQ - Len(s$) * 8) / 2, SQ * r + YO + 22), s$
  243.                 End If
  244.             Next
  245.             Color , &HFF000000
  246.         Next
  247.         If check = -4 Then
  248.             s$ = " AI is Winner!"
  249.         ElseIf check = 4 Then
  250.             s$ = " Human is Winner!"
  251.         ElseIf check = NumRows Then
  252.             s$ = " Board is full, no winner." ' keep Turn the same
  253.         End If
  254.         Locate 2, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  255.         s$ = " Play again? press spacebar, escape to quit... "
  256.         Locate 4, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  257.         _Display
  258.         keywait:
  259.         While Len(k$) = 0
  260.             k$ = InKey$
  261.             _Limit 200
  262.         Wend
  263.         If k$ = " " Then
  264.             ReDim Grid(NCM1, NRM1), Scores(NCM1)
  265.             If GoFirst = P Then GoFirst = AI Else GoFirst = P
  266.             Turn = GoFirst: MoveNum = 0
  267.         ElseIf Asc(k$) = 27 Then
  268.             System
  269.         Else
  270.             k$ = "": GoTo keywait:
  271.         End If
  272.     End If
  273.  
  274. Function CheckWin ' return WinX, WinY, WinD along with +/- 4, returns NumRows if grid full, 0 if no win and grid not full
  275.     Dim gridFull, r, c, s, i
  276.     gridFull = NumRows
  277.     For r = NRM1 To 0 Step -1 'bottom to top
  278.         For c = 0 To NCM1
  279.             If Grid(c, r) Then ' check if c starts a row
  280.                 If c < NCM1 - 2 Then
  281.                     s = 0
  282.                     For i = 0 To 3 ' east
  283.                         s = s + Grid(c + i, r)
  284.                     Next
  285.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 0: CheckWin = s: Exit Function
  286.                 End If
  287.                 If r > 2 Then ' check if c starts a col
  288.                     s = 0
  289.                     For i = 0 To 3 ' north
  290.                         s = s + Grid(c, r - i)
  291.                     Next
  292.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 6: CheckWin = s: Exit Function
  293.                 End If
  294.                 If r > 2 And c < NCM1 - 2 Then 'check if c starts diagonal up to right
  295.                     s = 0
  296.                     For i = 0 To 3 ' north  east
  297.                         s = s + Grid(c + i, r - i)
  298.                     Next
  299.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 7: CheckWin = s: Exit Function
  300.                 End If
  301.                 If r > 2 And c > 2 Then 'check if c starts a diagonal up to left
  302.                     s = 0
  303.                     For i = 0 To 3 ' north west
  304.                         s = s + Grid(c - i, r - i)
  305.                     Next
  306.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 5: CheckWin = s: Exit Function
  307.                 End If
  308.             Else
  309.                 gridFull = 0 ' at least one enpty cell left
  310.             End If 'grid is something
  311.         Next
  312.     Next
  313.     CheckWin = gridFull
  314.  
  315.  
  316. Sub pumpkin (dh&, cx, cy, pr, limit)
  317.     Dim lastr, u, dx, i, tx1, tx2, tx3, ty1, ty2, ty3, ty22, sxs
  318.     'carve this!
  319.     Color &HFFFF0000
  320.     fEllipse cx, cy, pr, 29 / 35 * pr
  321.     Color &HFF000000
  322.     lastr = 2 / 7 * pr
  323.     Do
  324.         ellipse cx, cy, lastr, 29 / 35 * pr
  325.         lastr = .5 * (pr - lastr) + lastr + 1 / 35 * pr
  326.         If pr - lastr < 1 / 80 * pr Then Exit Do
  327.     Loop
  328.  
  329.     ' 'flickering candle light
  330.     'Color _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  331.  
  332.     ' eye sockets
  333.     ftri2 dh&, cx - 9 * pr / 12, cy - 2 * pr / 12, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  334.     ftri2 dh&, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, cx - 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  335.     ftri2 dh&, cx + 9 * pr / 12, cy - 2 * pr / 12, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  336.     ftri2 dh&, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, cx + 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  337.  
  338.     ' nose
  339.     ftri2 dh&, cx, cy - rand%(2, 5) * pr / 12, cx - 2 * pr / 12, cy + 2 * pr / 12, cx + rand%(1, 2) * pr / 12, cy + 2 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  340.  
  341.     ' evil grin
  342.     ftri2 dh&, cx - 9 * pr / 12, cy + 1 * pr / 12, cx - 7 * pr / 12, cy + 7 * pr / 12, cx - 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  343.     ftri2 dh&, cx + 9 * pr / 12, cy + 1 * pr / 12, cx + 7 * pr / 12, cy + 7 * pr / 12, cx + 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  344.  
  345.     ' moving teeth/talk/grrrr..
  346.     u = rand%(4, 8)
  347.     dx = pr / u
  348.     For i = 1 To u
  349.         tx1 = cx - 6 * pr / 12 + (i - 1) * dx
  350.         tx2 = tx1 + .5 * dx
  351.         tx3 = tx1 + dx
  352.         ty1 = cy + 5 * pr / 12
  353.         ty3 = cy + 5 * pr / 12
  354.         ty2 = cy + (4 - Rnd) * pr / 12
  355.         ty22 = cy + (6 + Rnd) * pr / 12
  356.         ftri2 dh&, tx1, ty1, tx2, ty2, tx3, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  357.         ftri2 dh&, tx1 + .5 * dx, ty1, tx2 + .5 * dx, ty22, tx3 + .5 * dx, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  358.     Next
  359.     If limit Then
  360.         'shifty eyes
  361.         If limit = 3 Then sxs = sx Else sxs = .1 * limit * sx
  362.         pumpkin dh&, sxs + cx - 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  363.         pumpkin dh&, sxs + cx + 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  364.     End If
  365.  
  366. Sub fEllipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  367.     Dim scale As Single, x As Long, y As Long
  368.     scale = yRadius / xRadius
  369.     Line (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  370.     For x = 1 To xRadius
  371.         y = scale * Sqr(xRadius * xRadius - x * x)
  372.         Line (CX + x, CY - y)-(CX + x, CY + y), , BF
  373.         Line (CX - x, CY - y)-(CX - x, CY + y), , BF
  374.     Next
  375.  
  376. Sub ellipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  377.     Dim scale As Single, xs As Long, x As Long, y As Long
  378.     Dim lastx As Long, lasty As Long
  379.     scale = yRadius / xRadius: xs = xRadius * xRadius
  380.     PSet (CX, CY - yRadius): PSet (CX, CY + yRadius)
  381.     lastx = 0: lasty = yRadius
  382.     For x = 1 To xRadius
  383.         y = scale * Sqr(xs - x * x)
  384.         Line (CX + lastx, CY - lasty)-(CX + x, CY - y)
  385.         Line (CX + lastx, CY + lasty)-(CX + x, CY + y)
  386.         Line (CX - lastx, CY - lasty)-(CX - x, CY - y)
  387.         Line (CX - lastx, CY + lasty)-(CX - x, CY + y)
  388.         lastx = x: lasty = y
  389.     Next
  390.  
  391. Sub ftri2 (returnDest&, x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  392.     Dim a&
  393.     a& = _NewImage(1, 1, 32)
  394.     _Dest a&
  395.     PSet (0, 0), K
  396.     _Dest returnDest&
  397.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  398.     _FreeImage a& '<<< this is important!
  399.  
  400. Function rand% (lo%, hi%)
  401.     rand% = Int(Rnd * (hi% - lo% + 1)) + lo%
  402.  
  403.  
  404.  
  405. Sub drawLink (x1, y1, r1, x2, y2, r2, c As _Unsigned Long)
  406.     Dim a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  407.     a = _Atan2(y2 - y1, x2 - x1)
  408.     a1 = a + _Pi(1 / 2)
  409.     a2 = a - _Pi(1 / 2)
  410.     x3 = x1 + r1 * Cos(a1): y3 = y1 + r1 * Sin(a1)
  411.     x4 = x1 + r1 * Cos(a2): y4 = y1 + r1 * Sin(a2)
  412.     x5 = x2 + r2 * Cos(a1): y5 = y2 + r2 * Sin(a1)
  413.     x6 = x2 + r2 * Cos(a2): y6 = y2 + r2 * Sin(a2)
  414.     fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  415.     Fcirc x1, y1, r1, c
  416.     Fcirc x2, y2, r2, c
  417.  
  418. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  419. Sub fquad (x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, x3 As Integer, y3 As Integer, x4 As Integer, y4 As Integer, c As _Unsigned Long)
  420.     ftri x1, y1, x2, y2, x4, y4, c
  421.     ftri x3, y3, x4, y4, x1, y1, c
  422.  
  423. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  424.     Dim a&
  425.     a& = _NewImage(1, 1, 32)
  426.     _Dest a&
  427.     PSet (0, 0), K
  428.     _Dest 0
  429.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  430.     _FreeImage a& '<<< this is important!
  431.  
  432. Sub TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c As _Unsigned Long)
  433.     Dim max As Integer, mx2 As Integer, i As Integer, j As Integer, k As Single, lasti As Single, lastj As Single
  434.     Dim prc As _Unsigned Long, tef As Long
  435.     prc = _RGB32(255, 255, 255, 255)
  436.     If a > b Then max = a + 1 Else max = b + 1
  437.     mx2 = max + max
  438.     tef = _NewImage(mx2, mx2)
  439.     _Dest tef
  440.     _Source tef 'point wont read without this!
  441.     For k = 0 To 6.2832 + .05 Step .1
  442.         i = max + a * Cos(k) * Cos(ang) + b * Sin(k) * Sin(ang)
  443.         j = max + a * Cos(k) * Sin(ang) - b * Sin(k) * Cos(ang)
  444.         If k <> 0 Then
  445.             Line (lasti, lastj)-(i, j), prc
  446.         Else
  447.             PSet (i, j), prc
  448.         End If
  449.         lasti = i: lastj = j
  450.     Next
  451.     Dim xleft(mx2) As Integer, xright(mx2) As Integer, x As Integer, y As Integer
  452.     For y = 0 To mx2
  453.         x = 0
  454.         While Point(x, y) <> prc And x < mx2
  455.             x = x + 1
  456.         Wend
  457.         xleft(y) = x
  458.         While Point(x, y) = prc And x < mx2
  459.             x = x + 1
  460.         Wend
  461.         While Point(x, y) <> prc And x < mx2
  462.             x = x + 1
  463.         Wend
  464.         If x = mx2 Then xright(y) = xleft(y) Else xright(y) = x
  465.     Next
  466.     _Dest destHandle&
  467.     For y = 0 To mx2
  468.         If xleft(y) <> mx2 Then Line (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  469.     Next
  470.     _FreeImage tef
  471.  
  472. Sub Fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
  473.     Dim Radius As Long, RadiusError As Long
  474.     Dim X As Long, Y As Long
  475.     Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
  476.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  477.     Line (CX - X, CY)-(CX + X, CY), C, BF
  478.     While X > Y
  479.         RadiusError = RadiusError + Y * 2 + 1
  480.         If RadiusError >= 0 Then
  481.             If X <> Y + 1 Then
  482.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  483.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  484.             End If
  485.             X = X - 1
  486.             RadiusError = RadiusError - X * 2
  487.         End If
  488.         Y = Y + 1
  489.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  490.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  491.     Wend
  492.  
  493. Sub drawSpinner (x As Integer, y As Integer, scale As Single, heading As Single, c As _Unsigned Long)
  494.     Dim x1, x2, x3, x4, y1, y2, y3, y4, r, a, a1, a2, lg, d, rd
  495.     Dim rred, bblue, ggreen
  496.     Static switch As Integer
  497.     switch = switch + 2
  498.     switch = switch Mod 16 + 1
  499.     rred = _Red32(c): ggreen = _Green32(c): bblue = _Blue32(c)
  500.     r = 10 * scale
  501.     x1 = x + r * Cos(heading): y1 = y + r * Sin(heading)
  502.     r = 2 * r 'lg lengths
  503.     For lg = 1 To 8
  504.         If lg < 5 Then
  505.             a = heading + .9 * lg * _Pi(1 / 5) + (lg = switch) * _Pi(1 / 10)
  506.         Else
  507.             a = heading - .9 * (lg - 4) * _Pi(1 / 5) - (lg = switch) * _Pi(1 / 10)
  508.         End If
  509.         x2 = x1 + r * Cos(a): y2 = y1 + r * Sin(a)
  510.         drawLink x1, y1, 3 * scale, x2, y2, 2 * scale, _RGB32(rred + 20, ggreen + 10, bblue + 5)
  511.         If lg = 1 Or lg = 2 Or lg = 7 Or lg = 8 Then d = -1 Else d = 1
  512.         a1 = a + d * _Pi(1 / 12)
  513.         x3 = x2 + r * 1.5 * Cos(a1): y3 = y2 + r * 1.5 * Sin(a1)
  514.         drawLink x2, y2, 2 * scale, x3, y3, scale, _RGB32(rred + 35, ggreen + 17, bblue + 8)
  515.         rd = Int(Rnd * 8) + 1
  516.         a2 = a1 + d * _Pi(1 / 8) * rd / 8
  517.         x4 = x3 + r * 1.5 * Cos(a2): y4 = y3 + r * 1.5 * Sin(a2)
  518.         drawLink x3, y3, scale, x4, y4, scale, _RGB32(rred + 50, ggreen + 25, bblue + 12)
  519.     Next
  520.     r = r * .5
  521.     Fcirc x1, y1, r, _RGB32(rred - 20, ggreen - 10, bblue - 5)
  522.     x2 = x1 + (r + 1) * Cos(heading - _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading - _Pi(1 / 12))
  523.     Fcirc x2, y2, r * .2, &HFF000000
  524.     x2 = x1 + (r + 1) * Cos(heading + _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading + _Pi(1 / 12))
  525.     Fcirc x2, y2, r * .2, &HFF000000
  526.     r = r * 2
  527.     x1 = x + r * .9 * Cos(heading + _Pi): y1 = y + r * .9 * Sin(heading + _Pi)
  528.     TiltedEllipseFill 0, x1, y1, r, .7 * r, heading + _Pi, _RGB32(rred, ggreen, bblue)
  529.  
  530.  

Attached is Source and .exe for Windows (no assets program)
 
One Key Connect 4 (8x8) Halloween Style.PNG

* One Key Connect 4 (8x8) Halloween Style.zip (Filesize: 840.34 KB, Downloads: 137)

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #1 on: October 19, 2021, 08:18:38 pm »
Not bad. The drop delay was a bit slow for my taste though.
Would have been a neat addition to have the pieces drop down the board rather than just pop in place, and using an overlay you could even "simulate" round pieces!

and Yes I LOST! nearly had the whole board filled though.
Granted after becoming radioactive I only have a half-life!

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #2 on: October 19, 2021, 08:19:04 pm »
hi bplus
the game play would be better if you could also select the row

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #3 on: October 19, 2021, 08:29:47 pm »
@Cobalt nice suggestions thanks!

@jack what? AI pieces have to be in next available slot in column just like yours, maybe AI makes it's move too fast? It's last move is the lighter blue square. It goes first in first game but you go first in next, it alternates.

The human player (you) must keep pressing spacebar until the pumpkin piece is over the column you want then just wait or wait in holding area or spacebar back to holding area until you are sure of your column.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #4 on: October 19, 2021, 08:33:47 pm »
hi bplus
the game play would be better if you could also select the row

Ah! you haven't played Connect 4 before. OK

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #5 on: October 19, 2021, 09:05:10 pm »
The game would be better if you could blow stuff up. I played 4 times. I lost 4 times. I had to go in the backyard and blow up the barbecue. Oh well, it's the neighbors. Sorry Cobalt, it was getting rusty, anyway.

Pete

5 of 5: 🎃🎃🎃🎃🎃 
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #6 on: October 19, 2021, 09:25:27 pm »
Here is Cobalt's suggestion about dropping the pumpkin piece down as you would see it on a real game board:
Luv it!
Code: QB64: [Select]
  1. Option _Explicit ' One Key Connect 4 (8x8) Halloween Style - bplus 2021-10-19
  2. Const SQ = 60 '       square or grid cell
  3. Const NumCols = 8 '   number of columns
  4. Const NumRows = 8 '   you guessed it
  5. Const NCM1 = NumCols - 1 ' NumCols minus 1
  6. Const NRM1 = NumRows - 1 ' you can guess surely
  7. Const SW = SQ * (NumCols + 2) '  screen width
  8. Const SH = SQ * (NumRows + 3) '  screen height
  9. Const P = 1 '       Player is 1 on grid
  10. Const AI = -1 '     AI is -1 on grid
  11. Const XO = SQ '     x offset for grid
  12. Const YO = 2 * SQ ' y offset for grid
  13.  
  14. ReDim Shared Grid(NCM1, NRM1) ' 0 = empty  P=1 for Player,  AI=-1  for AI so -4 is win for AI..
  15. ReDim Shared DX(7), DY(7) ' Directions
  16. DX(0) = 1: DY(0) = 0 ': DString$(0) = "East"
  17. DX(1) = 1: DY(1) = 1 ': DString$(1) = "South East"
  18. DX(2) = 0: DY(2) = 1 ': DString$(2) = "South"
  19. DX(3) = -1: DY(3) = 1 ': DString$(3) = "South West"
  20. DX(4) = -1: DY(4) = 0 ': DString$(4) = "West"
  21. DX(5) = -1: DY(5) = -1 ': DString$(5) = "North West"
  22. DX(6) = 0: DY(6) = -1 ': DString$(6) = "North"
  23. DX(7) = 1: DY(7) = -1 ' : DString$(7) = "North East"
  24. ReDim Shared Scores(NCM1) ' rating column for AI and displaying them
  25. ReDim Shared AIX, AIY ' last move of AI for highlighting in display
  26. ReDim Shared WinX, WinY, WinD ' display Winning Connect 4
  27. ReDim Shared GameOn, Turn, GoFirst, PlayerLastMoveCol, PlayerLastMoveRow, MoveNum ' game tracking
  28. ReDim Shared Record$(NCM1, NRM1)
  29. Dim Shared sx ' for pumpkin recursion shifty eyes
  30. Dim place, k$, t, r, s$, pr, d, temp&, target, y, delaid
  31.  
  32. Screen _NewImage(SW, SH, 32)
  33. _ScreenMove 360, 60
  34.  
  35. _Title "One Key Connect 4 (8x8) Halloween Style"
  36. d = 1
  37. While _KeyDown(32) = 0
  38.     Cls
  39.     pumpkin 0, _Width / 2, _Height / 2, _Height / 2.3, 3
  40.     sx = sx + d
  41.     If sx > 10 Then d = -d: sx = 10
  42.     If sx < -10 Then d = -d: sx = -10
  43.     Color &HFFFFFFFF, &HFF000000:
  44.     Locate 40, 33: Print "Spacebar Only"
  45.     _Display
  46.     _Limit 20
  47. GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0
  48. ShowGrid
  49. place = -1
  50. t = Timer
  51. pr = (SQ - 6) / 2
  52. While GameOn
  53.     Cls
  54.     If Turn = P Then
  55.         k$ = InKey$
  56.         If k$ = Chr$(27) Then System ' emergency exit
  57.  
  58.         If k$ = " " Then
  59.             t = Timer: place = place + 1
  60.             If place >= NumCols Then place = -1
  61.         Else ' watch out for midnight!
  62.             If Timer - t < 0 Then 'midnight problem
  63.                 t = Timer ' wait a little longer
  64.             Else
  65.                 If Timer - t > 3 And place <> -1 Then ' col selected
  66.                     r = GetOpenRow(place)
  67.                     If r <> NumRows Then
  68.                         Cls
  69.                         ShowGrid
  70.                         _Display
  71.                         temp& = _NewImage(_Width, _Height, 32)
  72.                         _PutImage , 0, temp& 'snapshot
  73.                         y = SQ + SQ / 2
  74.                         target = r * SQ + YO + SQ / 2
  75.                         delaid = 6
  76.                         While y < target
  77.                             y = y + 1
  78.                             Cls
  79.                             _PutImage , temp&, 0
  80.                             pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 3
  81.                             sx = Rnd * 6 - 3
  82.                             _Display
  83.                             _Limit delaid
  84.                             delaid = delaid + 2
  85.                         Wend
  86.                         _FreeImage temp&
  87.                         Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  88.                         place = -1 ' reset back to hold area
  89.                     Else
  90.                         Beep
  91.                     End If
  92.                 End If
  93.             End If
  94.         End If
  95.     Else
  96.         AIMove
  97.         Turn = P: MoveNum = MoveNum + 1: t = Timer
  98.     End If
  99.     ShowGrid
  100.     If Turn = P Then
  101.         If place = -1 Then
  102.             s$ = "Holding area, press spacebar until over column to play."
  103.         Else
  104.             s$ = "Press Spacebar, if don't want to play" + Str$(place) + " column."
  105.         End If
  106.         Color &HFFFFFFFF, 0
  107.         _PrintString (XO, YO - SQ - 16), s$
  108.     End If
  109.     pumpkin 0, place * SQ + XO + SQ / 2, SQ + SQ / 2, pr, 3
  110.     sx = Rnd * 6 - 3
  111.     _Display
  112.     _Limit 15
  113.  
  114. Sub AIMove
  115.     ' What this sub does in English:
  116.     ' This sub assigns the value to playing each column, then plays the best value with following caveats:
  117.     ' + If it finds a winning move, it will play that immediately.
  118.     ' + If it finds a spoiler move, it will play that if no winning move was found.
  119.     ' + It will poisen the column's scoring, if opponent can play a winning move if AI plays this column,
  120.     '   but it might be the only legal move left.  We will have to play it if no better score was found.
  121.  
  122.     Dim c, r, d, cntA, cntP, bestScore, startR, startC, iStep, test, goodF, i
  123.     Dim openRow(NCM1) ' find open rows once
  124.     ReDim Scores(NCM1) ' evaluate each column's potential
  125.     AIX = -1: AIY = -1 ' set these when AI makes move, they are signal to display procedure AI's move.
  126.     For c = 0 To NCM1
  127.         openRow(c) = GetOpenRow(c)
  128.         r = openRow(c)
  129.         If r <> NumRows Then
  130.             For d = 0 To 3 ' 4 directions to build connect 4's that use cell c, r
  131.                 startC = c + -3 * DX(d): startR = r + -3 * DY(d)
  132.                 For i = 0 To 3 ' here we backup from the potential connect 4 in opposite build direction of c, r
  133.                     cntA = 0: cntP = 0: goodF = -1 ' reset counts and flag for good connect 4
  134.                     'from this start position run 4 steps forward to count all connects involving cell c, r
  135.                     For iStep = 0 To 3 ' process a potential connect 4
  136.                         test = GR(startC + i * DX(d) + iStep * DX(d), startR + i * DY(d) + iStep * DY(d))
  137.                         If test = NumRows Then goodF = 0: Exit For 'cant get connect4 from here
  138.                         If test = AI Then cntA = cntA + 1
  139.                         If test = P Then cntP = cntP + 1
  140.                     Next iStep
  141.                     If goodF Then 'evaluate the Legal Connect4 we could build with c, r
  142.                         If cntA = 3 Then ' we are done!  winner!
  143.                             AIX = c: AIY = r ' <<< this is the needed 4th cell to win tell ShowGrid last cell
  144.                             Grid(c, r) = AI '  <<< this is the needed 4th cell to win, add to grid this is AI move
  145.                             Scores(c) = 1000
  146.                             Exit Sub
  147.                         ElseIf cntP = 3 Then 'next best move spoiler!
  148.                             AIX = c: AIY = r 'set the move but don't exit there might be a winner
  149.                             Scores(c) = 900
  150.                         ElseIf cntA = 0 And cntP = 2 Then
  151.                             Scores(c) = Scores(c) + 8
  152.                         ElseIf cntA = 2 And cntP = 0 Then ' very good offense or defense
  153.                             Scores(c) = Scores(c) + 4 'play this to connect 3 or prevent player from Connect 3
  154.                         ElseIf cntA = 0 And cntP = 1 Then
  155.                             Scores(c) = Scores(c) + 4
  156.                         ElseIf (cntA = 1 And cntP = 0) Then 'good offense or defense
  157.                             Scores(c) = Scores(c) + 2 ' play this to connect 2 or prevent player from Connect 2
  158.                         ElseIf (cntA = 0 And cntP = 0) Then ' OK it's not a wasted move as it has potential for connect4
  159.                             Scores(c) = Scores(c) + 1 ' this is good move because this can still be a Connect 4
  160.                         End If
  161.                     End If ' in the board
  162.                 Next i
  163.             Next d
  164.             If Stupid(c, r) Then Scores(c) = -1000 + Scores(c) ' poison because if played the human can win
  165.         End If
  166.     Next
  167.     If AIX <> -1 Then ' we found a spoiler so move there since we haven't found a winner
  168.         Grid(AIX, AIY) = AI ' make move on grid and done!
  169.         Exit Sub
  170.     Else
  171.         If GetOpenRow(PlayerLastMoveCol) < NumRows Then 'all things being equal play on top of player's last move
  172.             bestScore = Scores(PlayerLastMoveCol): AIY = PlayerLastMoveRow - 1: AIX = PlayerLastMoveCol
  173.         Else
  174.             bestScore = -1000 ' a negative score indicates that the player can beat AI with their next move
  175.         End If
  176.         For c = 0 To NCM1
  177.             r = openRow(c)
  178.             If r <> NumRows Then
  179.                 If Scores(c) > bestScore Then bestScore = Scores(c): AIY = r: AIX = c
  180.             End If
  181.         Next
  182.         If AIX <> -1 Then
  183.             Grid(AIX, AIY) = AI ' make first best score move we found
  184.         Else 'We have trouble!  Oh but it could be there are no moves!!!
  185.             ' checkWin is run after every move by AI or Player if there were no legal moves left it should have caught that.
  186.             ' Just in case it didn't here is an error stop!
  187.             Beep: Locate 4, 2: Print "AI has failed to find a proper move, press any to end..."
  188.             Sleep ' <<< pause until user presses a key
  189.             End
  190.         End If
  191.     End If
  192.  
  193. Function GetOpenRow (forCol)
  194.     Dim i
  195.     GetOpenRow = NumRows 'assume none open
  196.     If forCol < 0 Or forCol > NCM1 Then Exit Function
  197.     For i = NRM1 To 0 Step -1
  198.         If Grid(forCol, i) = 0 Then GetOpenRow = i: Exit Function
  199.     Next
  200.  
  201. Function Stupid (c, r)
  202.     Dim pr
  203.     Grid(c, r) = AI
  204.     pr = GetOpenRow(c)
  205.     If pr <> NumRows Then
  206.         Grid(c, pr) = P
  207.         If CheckWin = 4 Then Stupid = -1
  208.         Grid(c, pr) = 0
  209.     End If
  210.     Grid(c, r) = 0
  211.  
  212. Function GR (c, r) ' if c, r are out of bounds returns N else returns grid(c, r)
  213.     ' need to check the grid(c, r) but only if c, r is on the board
  214.     If c < 0 Or c > NCM1 Or r < 0 Or r > NRM1 Then GR = NumRows Else GR = Grid(c, r)
  215.  
  216. Sub ShowGrid
  217.     Static lastMoveNum
  218.     Dim i, r, c, check, s$, k$
  219.     If MoveNum <> lastMoveNum Then ' file newest move
  220.         If MoveNum = 1 Then ReDim Record$(NCM1, NRM1)
  221.         If Turn = -1 Then
  222.             Record$(PlayerLastMoveCol, PlayerLastMoveRow) = _Trim$(Str$(MoveNum)) + " " + "P"
  223.         Else
  224.             Record$(AIX, AIY) = _Trim$(Str$(MoveNum)) + " " + "A"
  225.         End If
  226.         lastMoveNum = MoveNum
  227.     End If
  228.     'cls
  229.     Line (XO, YO)-Step(NumCols * SQ, NumRows * SQ), &HFF004400, BF
  230.     For i = 0 To NumCols 'grid
  231.         Line (SQ * i + XO, YO)-Step(0, NumRows * SQ), &HFFFFFFFF
  232.     Next
  233.     For i = 0 To NumRows
  234.         Line (XO, SQ * i + YO)-Step(NumCols * SQ, 0), &HFFFFFFFF
  235.     Next
  236.     For r = NRM1 To 0 Step -1 ''in grid rows are reversed 0 is top row
  237.         For c = 0 To NCM1
  238.             If Grid(c, r) = P Then
  239.                 Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF000000, BF
  240.                 pumpkin 0, c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, (SQ - 6) / 2, 2
  241.  
  242.             ElseIf Grid(c, r) = AI Then
  243.                 If c = AIX And r = AIY Then 'highlite last AI move
  244.                     Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF8888FF, BF
  245.                 Else
  246.                     Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF4444FF, BF
  247.                 End If
  248.                 drawSpinner c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, .5, _Pi(-c / 8), _RGB32(Rnd * 30 + 40, Rnd * 15 + 20, Rnd * 6 + 10)
  249.             End If
  250.             s$ = _Trim$(Str$(Scores(c)))
  251.             _PrintString (XO + c * SQ + (60 - Len(s$) * 8) / 2, YO + SQ * NumRows + 22), s$
  252.         Next
  253.     Next
  254.     '_Display
  255.     check = CheckWin
  256.     If check Then 'report end of round ad see if want to play again
  257.         If check = 4 Or check = -4 Then
  258.             For i = 0 To 3
  259.                 Line ((WinX + i * DX(WinD)) * SQ + XO + 5, (WinY + i * DY(WinD)) * SQ + YO + 5)-Step(SQ - 10, SQ - 10), &HFFFFFF00, B
  260.             Next
  261.         End If
  262.         For r = 0 To NRM1
  263.             For c = 0 To NCM1
  264.                 If Record$(c, r) <> "" Then
  265.                     s$ = Mid$(Record$(c, r), 1, InStr(Record$(c, r), " ") - 1)
  266.                     If Right$(Record$(c, r), 1) = "A" Then Color &HFFFFFFFF, &HFF000000 Else Color &HFFFFFFFF, &HFF000000
  267.                     _PrintString (SQ * c + XO + (SQ - Len(s$) * 8) / 2, SQ * r + YO + 22), s$
  268.                 End If
  269.             Next
  270.             Color , &HFF000000
  271.         Next
  272.         If check = -4 Then
  273.             s$ = " AI is Winner!"
  274.         ElseIf check = 4 Then
  275.             s$ = " Human is Winner!"
  276.         ElseIf check = NumRows Then
  277.             s$ = " Board is full, no winner." ' keep Turn the same
  278.         End If
  279.         Locate 2, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  280.         s$ = " Play again? press spacebar, escape to quit... "
  281.         Locate 4, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  282.         _Display
  283.         keywait:
  284.         While Len(k$) = 0
  285.             k$ = InKey$
  286.             _Limit 200
  287.         Wend
  288.         If k$ = " " Then
  289.             ReDim Grid(NCM1, NRM1), Scores(NCM1)
  290.             If GoFirst = P Then GoFirst = AI Else GoFirst = P
  291.             Turn = GoFirst: MoveNum = 0
  292.         ElseIf Asc(k$) = 27 Then
  293.             System
  294.         Else
  295.             k$ = "": GoTo keywait:
  296.         End If
  297.     End If
  298.  
  299. Function CheckWin ' return WinX, WinY, WinD along with +/- 4, returns NumRows if grid full, 0 if no win and grid not full
  300.     Dim gridFull, r, c, s, i
  301.     gridFull = NumRows
  302.     For r = NRM1 To 0 Step -1 'bottom to top
  303.         For c = 0 To NCM1
  304.             If Grid(c, r) Then ' check if c starts a row
  305.                 If c < NCM1 - 2 Then
  306.                     s = 0
  307.                     For i = 0 To 3 ' east
  308.                         s = s + Grid(c + i, r)
  309.                     Next
  310.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 0: CheckWin = s: Exit Function
  311.                 End If
  312.                 If r > 2 Then ' check if c starts a col
  313.                     s = 0
  314.                     For i = 0 To 3 ' north
  315.                         s = s + Grid(c, r - i)
  316.                     Next
  317.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 6: CheckWin = s: Exit Function
  318.                 End If
  319.                 If r > 2 And c < NCM1 - 2 Then 'check if c starts diagonal up to right
  320.                     s = 0
  321.                     For i = 0 To 3 ' north  east
  322.                         s = s + Grid(c + i, r - i)
  323.                     Next
  324.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 7: CheckWin = s: Exit Function
  325.                 End If
  326.                 If r > 2 And c > 2 Then 'check if c starts a diagonal up to left
  327.                     s = 0
  328.                     For i = 0 To 3 ' north west
  329.                         s = s + Grid(c - i, r - i)
  330.                     Next
  331.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 5: CheckWin = s: Exit Function
  332.                 End If
  333.             Else
  334.                 gridFull = 0 ' at least one enpty cell left
  335.             End If 'grid is something
  336.         Next
  337.     Next
  338.     CheckWin = gridFull
  339.  
  340.  
  341. Sub pumpkin (dh&, cx, cy, pr, limit)
  342.     Dim lastr, u, dx, i, tx1, tx2, tx3, ty1, ty2, ty3, ty22, sxs
  343.     'carve this!
  344.     Color &HFFFF0000
  345.     fEllipse cx, cy, pr, 29 / 35 * pr
  346.     Color &HFF000000
  347.     lastr = 2 / 7 * pr
  348.     Do
  349.         ellipse cx, cy, lastr, 29 / 35 * pr
  350.         lastr = .5 * (pr - lastr) + lastr + 1 / 35 * pr
  351.         If pr - lastr < 1 / 80 * pr Then Exit Do
  352.     Loop
  353.  
  354.     ' 'flickering candle light
  355.     'Color _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  356.  
  357.     ' eye sockets
  358.     ftri2 dh&, cx - 9 * pr / 12, cy - 2 * pr / 12, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  359.     ftri2 dh&, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, cx - 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  360.     ftri2 dh&, cx + 9 * pr / 12, cy - 2 * pr / 12, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  361.     ftri2 dh&, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, cx + 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  362.  
  363.     ' nose
  364.     ftri2 dh&, cx, cy - rand%(2, 5) * pr / 12, cx - 2 * pr / 12, cy + 2 * pr / 12, cx + rand%(1, 2) * pr / 12, cy + 2 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  365.  
  366.     ' evil grin
  367.     ftri2 dh&, cx - 9 * pr / 12, cy + 1 * pr / 12, cx - 7 * pr / 12, cy + 7 * pr / 12, cx - 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  368.     ftri2 dh&, cx + 9 * pr / 12, cy + 1 * pr / 12, cx + 7 * pr / 12, cy + 7 * pr / 12, cx + 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  369.  
  370.     ' moving teeth/talk/grrrr..
  371.     u = rand%(4, 8)
  372.     dx = pr / u
  373.     For i = 1 To u
  374.         tx1 = cx - 6 * pr / 12 + (i - 1) * dx
  375.         tx2 = tx1 + .5 * dx
  376.         tx3 = tx1 + dx
  377.         ty1 = cy + 5 * pr / 12
  378.         ty3 = cy + 5 * pr / 12
  379.         ty2 = cy + (4 - Rnd) * pr / 12
  380.         ty22 = cy + (6 + Rnd) * pr / 12
  381.         ftri2 dh&, tx1, ty1, tx2, ty2, tx3, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  382.         ftri2 dh&, tx1 + .5 * dx, ty1, tx2 + .5 * dx, ty22, tx3 + .5 * dx, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  383.     Next
  384.     If limit Then
  385.         'shifty eyes
  386.         If limit = 3 Then sxs = sx Else sxs = .1 * limit * sx
  387.         pumpkin dh&, sxs + cx - 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  388.         pumpkin dh&, sxs + cx + 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  389.     End If
  390.  
  391. Sub fEllipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  392.     Dim scale As Single, x As Long, y As Long
  393.     scale = yRadius / xRadius
  394.     Line (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  395.     For x = 1 To xRadius
  396.         y = scale * Sqr(xRadius * xRadius - x * x)
  397.         Line (CX + x, CY - y)-(CX + x, CY + y), , BF
  398.         Line (CX - x, CY - y)-(CX - x, CY + y), , BF
  399.     Next
  400.  
  401. Sub ellipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  402.     Dim scale As Single, xs As Long, x As Long, y As Long
  403.     Dim lastx As Long, lasty As Long
  404.     scale = yRadius / xRadius: xs = xRadius * xRadius
  405.     PSet (CX, CY - yRadius): PSet (CX, CY + yRadius)
  406.     lastx = 0: lasty = yRadius
  407.     For x = 1 To xRadius
  408.         y = scale * Sqr(xs - x * x)
  409.         Line (CX + lastx, CY - lasty)-(CX + x, CY - y)
  410.         Line (CX + lastx, CY + lasty)-(CX + x, CY + y)
  411.         Line (CX - lastx, CY - lasty)-(CX - x, CY - y)
  412.         Line (CX - lastx, CY + lasty)-(CX - x, CY + y)
  413.         lastx = x: lasty = y
  414.     Next
  415.  
  416. Sub ftri2 (returnDest&, x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  417.     Dim a&
  418.     a& = _NewImage(1, 1, 32)
  419.     _Dest a&
  420.     PSet (0, 0), K
  421.     _Dest returnDest&
  422.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  423.     _FreeImage a& '<<< this is important!
  424.  
  425. Function rand% (lo%, hi%)
  426.     rand% = Int(Rnd * (hi% - lo% + 1)) + lo%
  427.  
  428.  
  429.  
  430. Sub drawLink (x1, y1, r1, x2, y2, r2, c As _Unsigned Long)
  431.     Dim a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  432.     a = _Atan2(y2 - y1, x2 - x1)
  433.     a1 = a + _Pi(1 / 2)
  434.     a2 = a - _Pi(1 / 2)
  435.     x3 = x1 + r1 * Cos(a1): y3 = y1 + r1 * Sin(a1)
  436.     x4 = x1 + r1 * Cos(a2): y4 = y1 + r1 * Sin(a2)
  437.     x5 = x2 + r2 * Cos(a1): y5 = y2 + r2 * Sin(a1)
  438.     x6 = x2 + r2 * Cos(a2): y6 = y2 + r2 * Sin(a2)
  439.     fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  440.     Fcirc x1, y1, r1, c
  441.     Fcirc x2, y2, r2, c
  442.  
  443. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  444. Sub fquad (x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, x3 As Integer, y3 As Integer, x4 As Integer, y4 As Integer, c As _Unsigned Long)
  445.     ftri x1, y1, x2, y2, x4, y4, c
  446.     ftri x3, y3, x4, y4, x1, y1, c
  447.  
  448. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  449.     Dim a&
  450.     a& = _NewImage(1, 1, 32)
  451.     _Dest a&
  452.     PSet (0, 0), K
  453.     _Dest 0
  454.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  455.     _FreeImage a& '<<< this is important!
  456.  
  457. Sub TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c As _Unsigned Long)
  458.     Dim max As Integer, mx2 As Integer, i As Integer, j As Integer, k As Single, lasti As Single, lastj As Single
  459.     Dim prc As _Unsigned Long, tef As Long
  460.     prc = _RGB32(255, 255, 255, 255)
  461.     If a > b Then max = a + 1 Else max = b + 1
  462.     mx2 = max + max
  463.     tef = _NewImage(mx2, mx2)
  464.     _Dest tef
  465.     _Source tef 'point wont read without this!
  466.     For k = 0 To 6.2832 + .05 Step .1
  467.         i = max + a * Cos(k) * Cos(ang) + b * Sin(k) * Sin(ang)
  468.         j = max + a * Cos(k) * Sin(ang) - b * Sin(k) * Cos(ang)
  469.         If k <> 0 Then
  470.             Line (lasti, lastj)-(i, j), prc
  471.         Else
  472.             PSet (i, j), prc
  473.         End If
  474.         lasti = i: lastj = j
  475.     Next
  476.     Dim xleft(mx2) As Integer, xright(mx2) As Integer, x As Integer, y As Integer
  477.     For y = 0 To mx2
  478.         x = 0
  479.         While Point(x, y) <> prc And x < mx2
  480.             x = x + 1
  481.         Wend
  482.         xleft(y) = x
  483.         While Point(x, y) = prc And x < mx2
  484.             x = x + 1
  485.         Wend
  486.         While Point(x, y) <> prc And x < mx2
  487.             x = x + 1
  488.         Wend
  489.         If x = mx2 Then xright(y) = xleft(y) Else xright(y) = x
  490.     Next
  491.     _Dest destHandle&
  492.     For y = 0 To mx2
  493.         If xleft(y) <> mx2 Then Line (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  494.     Next
  495.     _FreeImage tef
  496.  
  497. Sub Fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
  498.     Dim Radius As Long, RadiusError As Long
  499.     Dim X As Long, Y As Long
  500.     Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
  501.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  502.     Line (CX - X, CY)-(CX + X, CY), C, BF
  503.     While X > Y
  504.         RadiusError = RadiusError + Y * 2 + 1
  505.         If RadiusError >= 0 Then
  506.             If X <> Y + 1 Then
  507.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  508.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  509.             End If
  510.             X = X - 1
  511.             RadiusError = RadiusError - X * 2
  512.         End If
  513.         Y = Y + 1
  514.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  515.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  516.     Wend
  517.  
  518. Sub drawSpinner (x As Integer, y As Integer, scale As Single, heading As Single, c As _Unsigned Long)
  519.     Dim x1, x2, x3, x4, y1, y2, y3, y4, r, a, a1, a2, lg, d, rd
  520.     Dim rred, bblue, ggreen
  521.     Static switch As Integer
  522.     switch = switch + 2
  523.     switch = switch Mod 16 + 1
  524.     rred = _Red32(c): ggreen = _Green32(c): bblue = _Blue32(c)
  525.     r = 10 * scale
  526.     x1 = x + r * Cos(heading): y1 = y + r * Sin(heading)
  527.     r = 2 * r 'lg lengths
  528.     For lg = 1 To 8
  529.         If lg < 5 Then
  530.             a = heading + .9 * lg * _Pi(1 / 5) + (lg = switch) * _Pi(1 / 10)
  531.         Else
  532.             a = heading - .9 * (lg - 4) * _Pi(1 / 5) - (lg = switch) * _Pi(1 / 10)
  533.         End If
  534.         x2 = x1 + r * Cos(a): y2 = y1 + r * Sin(a)
  535.         drawLink x1, y1, 3 * scale, x2, y2, 2 * scale, _RGB32(rred + 20, ggreen + 10, bblue + 5)
  536.         If lg = 1 Or lg = 2 Or lg = 7 Or lg = 8 Then d = -1 Else d = 1
  537.         a1 = a + d * _Pi(1 / 12)
  538.         x3 = x2 + r * 1.5 * Cos(a1): y3 = y2 + r * 1.5 * Sin(a1)
  539.         drawLink x2, y2, 2 * scale, x3, y3, scale, _RGB32(rred + 35, ggreen + 17, bblue + 8)
  540.         rd = Int(Rnd * 8) + 1
  541.         a2 = a1 + d * _Pi(1 / 8) * rd / 8
  542.         x4 = x3 + r * 1.5 * Cos(a2): y4 = y3 + r * 1.5 * Sin(a2)
  543.         drawLink x3, y3, scale, x4, y4, scale, _RGB32(rred + 50, ggreen + 25, bblue + 12)
  544.     Next
  545.     r = r * .5
  546.     Fcirc x1, y1, r, _RGB32(rred - 20, ggreen - 10, bblue - 5)
  547.     x2 = x1 + (r + 1) * Cos(heading - _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading - _Pi(1 / 12))
  548.     Fcirc x2, y2, r * .2, &HFF000000
  549.     x2 = x1 + (r + 1) * Cos(heading + _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading + _Pi(1 / 12))
  550.     Fcirc x2, y2, r * .2, &HFF000000
  551.     r = r * 2
  552.     x1 = x + r * .9 * Cos(heading + _Pi): y1 = y + r * .9 * Sin(heading + _Pi)
  553.     TiltedEllipseFill 0, x1, y1, r, .7 * r, heading + _Pi, _RGB32(rred, ggreen, bblue)
  554.  
  555.  

For Pete:
 
Human wins qm.PNG


For friends at Syntax Bomb the Windows compiled version and source:
(Updated just before midnight, only one download before update)
* One Key Connect 4 (8x8) Halloween Style.zip (Filesize: 841.69 KB, Downloads: 116)
« Last Edit: October 19, 2021, 11:59:40 pm by bplus »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #7 on: October 19, 2021, 10:01:23 pm »
I like the original version better, but then I'm impatient. I see my avatar stomping that pumpkin into place with his tiny Western boots.

If I had one suggestion to make this version better, it would be to add a gravity factor, so the pumpkin picks up speed as it falls.

I thought you might make it shake a bit as it falls, although the last time I played this game, I was 8.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #8 on: October 19, 2021, 11:15:17 pm »
delaid variable in _Limit increases allowing more loop updates per second.
Not just gravity, frictional force works against complete freefall of piece. I thought it noticeable specially at the beginning.
Code: QB64: [Select]
  1.                         While y < target
  2.                             y = y + 1
  3.                             Cls
  4.                             _PutImage , temp&, 0
  5.                             pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 3
  6.                             sx = Rnd * 6 - 3
  7.                             _Display
  8.                             _Limit delaid
  9.                             delaid = delaid + 2
  10.                         Wend
  11.  



Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #9 on: October 19, 2021, 11:57:17 pm »
OK I sped up the drop, decreased the Timer difference from 4 to 2 secs and it turns out the screen update sub ShowGrid is fast enough that I don't have to take a screen snapshot so the pumpkins and spiders remain quite active as the pumpkin piece drops down the column.

Modified to this section in code:
Code: QB64: [Select]
  1.                 If Timer - t > 2 And place <> -1 Then ' col selected
  2.                     r = GetOpenRow(place)
  3.                     If r <> NumRows Then
  4.                         y = SQ + SQ / 2
  5.                         target = r * SQ + YO + SQ / 2
  6.                         delaid = 6
  7.                         While y < target
  8.                             y = y + 1
  9.                             Cls
  10.                             ShowGrid
  11.                             pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 3
  12.                             sx = Rnd * 6 - 3
  13.                             _Display
  14.                             _Limit delaid
  15.                             delaid = delaid * 2
  16.                         Wend
  17.                         Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  18.                         place = -1 ' reset back to hold area
  19.                     Else
  20.                         Beep
  21.                     End If
  22.                 End If
  23.  

I have changed out the old zip file in Best Answer with the new code source and Windows compiled .exe, so it is still Best Answer and spiders and pumpkins all move while piece falls into place.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #10 on: October 20, 2021, 12:36:54 am »
Better. Either that, or I'm just in a better mood because after 7 games, I finally beat the A.I.

Pete 👠 Woooohoooo!
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #11 on: October 22, 2021, 11:14:26 am »
I added that board overlay I was talking about.

Code: QB64: [Select]
  1. 'OPTION _EXPLICIT ' One Key Connect 4 (8x8) Halloween Style - bplus 2021-10-19
  2. CONST SQ = 60 '       square or grid cell
  3. CONST NumCols = 8 '   number of columns
  4. CONST NumRows = 8 '   you guessed it
  5. CONST NCM1 = NumCols - 1 ' NumCols minus 1
  6. CONST NRM1 = NumRows - 1 ' you can guess surely
  7. CONST SW = SQ * (NumCols + 2) '  screen width
  8. CONST SH = SQ * (NumRows + 3) '  screen height
  9. CONST P = 1 '       Player is 1 on grid
  10. CONST AI = -1 '     AI is -1 on grid
  11. CONST XO = SQ '     x offset for grid
  12. CONST YO = 2 * SQ ' y offset for grid
  13.  
  14. REDIM SHARED Grid(NCM1, NRM1) ' 0 = empty  P=1 for Player,  AI=-1  for AI so -4 is win for AI..
  15. REDIM SHARED DX(7), DY(7) ' Directions
  16. DX(0) = 1: DY(0) = 0 ': DString$(0) = "East"
  17. DX(1) = 1: DY(1) = 1 ': DString$(1) = "South East"
  18. DX(2) = 0: DY(2) = 1 ': DString$(2) = "South"
  19. DX(3) = -1: DY(3) = 1 ': DString$(3) = "South West"
  20. DX(4) = -1: DY(4) = 0 ': DString$(4) = "West"
  21. DX(5) = -1: DY(5) = -1 ': DString$(5) = "North West"
  22. DX(6) = 0: DY(6) = -1 ': DString$(6) = "North"
  23. DX(7) = 1: DY(7) = -1 ' : DString$(7) = "North East"
  24. REDIM SHARED Scores(NCM1) ' rating column for AI and displaying them
  25. REDIM SHARED AIX, AIY ' last move of AI for highlighting in display
  26. REDIM SHARED WinX, WinY, WinD ' display Winning Connect 4
  27. REDIM SHARED GameOn, Turn, GoFirst, PlayerLastMoveCol, PlayerLastMoveRow, MoveNum ' game tracking
  28. REDIM SHARED Record$(NCM1, NRM1)
  29. DIM SHARED sx ' for pumpkin recursion shifty eyes
  30. DIM place, k$, t, r, s$, pr, d, temp&, target, y, delaid
  31. DIM SHARED Overlay& 'the board overlay
  32.  
  33. SCREEN _NEWIMAGE(SW, SH, 32)
  34. _SCREENMOVE 360, 60
  35. Overlay& = _NEWIMAGE(SW, SH, 32)
  36. Create_Board
  37.  
  38. _TITLE "One Key Connect 4 (8x8) Halloween Style"
  39. d = 1
  40. WHILE _KEYDOWN(32) = 0
  41.  CLS
  42.  pumpkin 0, _WIDTH / 2, _HEIGHT / 2, _HEIGHT / 2.3, 3
  43.  sx = sx + d
  44.  IF sx > 10 THEN d = -d: sx = 10
  45.  IF sx < -10 THEN d = -d: sx = -10
  46.  COLOR &HFFFFFFFF, &HFF000000:
  47.  LOCATE 40, 33: PRINT "Spacebar Only"
  48.  _LIMIT 20
  49. GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0
  50. ShowGrid
  51. place = -1
  52. t = TIMER
  53. pr = (SQ - 6) / 2
  54. WHILE GameOn
  55.  CLS
  56.  IF Turn = P THEN
  57.   k$ = INKEY$
  58.   IF k$ = CHR$(27) THEN SYSTEM ' emergency exit
  59.   IF k$ = " " THEN
  60.    t = TIMER: place = place + 1
  61.    IF place >= NumCols THEN place = -1
  62.   ELSE ' watch out for midnight!
  63.    IF TIMER - t < 0 THEN 'midnight problem
  64.     t = TIMER ' wait a little longer
  65.    ELSE
  66.     IF TIMER - t > 2 AND place <> -1 THEN ' col selected
  67.      r = GetOpenRow(place)
  68.      IF r <> NumRows THEN
  69.       y = SQ + SQ / 2
  70.       target = r * SQ + YO + SQ / 2
  71.       delaid = 6
  72.       WHILE y < target
  73.        y = y + 1
  74.        CLS
  75.        ShowGrid
  76.        pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 3
  77.        sx = RND * 6 - 3
  78.        _PUTIMAGE , Overlay&, _DISPLAY
  79.        _DISPLAY
  80.        _LIMIT delaid
  81.        delaid = delaid * 2
  82.       WEND
  83.       Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  84.       place = -1 ' reset back to hold area
  85.      ELSE
  86.       BEEP
  87.      END IF
  88.     END IF
  89.    END IF
  90.   END IF
  91.   AIMove
  92.   Turn = P: MoveNum = MoveNum + 1: t = TIMER
  93.  ShowGrid
  94.  IF Turn = P THEN
  95.   IF place = -1 THEN
  96.    s$ = "Holding area, press spacebar until over column to play."
  97.   ELSE
  98.    s$ = "Press Spacebar, if don't want to play" + STR$(place) + " column."
  99.   END IF
  100.   COLOR &HFFFFFFFF, 0
  101.   _PRINTSTRING (XO, YO - SQ - 16), s$
  102.  pumpkin 0, place * SQ + XO + SQ / 2, SQ + SQ / 2, pr, 3
  103.  sx = RND * 6 - 3
  104.  _PUTIMAGE , Overlay&, _DISPLAY
  105.  _LIMIT 15
  106.  
  107. SUB AIMove
  108.  ' What this sub does in English:
  109.  ' This sub assigns the value to playing each column, then plays the best value with following caveats:
  110.  ' + If it finds a winning move, it will play that immediately.
  111.  ' + If it finds a spoiler move, it will play that if no winning move was found.
  112.  ' + It will poisen the column's scoring, if opponent can play a winning move if AI plays this column,
  113.  '   but it might be the only legal move left.  We will have to play it if no better score was found.
  114.  
  115.  DIM c, r, d, cntA, cntP, bestScore, startR, startC, iStep, test, goodF, i
  116.  DIM openRow(NCM1) ' find open rows once
  117.  REDIM Scores(NCM1) ' evaluate each column's potential
  118.  AIX = -1: AIY = -1 ' set these when AI makes move, they are signal to display procedure AI's move.
  119.  FOR c = 0 TO NCM1
  120.   openRow(c) = GetOpenRow(c)
  121.   r = openRow(c)
  122.   IF r <> NumRows THEN
  123.    FOR d = 0 TO 3 ' 4 directions to build connect 4's that use cell c, r
  124.     startC = c + -3 * DX(d): startR = r + -3 * DY(d)
  125.     FOR i = 0 TO 3 ' here we backup from the potential connect 4 in opposite build direction of c, r
  126.      cntA = 0: cntP = 0: goodF = -1 ' reset counts and flag for good connect 4
  127.      'from this start position run 4 steps forward to count all connects involving cell c, r
  128.      FOR iStep = 0 TO 3 ' process a potential connect 4
  129.       test = GR(startC + i * DX(d) + iStep * DX(d), startR + i * DY(d) + iStep * DY(d))
  130.       IF test = NumRows THEN goodF = 0: EXIT FOR 'cant get connect4 from here
  131.       IF test = AI THEN cntA = cntA + 1
  132.       IF test = P THEN cntP = cntP + 1
  133.      NEXT iStep
  134.      IF goodF THEN 'evaluate the Legal Connect4 we could build with c, r
  135.       IF cntA = 3 THEN ' we are done!  winner!
  136.        AIX = c: AIY = r ' <<< this is the needed 4th cell to win tell ShowGrid last cell
  137.        Grid(c, r) = AI '  <<< this is the needed 4th cell to win, add to grid this is AI move
  138.        Scores(c) = 1000
  139.        EXIT SUB
  140.       ELSEIF cntP = 3 THEN 'next best move spoiler!
  141.        AIX = c: AIY = r 'set the move but don't exit there might be a winner
  142.        Scores(c) = 900
  143.       ELSEIF cntA = 0 AND cntP = 2 THEN
  144.        Scores(c) = Scores(c) + 8
  145.       ELSEIF cntA = 2 AND cntP = 0 THEN ' very good offense or defense
  146.        Scores(c) = Scores(c) + 4 'play this to connect 3 or prevent player from Connect 3
  147.       ELSEIF cntA = 0 AND cntP = 1 THEN
  148.        Scores(c) = Scores(c) + 4
  149.       ELSEIF (cntA = 1 AND cntP = 0) THEN 'good offense or defense
  150.        Scores(c) = Scores(c) + 2 ' play this to connect 2 or prevent player from Connect 2
  151.       ELSEIF (cntA = 0 AND cntP = 0) THEN ' OK it's not a wasted move as it has potential for connect4
  152.        Scores(c) = Scores(c) + 1 ' this is good move because this can still be a Connect 4
  153.       END IF
  154.      END IF ' in the board
  155.     NEXT i
  156.    NEXT d
  157.    IF Stupid(c, r) THEN Scores(c) = -1000 + Scores(c) ' poison because if played the human can win
  158.   END IF
  159.  IF AIX <> -1 THEN ' we found a spoiler so move there since we haven't found a winner
  160.   Grid(AIX, AIY) = AI ' make move on grid and done!
  161.   IF GetOpenRow(PlayerLastMoveCol) < NumRows THEN 'all things being equal play on top of player's last move
  162.    bestScore = Scores(PlayerLastMoveCol): AIY = PlayerLastMoveRow - 1: AIX = PlayerLastMoveCol
  163.   ELSE
  164.    bestScore = -1000 ' a negative score indicates that the player can beat AI with their next move
  165.   END IF
  166.   FOR c = 0 TO NCM1
  167.    r = openRow(c)
  168.    IF r <> NumRows THEN
  169.     IF Scores(c) > bestScore THEN bestScore = Scores(c): AIY = r: AIX = c
  170.    END IF
  171.   NEXT
  172.   IF AIX <> -1 THEN
  173.    Grid(AIX, AIY) = AI ' make first best score move we found
  174.   ELSE 'We have trouble!  Oh but it could be there are no moves!!!
  175.    ' checkWin is run after every move by AI or Player if there were no legal moves left it should have caught that.
  176.    ' Just in case it didn't here is an error stop!
  177.    BEEP: LOCATE 4, 2: PRINT "AI has failed to find a proper move, press any to end..."
  178.    SLEEP ' <<< pause until user presses a key
  179.    END
  180.   END IF
  181.  
  182. FUNCTION GetOpenRow (forCol)
  183.  DIM i
  184.  GetOpenRow = NumRows 'assume none open
  185.  IF forCol < 0 OR forCol > NCM1 THEN EXIT FUNCTION
  186.  FOR i = NRM1 TO 0 STEP -1
  187.   IF Grid(forCol, i) = 0 THEN GetOpenRow = i: EXIT FUNCTION
  188.  
  189. FUNCTION Stupid (c, r)
  190.  DIM pr
  191.  Grid(c, r) = AI
  192.  pr = GetOpenRow(c)
  193.  IF pr <> NumRows THEN
  194.   Grid(c, pr) = P
  195.   IF CheckWin = 4 THEN Stupid = -1
  196.   Grid(c, pr) = 0
  197.  Grid(c, r) = 0
  198.  
  199. FUNCTION GR (c, r) ' if c, r are out of bounds returns N else returns grid(c, r)
  200.  ' need to check the grid(c, r) but only if c, r is on the board
  201.  IF c < 0 OR c > NCM1 OR r < 0 OR r > NRM1 THEN GR = NumRows ELSE GR = Grid(c, r)
  202.  
  203. SUB ShowGrid
  204.  STATIC lastMoveNum
  205.  DIM i, r, c, check, s$, k$
  206.  IF MoveNum <> lastMoveNum THEN ' file newest move
  207.   IF MoveNum = 1 THEN REDIM Record$(NCM1, NRM1)
  208.   IF Turn = -1 THEN
  209.    Record$(PlayerLastMoveCol, PlayerLastMoveRow) = _TRIM$(STR$(MoveNum)) + " " + "P"
  210.   ELSE
  211.    Record$(AIX, AIY) = _TRIM$(STR$(MoveNum)) + " " + "A"
  212.   END IF
  213.   lastMoveNum = MoveNum
  214.  'cls
  215.  LINE (XO, YO)-STEP(NumCols * SQ, NumRows * SQ), &HFF004400, BF
  216.  FOR i = 0 TO NumCols 'grid
  217.   LINE (SQ * i + XO, YO)-STEP(0, NumRows * SQ), &HFFFFFFFF
  218.  FOR i = 0 TO NumRows
  219.   LINE (XO, SQ * i + YO)-STEP(NumCols * SQ, 0), &HFFFFFFFF
  220.  FOR r = NRM1 TO 0 STEP -1 ''in grid rows are reversed 0 is top row
  221.   FOR c = 0 TO NCM1
  222.    IF Grid(c, r) = P THEN
  223.     LINE (c * SQ + XO + 3, r * SQ + YO + 3)-STEP(SQ - 6, SQ - 6), &HFF000000, BF
  224.     pumpkin 0, c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, (SQ - 6) / 2, 2
  225.  
  226.    ELSEIF Grid(c, r) = AI THEN
  227.     IF c = AIX AND r = AIY THEN 'highlite last AI move
  228.      LINE (c * SQ + XO + 3, r * SQ + YO + 3)-STEP(SQ - 6, SQ - 6), &HFF8888FF, BF
  229.     ELSE
  230.      LINE (c * SQ + XO + 3, r * SQ + YO + 3)-STEP(SQ - 6, SQ - 6), &HFF4444FF, BF
  231.     END IF
  232.     drawSpinner c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, .5, _PI(-c / 8), _RGB32(RND * 30 + 40, RND * 15 + 20, RND * 6 + 10)
  233.    END IF
  234.    s$ = _TRIM$(STR$(Scores(c)))
  235.    _PRINTSTRING (XO + c * SQ + (60 - LEN(s$) * 8) / 2, YO + SQ * NumRows + 22), s$
  236.   NEXT
  237.  '_Display
  238.  check = CheckWin
  239.  IF check THEN 'report end of round ad see if want to play again
  240.   IF check = 4 OR check = -4 THEN
  241.    FOR i = 0 TO 3
  242.     LINE ((WinX + i * DX(WinD)) * SQ + XO + 5, (WinY + i * DY(WinD)) * SQ + YO + 5)-STEP(SQ - 10, SQ - 10), &HFFFFFF00, B
  243.    NEXT
  244.   END IF
  245.   FOR r = 0 TO NRM1
  246.    FOR c = 0 TO NCM1
  247.     IF Record$(c, r) <> "" THEN
  248.      s$ = MID$(Record$(c, r), 1, INSTR(Record$(c, r), " ") - 1)
  249.      IF RIGHT$(Record$(c, r), 1) = "A" THEN COLOR &HFFFFFFFF, &HFF000000 ELSE COLOR &HFFFFFFFF, &HFF000000
  250.      _PRINTSTRING (SQ * c + XO + (SQ - LEN(s$) * 8) / 2, SQ * r + YO + 22), s$
  251.     END IF
  252.    NEXT
  253.    COLOR , &HFF000000
  254.   NEXT
  255.   IF check = -4 THEN
  256.    s$ = " AI is Winner!"
  257.   ELSEIF check = 4 THEN
  258.    s$ = " Human is Winner!"
  259.   ELSEIF check = NumRows THEN
  260.    s$ = " Board is full, no winner." ' keep Turn the same
  261.   END IF
  262.   LOCATE 2, ((SW - LEN(s$) * 8) / 2) / 8: PRINT s$
  263.   s$ = " Play again? press spacebar, escape to quit... "
  264.   LOCATE 4, ((SW - LEN(s$) * 8) / 2) / 8: PRINT s$
  265.   _PUTIMAGE , Overlay&, _DISPLAY
  266.   keywait:
  267.   WHILE LEN(k$) = 0
  268.    k$ = INKEY$
  269.    _LIMIT 200
  270.   WEND
  271.   IF k$ = " " THEN
  272.    REDIM Grid(NCM1, NRM1), Scores(NCM1)
  273.    IF GoFirst = P THEN GoFirst = AI ELSE GoFirst = P
  274.    Turn = GoFirst: MoveNum = 0
  275.   ELSEIF ASC(k$) = 27 THEN
  276.    SYSTEM
  277.   ELSE
  278.    k$ = "": GOTO keywait:
  279.   END IF
  280.  
  281. FUNCTION CheckWin ' return WinX, WinY, WinD along with +/- 4, returns NumRows if grid full, 0 if no win and grid not full
  282.  DIM gridFull, r, c, s, i
  283.  gridFull = NumRows
  284.  FOR r = NRM1 TO 0 STEP -1 'bottom to top
  285.   FOR c = 0 TO NCM1
  286.    IF Grid(c, r) THEN ' check if c starts a row
  287.     IF c < NCM1 - 2 THEN
  288.      s = 0
  289.      FOR i = 0 TO 3 ' east
  290.       s = s + Grid(c + i, r)
  291.      NEXT
  292.      IF s = 4 OR s = -4 THEN WinX = c: WinY = r: WinD = 0: CheckWin = s: EXIT FUNCTION
  293.     END IF
  294.     IF r > 2 THEN ' check if c starts a col
  295.      s = 0
  296.      FOR i = 0 TO 3 ' north
  297.       s = s + Grid(c, r - i)
  298.      NEXT
  299.      IF s = 4 OR s = -4 THEN WinX = c: WinY = r: WinD = 6: CheckWin = s: EXIT FUNCTION
  300.     END IF
  301.     IF r > 2 AND c < NCM1 - 2 THEN 'check if c starts diagonal up to right
  302.      s = 0
  303.      FOR i = 0 TO 3 ' north  east
  304.       s = s + Grid(c + i, r - i)
  305.      NEXT
  306.      IF s = 4 OR s = -4 THEN WinX = c: WinY = r: WinD = 7: CheckWin = s: EXIT FUNCTION
  307.     END IF
  308.     IF r > 2 AND c > 2 THEN 'check if c starts a diagonal up to left
  309.      s = 0
  310.      FOR i = 0 TO 3 ' north west
  311.       s = s + Grid(c - i, r - i)
  312.      NEXT
  313.      IF s = 4 OR s = -4 THEN WinX = c: WinY = r: WinD = 5: CheckWin = s: EXIT FUNCTION
  314.     END IF
  315.    ELSE
  316.     gridFull = 0 ' at least one enpty cell left
  317.    END IF 'grid is something
  318.   NEXT
  319.  CheckWin = gridFull
  320.  
  321.  
  322. SUB pumpkin (dh&, cx, cy, pr, limit)
  323.  DIM lastr, u, dx, i, tx1, tx2, tx3, ty1, ty2, ty3, ty22, sxs
  324.  'carve this!
  325.  COLOR &HFFFF0000
  326.  fEllipse cx, cy, pr, 29 / 35 * pr
  327.  COLOR &HFF000000
  328.  lastr = 2 / 7 * pr
  329.  DO
  330.   ellipse cx, cy, lastr, 29 / 35 * pr
  331.   lastr = .5 * (pr - lastr) + lastr + 1 / 35 * pr
  332.   IF pr - lastr < 1 / 80 * pr THEN EXIT DO
  333.  
  334.  ' 'flickering candle light
  335.  'Color _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  336.  
  337.  ' eye sockets
  338.  ftri2 dh&, cx - 9 * pr / 12, cy - 2 * pr / 12, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  339.  ftri2 dh&, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, cx - 2 * pr / 12, cy - 3 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  340.  ftri2 dh&, cx + 9 * pr / 12, cy - 2 * pr / 12, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  341.  ftri2 dh&, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, cx + 2 * pr / 12, cy - 3 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  342.  
  343.  ' nose
  344.  ftri2 dh&, cx, cy - rand%(2, 5) * pr / 12, cx - 2 * pr / 12, cy + 2 * pr / 12, cx + rand%(1, 2) * pr / 12, cy + 2 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  345.  
  346.  ' evil grin
  347.  ftri2 dh&, cx - 9 * pr / 12, cy + 1 * pr / 12, cx - 7 * pr / 12, cy + 7 * pr / 12, cx - 6 * pr / 12, cy + 5 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  348.  ftri2 dh&, cx + 9 * pr / 12, cy + 1 * pr / 12, cx + 7 * pr / 12, cy + 7 * pr / 12, cx + 6 * pr / 12, cy + 5 * pr / 12, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  349.  
  350.  ' moving teeth/talk/grrrr..
  351.  u = rand%(4, 8)
  352.  dx = pr / u
  353.  FOR i = 1 TO u
  354.   tx1 = cx - 6 * pr / 12 + (i - 1) * dx
  355.   tx2 = tx1 + .5 * dx
  356.   tx3 = tx1 + dx
  357.   ty1 = cy + 5 * pr / 12
  358.   ty3 = cy + 5 * pr / 12
  359.   ty2 = cy + (4 - RND) * pr / 12
  360.   ty22 = cy + (6 + RND) * pr / 12
  361.   ftri2 dh&, tx1, ty1, tx2, ty2, tx3, ty3, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  362.   ftri2 dh&, tx1 + .5 * dx, ty1, tx2 + .5 * dx, ty22, tx3 + .5 * dx, ty3, _RGB(RND * 55 + 200, RND * 55 + 200, 120)
  363.  IF limit THEN
  364.   'shifty eyes
  365.   IF limit = 3 THEN sxs = sx ELSE sxs = .1 * limit * sx
  366.   pumpkin dh&, sxs + cx - 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, INT(limit - 1)
  367.   pumpkin dh&, sxs + cx + 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, INT(limit - 1)
  368.  
  369. SUB fEllipse (CX AS LONG, CY AS LONG, xRadius AS LONG, yRadius AS LONG)
  370.  DIM scale AS SINGLE, x AS LONG, y AS LONG
  371.  scale = yRadius / xRadius
  372.  LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  373.  FOR x = 1 TO xRadius
  374.   y = scale * SQR(xRadius * xRadius - x * x)
  375.   LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  376.   LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  377.  
  378. SUB ellipse (CX AS LONG, CY AS LONG, xRadius AS LONG, yRadius AS LONG)
  379.  DIM scale AS SINGLE, xs AS LONG, x AS LONG, y AS LONG
  380.  DIM lastx AS LONG, lasty AS LONG
  381.  scale = yRadius / xRadius: xs = xRadius * xRadius
  382.  PSET (CX, CY - yRadius): PSET (CX, CY + yRadius)
  383.  lastx = 0: lasty = yRadius
  384.  FOR x = 1 TO xRadius
  385.   y = scale * SQR(xs - x * x)
  386.   LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  387.   LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  388.   LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  389.   LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  390.   lastx = x: lasty = y
  391.  
  392. SUB ftri2 (returnDest&, x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  393.  DIM a&
  394.  a& = _NEWIMAGE(1, 1, 32)
  395.  _DEST a&
  396.  PSET (0, 0), K
  397.  _DEST returnDest&
  398.  _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  399.  _FREEIMAGE a& '<<< this is important!
  400.  
  401. FUNCTION rand% (lo%, hi%)
  402.  rand% = INT(RND * (hi% - lo% + 1)) + lo%
  403.  
  404.  
  405.  
  406. SUB drawLink (x1, y1, r1, x2, y2, r2, c AS _UNSIGNED LONG)
  407.  DIM a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  408.  a = _ATAN2(y2 - y1, x2 - x1)
  409.  a1 = a + _PI(1 / 2)
  410.  a2 = a - _PI(1 / 2)
  411.  x3 = x1 + r1 * COS(a1): y3 = y1 + r1 * SIN(a1)
  412.  x4 = x1 + r1 * COS(a2): y4 = y1 + r1 * SIN(a2)
  413.  x5 = x2 + r2 * COS(a1): y5 = y2 + r2 * SIN(a1)
  414.  x6 = x2 + r2 * COS(a2): y6 = y2 + r2 * SIN(a2)
  415.  fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  416.  Fcirc x1, y1, r1, c
  417.  Fcirc x2, y2, r2, c
  418.  
  419. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  420. SUB fquad (x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER, x3 AS INTEGER, y3 AS INTEGER, x4 AS INTEGER, y4 AS INTEGER, c AS _UNSIGNED LONG)
  421.  ftri x1, y1, x2, y2, x4, y4, c
  422.  ftri x3, y3, x4, y4, x1, y1, c
  423.  
  424. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  425.  DIM a&
  426.  a& = _NEWIMAGE(1, 1, 32)
  427.  _DEST a&
  428.  PSET (0, 0), K
  429.  _DEST 0
  430.  _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  431.  _FREEIMAGE a& '<<< this is important!
  432.  
  433. SUB TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  434.  DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER, k AS SINGLE, lasti AS SINGLE, lastj AS SINGLE
  435.  DIM prc AS _UNSIGNED LONG, tef AS LONG
  436.  prc = _RGB32(255, 255, 255, 255)
  437.  IF a > b THEN max = a + 1 ELSE max = b + 1
  438.  mx2 = max + max
  439.  tef = _NEWIMAGE(mx2, mx2)
  440.  _DEST tef
  441.  _SOURCE tef 'point wont read without this!
  442.  FOR k = 0 TO 6.2832 + .05 STEP .1
  443.   i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  444.   j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  445.   IF k <> 0 THEN
  446.    LINE (lasti, lastj)-(i, j), prc
  447.   ELSE
  448.    PSET (i, j), prc
  449.   END IF
  450.   lasti = i: lastj = j
  451.  DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  452.  FOR y = 0 TO mx2
  453.   x = 0
  454.   WHILE POINT(x, y) <> prc AND x < mx2
  455.    x = x + 1
  456.   WEND
  457.   xleft(y) = x
  458.   WHILE POINT(x, y) = prc AND x < mx2
  459.    x = x + 1
  460.   WEND
  461.   WHILE POINT(x, y) <> prc AND x < mx2
  462.    x = x + 1
  463.   WEND
  464.   IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  465.  _DEST destHandle&
  466.  FOR y = 0 TO mx2
  467.   IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  468.  
  469. SUB Fcirc (CX AS LONG, CY AS LONG, R AS LONG, C AS _UNSIGNED LONG)
  470.  DIM Radius AS LONG, RadiusError AS LONG
  471.  DIM X AS LONG, Y AS LONG
  472.  Radius = ABS(R): RadiusError = -Radius: X = Radius: Y = 0
  473.  IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  474.  LINE (CX - X, CY)-(CX + X, CY), C, BF
  475.  WHILE X > Y
  476.   RadiusError = RadiusError + Y * 2 + 1
  477.   IF RadiusError >= 0 THEN
  478.    IF X <> Y + 1 THEN
  479.     LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  480.     LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  481.    END IF
  482.    X = X - 1
  483.    RadiusError = RadiusError - X * 2
  484.   END IF
  485.   Y = Y + 1
  486.   LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  487.   LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  488.  
  489. SUB drawSpinner (x AS INTEGER, y AS INTEGER, scale AS SINGLE, heading AS SINGLE, c AS _UNSIGNED LONG)
  490.  DIM x1, x2, x3, x4, y1, y2, y3, y4, r, a, a1, a2, lg, d, rd
  491.  DIM rred, bblue, ggreen
  492.  STATIC switch AS INTEGER
  493.  switch = switch + 2
  494.  switch = switch MOD 16 + 1
  495.  rred = _RED32(c): ggreen = _GREEN32(c): bblue = _BLUE32(c)
  496.  r = 10 * scale
  497.  x1 = x + r * COS(heading): y1 = y + r * SIN(heading)
  498.  r = 2 * r 'lg lengths
  499.  FOR lg = 1 TO 8
  500.   IF lg < 5 THEN
  501.    a = heading + .9 * lg * _PI(1 / 5) + (lg = switch) * _PI(1 / 10)
  502.   ELSE
  503.    a = heading - .9 * (lg - 4) * _PI(1 / 5) - (lg = switch) * _PI(1 / 10)
  504.   END IF
  505.   x2 = x1 + r * COS(a): y2 = y1 + r * SIN(a)
  506.   drawLink x1, y1, 3 * scale, x2, y2, 2 * scale, _RGB32(rred + 20, ggreen + 10, bblue + 5)
  507.   IF lg = 1 OR lg = 2 OR lg = 7 OR lg = 8 THEN d = -1 ELSE d = 1
  508.   a1 = a + d * _PI(1 / 12)
  509.   x3 = x2 + r * 1.5 * COS(a1): y3 = y2 + r * 1.5 * SIN(a1)
  510.   drawLink x2, y2, 2 * scale, x3, y3, scale, _RGB32(rred + 35, ggreen + 17, bblue + 8)
  511.   rd = INT(RND * 8) + 1
  512.   a2 = a1 + d * _PI(1 / 8) * rd / 8
  513.   x4 = x3 + r * 1.5 * COS(a2): y4 = y3 + r * 1.5 * SIN(a2)
  514.   drawLink x3, y3, scale, x4, y4, scale, _RGB32(rred + 50, ggreen + 25, bblue + 12)
  515.  r = r * .5
  516.  Fcirc x1, y1, r, _RGB32(rred - 20, ggreen - 10, bblue - 5)
  517.  x2 = x1 + (r + 1) * COS(heading - _PI(1 / 12)): y2 = y1 + (r + 1) * SIN(heading - _PI(1 / 12))
  518.  Fcirc x2, y2, r * .2, &HFF000000
  519.  x2 = x1 + (r + 1) * COS(heading + _PI(1 / 12)): y2 = y1 + (r + 1) * SIN(heading + _PI(1 / 12))
  520.  Fcirc x2, y2, r * .2, &HFF000000
  521.  r = r * 2
  522.  x1 = x + r * .9 * COS(heading + _PI): y1 = y + r * .9 * SIN(heading + _PI)
  523.  TiltedEllipseFill 0, x1, y1, r, .7 * r, heading + _PI, _RGB32(rred, ggreen, bblue)
  524.  
  525. SUB Create_Board
  526.  _DEST Overlay&
  527.  LINE (60, 120)-STEP(480, 480), _RGB32(180, 180, 16), BF
  528.  FOR y% = 0 TO 7
  529.   FOR x% = 0 TO 7
  530.    Fcirc 90 + 60 * x%, 150 + 60 * y%, 25, _RGB32(0)
  531.  NEXT x%, y%
  532.  _CLEARCOLOR _RGB32(0), Overlay&
  533.  
Granted after becoming radioactive I only have a half-life!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #12 on: October 22, 2021, 11:41:26 am »
@Cobalt Big fan of overlays! Color scheme of yellow on green? Um, not a big fan. Version also needs the pumpkin fall acceleration. It definitely reminded me of the old game apparatus, which was indeed, yellow. Overall, a really nice addition with the Connect 4 board look.

@bplus You might want to consider a space bar toggle for AI or two-player version. Wow, I was just thinking that it's been 20 years since I did networking routines for home networks. I mean it certainly could be used by two people on one computer, but over home network would be cool.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #13 on: October 22, 2021, 12:59:07 pm »
OK with overlay, but I changed color scheme so that background shows through empty holes, tiny adjustments in sizes of things and colors so the winning 4 is displayed.

Code: QB64: [Select]
  1. Option _Explicit ' One Key Connect 4 (8x8) Halloween Style - bplus 2021-10-19
  2. Const SQ = 60 '       square or grid cell
  3. Const NumCols = 8 '   number of columns
  4. Const NumRows = 8 '   you guessed it
  5. Const NCM1 = NumCols - 1 ' NumCols minus 1
  6. Const NRM1 = NumRows - 1 ' you can guess surely
  7. Const SW = SQ * (NumCols + 2) '  screen width
  8. Const SH = SQ * (NumRows + 3) '  screen height
  9. Const P = 1 '       Player is 1 on grid
  10. Const AI = -1 '     AI is -1 on grid
  11. Const XO = SQ '     x offset for grid
  12. Const YO = 2 * SQ ' y offset for grid
  13.  
  14. ReDim Shared Grid(NCM1, NRM1) ' 0 = empty  P=1 for Player,  AI=-1  for AI so -4 is win for AI..
  15. ReDim Shared DX(7), DY(7) ' Directions
  16. DX(0) = 1: DY(0) = 0 ': DString$(0) = "East"
  17. DX(1) = 1: DY(1) = 1 ': DString$(1) = "South East"
  18. DX(2) = 0: DY(2) = 1 ': DString$(2) = "South"
  19. DX(3) = -1: DY(3) = 1 ': DString$(3) = "South West"
  20. DX(4) = -1: DY(4) = 0 ': DString$(4) = "West"
  21. DX(5) = -1: DY(5) = -1 ': DString$(5) = "North West"
  22. DX(6) = 0: DY(6) = -1 ': DString$(6) = "North"
  23. DX(7) = 1: DY(7) = -1 ' : DString$(7) = "North East"
  24. ReDim Shared Scores(NCM1) ' rating column for AI and displaying them
  25. ReDim Shared AIX, AIY ' last move of AI for highlighting in display
  26. ReDim Shared WinX, WinY, WinD ' display Winning Connect 4
  27. ReDim Shared GameOn, Turn, GoFirst, PlayerLastMoveCol, PlayerLastMoveRow, MoveNum ' game tracking
  28. ReDim Shared Record$(NCM1, NRM1)
  29. Dim Shared sx, pr ' for pumpkin recursion shifty eyes and pumkin radius
  30. Dim place, k$, t, r, s$, d, temp&, target, y, delaid
  31. Dim Shared Overlay& 'the board overlay
  32.  
  33. Screen _NewImage(SW, SH, 32)
  34. _ScreenMove 360, 60
  35. Overlay& = _NewImage(SW, SH, 32)
  36. Create_Board
  37.  
  38. _Title "One Key Connect 4 (8x8) Halloween Style"
  39. d = 1
  40. While _KeyDown(32) = 0
  41.     Cls
  42.     pumpkin 0, _Width / 2, _Height / 2, _Height / 2.3, 3
  43.     sx = sx + d
  44.     If sx > 10 Then d = -d: sx = 10
  45.     If sx < -10 Then d = -d: sx = -10
  46.     Color &HFFFFFFFF
  47.     Locate 40, 33: Print "Spacebar Only"
  48.     _Display
  49.     _Limit 20
  50. GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0
  51. ShowGrid
  52. place = -1
  53. t = Timer
  54. pr = (SQ - 2) / 2
  55. While GameOn
  56.     Cls
  57.     If Turn = P Then
  58.         k$ = InKey$
  59.         If k$ = Chr$(27) Then System ' emergency exit
  60.         If k$ = " " Then
  61.             t = Timer: place = place + 1
  62.             If place >= NumCols Then place = -1
  63.         Else ' watch out for midnight!
  64.             If Timer - t < 0 Then 'midnight problem
  65.                 t = Timer ' wait a little longer
  66.             Else
  67.                 If Timer - t > 2 And place <> -1 Then ' col selected
  68.                     r = GetOpenRow(place)
  69.                     If r <> NumRows Then
  70.                         y = SQ + SQ / 2
  71.                         target = r * SQ + YO + SQ / 2
  72.                         delaid = 6
  73.                         While y < target
  74.                             y = y + 1
  75.                             Cls
  76.                             ShowGrid
  77.                             pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 2
  78.                             sx = Rnd * 6 - 3
  79.                             _PutImage , Overlay&, _Display
  80.                             _Display
  81.                             _Limit delaid
  82.                             delaid = delaid * 2
  83.                         Wend
  84.                         Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  85.                         place = -1 ' reset back to hold area
  86.                     Else
  87.                         Beep
  88.                     End If
  89.                 End If
  90.             End If
  91.         End If
  92.     Else
  93.         AIMove
  94.         Turn = P: MoveNum = MoveNum + 1: t = Timer
  95.     End If
  96.     ShowGrid
  97.     If Turn = P Then
  98.         If place = -1 Then
  99.             s$ = "Holding area, press spacebar until over column to play."
  100.         Else
  101.             s$ = "Press Spacebar, if don't want to play" + Str$(place) + " column."
  102.         End If
  103.         Color &HFFFFFFFF
  104.         _PrintString (XO, YO - SQ - 16), s$
  105.     End If
  106.     pumpkin 0, place * SQ + XO + SQ / 2, SQ + SQ / 2, pr, 2
  107.     sx = Rnd * 6 - 3
  108.     _PutImage , Overlay&, _Display
  109.     _Display
  110.     _Limit 15
  111.  
  112. Sub AIMove
  113.     ' What this sub does in English:
  114.     ' This sub assigns the value to playing each column, then plays the best value with following caveats:
  115.     ' + If it finds a winning move, it will play that immediately.
  116.     ' + If it finds a spoiler move, it will play that if no winning move was found.
  117.     ' + It will poisen the column's scoring, if opponent can play a winning move if AI plays this column,
  118.     '   but it might be the only legal move left.  We will have to play it if no better score was found.
  119.  
  120.     Dim c, r, d, cntA, cntP, bestScore, startR, startC, iStep, test, goodF, i
  121.     Dim openRow(NCM1) ' find open rows once
  122.     ReDim Scores(NCM1) ' evaluate each column's potential
  123.     AIX = -1: AIY = -1 ' set these when AI makes move, they are signal to display procedure AI's move.
  124.     For c = 0 To NCM1
  125.         openRow(c) = GetOpenRow(c)
  126.         r = openRow(c)
  127.         If r <> NumRows Then
  128.             For d = 0 To 3 ' 4 directions to build connect 4's that use cell c, r
  129.                 startC = c + -3 * DX(d): startR = r + -3 * DY(d)
  130.                 For i = 0 To 3 ' here we backup from the potential connect 4 in opposite build direction of c, r
  131.                     cntA = 0: cntP = 0: goodF = -1 ' reset counts and flag for good connect 4
  132.                     'from this start position run 4 steps forward to count all connects involving cell c, r
  133.                     For iStep = 0 To 3 ' process a potential connect 4
  134.                         test = GR(startC + i * DX(d) + iStep * DX(d), startR + i * DY(d) + iStep * DY(d))
  135.                         If test = NumRows Then goodF = 0: Exit For 'cant get connect4 from here
  136.                         If test = AI Then cntA = cntA + 1
  137.                         If test = P Then cntP = cntP + 1
  138.                     Next iStep
  139.                     If goodF Then 'evaluate the Legal Connect4 we could build with c, r
  140.                         If cntA = 3 Then ' we are done!  winner!
  141.                             AIX = c: AIY = r ' <<< this is the needed 4th cell to win tell ShowGrid last cell
  142.                             Grid(c, r) = AI '  <<< this is the needed 4th cell to win, add to grid this is AI move
  143.                             Scores(c) = 1000
  144.                             Exit Sub
  145.                         ElseIf cntP = 3 Then 'next best move spoiler!
  146.                             AIX = c: AIY = r 'set the move but don't exit there might be a winner
  147.                             Scores(c) = 900
  148.                         ElseIf cntA = 0 And cntP = 2 Then
  149.                             Scores(c) = Scores(c) + 8
  150.                         ElseIf cntA = 2 And cntP = 0 Then ' very good offense or defense
  151.                             Scores(c) = Scores(c) + 4 'play this to connect 3 or prevent player from Connect 3
  152.                         ElseIf cntA = 0 And cntP = 1 Then
  153.                             Scores(c) = Scores(c) + 4
  154.                         ElseIf (cntA = 1 And cntP = 0) Then 'good offense or defense
  155.                             Scores(c) = Scores(c) + 2 ' play this to connect 2 or prevent player from Connect 2
  156.                         ElseIf (cntA = 0 And cntP = 0) Then ' OK it's not a wasted move as it has potential for connect4
  157.                             Scores(c) = Scores(c) + 1 ' this is good move because this can still be a Connect 4
  158.                         End If
  159.                     End If ' in the board
  160.                 Next i
  161.             Next d
  162.             If Stupid(c, r) Then Scores(c) = -1000 + Scores(c) ' poison because if played the human can win
  163.         End If
  164.     Next
  165.     If AIX <> -1 Then ' we found a spoiler so move there since we haven't found a winner
  166.         Grid(AIX, AIY) = AI ' make move on grid and done!
  167.         Exit Sub
  168.     Else
  169.         If GetOpenRow(PlayerLastMoveCol) < NumRows Then 'all things being equal play on top of player's last move
  170.             bestScore = Scores(PlayerLastMoveCol): AIY = PlayerLastMoveRow - 1: AIX = PlayerLastMoveCol
  171.         Else
  172.             bestScore = -1000 ' a negative score indicates that the player can beat AI with their next move
  173.         End If
  174.         For c = 0 To NCM1
  175.             r = openRow(c)
  176.             If r <> NumRows Then
  177.                 If Scores(c) > bestScore Then bestScore = Scores(c): AIY = r: AIX = c
  178.             End If
  179.         Next
  180.         If AIX <> -1 Then
  181.             Grid(AIX, AIY) = AI ' make first best score move we found
  182.         Else 'We have trouble!  Oh but it could be there are no moves!!!
  183.             ' checkWin is run after every move by AI or Player if there were no legal moves left it should have caught that.
  184.             ' Just in case it didn't here is an error stop!
  185.             Color &HFFFFFFFF
  186.             Beep: Locate 4, 2: Print "AI has failed to find a proper move, press any to end..."
  187.             Sleep ' <<< pause until user presses a key
  188.             End
  189.         End If
  190.     End If
  191.  
  192. Function GetOpenRow (forCol)
  193.     Dim i
  194.     GetOpenRow = NumRows 'assume none open
  195.     If forCol < 0 Or forCol > NCM1 Then Exit Function
  196.     For i = NRM1 To 0 Step -1
  197.         If Grid(forCol, i) = 0 Then GetOpenRow = i: Exit Function
  198.     Next
  199.  
  200. Function Stupid (c, r)
  201.     Dim ppr
  202.     Grid(c, r) = AI
  203.     ppr = GetOpenRow(c)
  204.     If ppr <> NumRows Then
  205.         Grid(c, ppr) = P
  206.         If CheckWin = 4 Then Stupid = -1
  207.         Grid(c, ppr) = 0
  208.     End If
  209.     Grid(c, r) = 0
  210.  
  211. Function GR (c, r) ' if c, r are out of bounds returns N else returns grid(c, r)
  212.     ' need to check the grid(c, r) but only if c, r is on the board
  213.     If c < 0 Or c > NCM1 Or r < 0 Or r > NRM1 Then GR = NumRows Else GR = Grid(c, r)
  214.  
  215. Sub ShowGrid
  216.     Static lastMoveNum
  217.     Dim i, r, c, check, s$, k$
  218.     If MoveNum <> lastMoveNum Then ' file newest move
  219.         If MoveNum = 1 Then ReDim Record$(NCM1, NRM1)
  220.         If Turn = -1 Then
  221.             Record$(PlayerLastMoveCol, PlayerLastMoveRow) = _Trim$(Str$(MoveNum)) + " " + "P"
  222.         Else
  223.             Record$(AIX, AIY) = _Trim$(Str$(MoveNum)) + " " + "A"
  224.         End If
  225.         lastMoveNum = MoveNum
  226.     End If
  227.     Color _RGB32(255, 255, 255), _RGB32(64, 64, 255): Cls
  228.     'Line (XO, YO)-Step(NumCols * SQ, NumRows * SQ), &HFF004400, BF
  229.     For i = 0 To NumCols 'grid
  230.         Line (SQ * i + XO, YO)-Step(0, NumRows * SQ), &HFFFFFFFF
  231.     Next
  232.     For i = 0 To NumRows
  233.         Line (XO, SQ * i + YO)-Step(NumCols * SQ, 0), &HFFFFFFFF
  234.     Next
  235.     Color
  236.     For r = NRM1 To 0 Step -1 ''in grid rows are reversed 0 is top row
  237.         For c = 0 To NCM1
  238.             If Grid(c, r) = P Then
  239.                 'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF000000, BF
  240.                 pumpkin 0, c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, pr, 2
  241.  
  242.             ElseIf Grid(c, r) = AI Then
  243.                 If c = AIX And r = AIY Then 'highlite last AI move
  244.                     'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF8888FF, BF  ' no overlay
  245.                     Line (c * SQ + XO, r * SQ + YO)-Step(SQ, SQ), &HFF8888FF, BF
  246.                     'Else
  247.                     'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF4444FF, BF  ' no overlay
  248.                     'Line (c * SQ + XO, r * SQ + YO)-Step(SQ, SQ), &HFF4444FF, BF
  249.                 End If
  250.                 drawSpinner c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, .4, _Pi(-c / 8), _RGB32(Rnd * 30 + 40, Rnd * 15 + 20, Rnd * 6 + 10)
  251.             End If
  252.             s$ = _Trim$(Str$(Scores(c)))
  253.             Color &HFFFFFFFF
  254.             _PrintString (XO + c * SQ + (60 - Len(s$) * 8) / 2, YO + SQ * NumRows + 22), s$
  255.         Next
  256.     Next
  257.     '_Display
  258.     check = CheckWin
  259.     If check Then 'report end of round ad see if want to play again
  260.         If check = 4 Or check = -4 Then
  261.             For i = 0 To 3
  262.                 Line ((WinX + i * DX(WinD)) * SQ + XO + 10, (WinY + i * DY(WinD)) * SQ + YO + 10)-Step(SQ - 20, SQ - 20), &HFFFFFF00, B
  263.             Next
  264.         End If
  265.         Color &HFFFFFFFF
  266.         For r = 0 To NRM1
  267.             For c = 0 To NCM1
  268.                 If Record$(c, r) <> "" Then
  269.                     s$ = Mid$(Record$(c, r), 1, InStr(Record$(c, r), " ") - 1)
  270.                     _PrintString (SQ * c + XO + (SQ - Len(s$) * 8) / 2, SQ * r + YO + 22), s$
  271.                 End If
  272.             Next
  273.         Next
  274.         If check = -4 Then
  275.             s$ = " AI is Winner!"
  276.         ElseIf check = 4 Then
  277.             s$ = " Human is Winner!"
  278.         ElseIf check = NumRows Then
  279.             s$ = " Board is full, no winner." ' keep Turn the same
  280.         End If
  281.         Locate 2, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  282.         s$ = " Play again? press spacebar, escape to quit... "
  283.         Locate 4, ((SW - Len(s$) * 8) / 2) / 8: Print s$
  284.         _PutImage , Overlay&, _Display
  285.         _Display
  286.         keywait:
  287.         While Len(k$) = 0
  288.             k$ = InKey$
  289.             _Limit 200
  290.         Wend
  291.         If k$ = " " Then
  292.             ReDim Grid(NCM1, NRM1), Scores(NCM1)
  293.             If GoFirst = P Then GoFirst = AI Else GoFirst = P
  294.             Turn = GoFirst: MoveNum = 0
  295.         ElseIf Asc(k$) = 27 Then
  296.             System
  297.         Else
  298.             k$ = "": GoTo keywait:
  299.         End If
  300.     End If
  301.  
  302. Function CheckWin ' return WinX, WinY, WinD along with +/- 4, returns NumRows if grid full, 0 if no win and grid not full
  303.     Dim gridFull, r, c, s, i
  304.     gridFull = NumRows
  305.     For r = NRM1 To 0 Step -1 'bottom to top
  306.         For c = 0 To NCM1
  307.             If Grid(c, r) Then ' check if c starts a row
  308.                 If c < NCM1 - 2 Then
  309.                     s = 0
  310.                     For i = 0 To 3 ' east
  311.                         s = s + Grid(c + i, r)
  312.                     Next
  313.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 0: CheckWin = s: Exit Function
  314.                 End If
  315.                 If r > 2 Then ' check if c starts a col
  316.                     s = 0
  317.                     For i = 0 To 3 ' north
  318.                         s = s + Grid(c, r - i)
  319.                     Next
  320.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 6: CheckWin = s: Exit Function
  321.                 End If
  322.                 If r > 2 And c < NCM1 - 2 Then 'check if c starts diagonal up to right
  323.                     s = 0
  324.                     For i = 0 To 3 ' north  east
  325.                         s = s + Grid(c + i, r - i)
  326.                     Next
  327.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 7: CheckWin = s: Exit Function
  328.                 End If
  329.                 If r > 2 And c > 2 Then 'check if c starts a diagonal up to left
  330.                     s = 0
  331.                     For i = 0 To 3 ' north west
  332.                         s = s + Grid(c - i, r - i)
  333.                     Next
  334.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 5: CheckWin = s: Exit Function
  335.                 End If
  336.             Else
  337.                 gridFull = 0 ' at least one enpty cell left
  338.             End If 'grid is something
  339.         Next
  340.     Next
  341.     CheckWin = gridFull
  342.  
  343.  
  344. Sub pumpkin (dh&, cx, cy, pr, limit)
  345.     Dim lastr, u, dx, i, tx1, tx2, tx3, ty1, ty2, ty3, ty22, sxs
  346.     'carve this!
  347.     Color &HFFFF0000
  348.     fEllipse cx, cy, pr, 29 / 35 * pr
  349.     Color &HFF000000
  350.     lastr = 2 / 7 * pr
  351.     Do
  352.         ellipse cx, cy, lastr, 29 / 35 * pr
  353.         lastr = .5 * (pr - lastr) + lastr + 1 / 35 * pr
  354.         If pr - lastr < 1 / 80 * pr Then Exit Do
  355.     Loop
  356.  
  357.     ' 'flickering candle light
  358.     'Color _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  359.  
  360.     ' eye sockets
  361.     ftri2 dh&, cx - 9 * pr / 12, cy - 2 * pr / 12, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  362.     ftri2 dh&, cx - 7 * pr / 12, cy - 6 * pr / 12, cx - 3 * pr / 12, cy - 0 * pr / 12, cx - 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  363.     ftri2 dh&, cx + 9 * pr / 12, cy - 2 * pr / 12, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  364.     ftri2 dh&, cx + 7 * pr / 12, cy - 6 * pr / 12, cx + 3 * pr / 12, cy - 0 * pr / 12, cx + 2 * pr / 12, cy - 3 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  365.  
  366.     ' nose
  367.     ftri2 dh&, cx, cy - rand%(2, 5) * pr / 12, cx - 2 * pr / 12, cy + 2 * pr / 12, cx + rand%(1, 2) * pr / 12, cy + 2 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  368.  
  369.     ' evil grin
  370.     ftri2 dh&, cx - 9 * pr / 12, cy + 1 * pr / 12, cx - 7 * pr / 12, cy + 7 * pr / 12, cx - 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  371.     ftri2 dh&, cx + 9 * pr / 12, cy + 1 * pr / 12, cx + 7 * pr / 12, cy + 7 * pr / 12, cx + 6 * pr / 12, cy + 5 * pr / 12, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  372.  
  373.     ' moving teeth/talk/grrrr..
  374.     u = rand%(4, 8)
  375.     dx = pr / u
  376.     For i = 1 To u
  377.         tx1 = cx - 6 * pr / 12 + (i - 1) * dx
  378.         tx2 = tx1 + .5 * dx
  379.         tx3 = tx1 + dx
  380.         ty1 = cy + 5 * pr / 12
  381.         ty3 = cy + 5 * pr / 12
  382.         ty2 = cy + (4 - Rnd) * pr / 12
  383.         ty22 = cy + (6 + Rnd) * pr / 12
  384.         ftri2 dh&, tx1, ty1, tx2, ty2, tx3, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  385.         ftri2 dh&, tx1 + .5 * dx, ty1, tx2 + .5 * dx, ty22, tx3 + .5 * dx, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  386.     Next
  387.     If limit Then
  388.         'shifty eyes
  389.         If limit = 3 Then sxs = sx Else sxs = .1 * limit * sx
  390.         pumpkin dh&, sxs + cx - 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  391.         pumpkin dh&, sxs + cx + 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  392.     End If
  393.  
  394. Sub fEllipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  395.     Dim scale As Single, x As Long, y As Long
  396.     scale = yRadius / xRadius
  397.     Line (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  398.     For x = 1 To xRadius
  399.         y = scale * Sqr(xRadius * xRadius - x * x)
  400.         Line (CX + x, CY - y)-(CX + x, CY + y), , BF
  401.         Line (CX - x, CY - y)-(CX - x, CY + y), , BF
  402.     Next
  403.  
  404. Sub ellipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  405.     Dim scale As Single, xs As Long, x As Long, y As Long
  406.     Dim lastx As Long, lasty As Long
  407.     scale = yRadius / xRadius: xs = xRadius * xRadius
  408.     PSet (CX, CY - yRadius): PSet (CX, CY + yRadius)
  409.     lastx = 0: lasty = yRadius
  410.     For x = 1 To xRadius
  411.         y = scale * Sqr(xs - x * x)
  412.         Line (CX + lastx, CY - lasty)-(CX + x, CY - y)
  413.         Line (CX + lastx, CY + lasty)-(CX + x, CY + y)
  414.         Line (CX - lastx, CY - lasty)-(CX - x, CY - y)
  415.         Line (CX - lastx, CY + lasty)-(CX - x, CY + y)
  416.         lastx = x: lasty = y
  417.     Next
  418.  
  419. Sub ftri2 (returnDest&, x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  420.     Dim a&
  421.     a& = _NewImage(1, 1, 32)
  422.     _Dest a&
  423.     PSet (0, 0), K
  424.     _Dest returnDest&
  425.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  426.     _FreeImage a& '<<< this is important!
  427.  
  428. Function rand% (lo%, hi%)
  429.     rand% = Int(Rnd * (hi% - lo% + 1)) + lo%
  430.  
  431.  
  432.  
  433. Sub drawLink (x1, y1, r1, x2, y2, r2, c As _Unsigned Long)
  434.     Dim a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  435.     a = _Atan2(y2 - y1, x2 - x1)
  436.     a1 = a + _Pi(1 / 2)
  437.     a2 = a - _Pi(1 / 2)
  438.     x3 = x1 + r1 * Cos(a1): y3 = y1 + r1 * Sin(a1)
  439.     x4 = x1 + r1 * Cos(a2): y4 = y1 + r1 * Sin(a2)
  440.     x5 = x2 + r2 * Cos(a1): y5 = y2 + r2 * Sin(a1)
  441.     x6 = x2 + r2 * Cos(a2): y6 = y2 + r2 * Sin(a2)
  442.     fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  443.     Fcirc x1, y1, r1, c
  444.     Fcirc x2, y2, r2, c
  445.  
  446. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  447. Sub fquad (x1 As Integer, y1 As Integer, x2 As Integer, y2 As Integer, x3 As Integer, y3 As Integer, x4 As Integer, y4 As Integer, c As _Unsigned Long)
  448.     ftri x1, y1, x2, y2, x4, y4, c
  449.     ftri x3, y3, x4, y4, x1, y1, c
  450.  
  451. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  452.     Dim a&
  453.     a& = _NewImage(1, 1, 32)
  454.     _Dest a&
  455.     PSet (0, 0), K
  456.     _Dest 0
  457.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  458.     _FreeImage a& '<<< this is important!
  459.  
  460. Sub TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c As _Unsigned Long)
  461.     Dim max As Integer, mx2 As Integer, i As Integer, j As Integer, k As Single, lasti As Single, lastj As Single
  462.     Dim prc As _Unsigned Long, tef As Long
  463.     prc = _RGB32(255, 255, 255, 255)
  464.     If a > b Then max = a + 1 Else max = b + 1
  465.     mx2 = max + max
  466.     tef = _NewImage(mx2, mx2)
  467.     _Dest tef
  468.     _Source tef 'point wont read without this!
  469.     For k = 0 To 6.2832 + .05 Step .1
  470.         i = max + a * Cos(k) * Cos(ang) + b * Sin(k) * Sin(ang)
  471.         j = max + a * Cos(k) * Sin(ang) - b * Sin(k) * Cos(ang)
  472.         If k <> 0 Then
  473.             Line (lasti, lastj)-(i, j), prc
  474.         Else
  475.             PSet (i, j), prc
  476.         End If
  477.         lasti = i: lastj = j
  478.     Next
  479.     Dim xleft(mx2) As Integer, xright(mx2) As Integer, x As Integer, y As Integer
  480.     For y = 0 To mx2
  481.         x = 0
  482.         While Point(x, y) <> prc And x < mx2
  483.             x = x + 1
  484.         Wend
  485.         xleft(y) = x
  486.         While Point(x, y) = prc And x < mx2
  487.             x = x + 1
  488.         Wend
  489.         While Point(x, y) <> prc And x < mx2
  490.             x = x + 1
  491.         Wend
  492.         If x = mx2 Then xright(y) = xleft(y) Else xright(y) = x
  493.     Next
  494.     _Dest destHandle&
  495.     For y = 0 To mx2
  496.         If xleft(y) <> mx2 Then Line (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  497.     Next
  498.     _FreeImage tef
  499.  
  500. Sub Fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
  501.     Dim Radius As Long, RadiusError As Long
  502.     Dim X As Long, Y As Long
  503.     Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
  504.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  505.     Line (CX - X, CY)-(CX + X, CY), C, BF
  506.     While X > Y
  507.         RadiusError = RadiusError + Y * 2 + 1
  508.         If RadiusError >= 0 Then
  509.             If X <> Y + 1 Then
  510.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  511.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  512.             End If
  513.             X = X - 1
  514.             RadiusError = RadiusError - X * 2
  515.         End If
  516.         Y = Y + 1
  517.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  518.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  519.     Wend
  520.  
  521. Sub drawSpinner (x As Integer, y As Integer, scale As Single, heading As Single, c As _Unsigned Long)
  522.     Dim x1, x2, x3, x4, y1, y2, y3, y4, r, a, a1, a2, lg, d, rd
  523.     Dim rred, bblue, ggreen
  524.     Static switch As Integer
  525.     switch = switch + 2
  526.     switch = switch Mod 16 + 1
  527.     rred = _Red32(c): ggreen = _Green32(c): bblue = _Blue32(c)
  528.     r = 10 * scale
  529.     x1 = x + r * Cos(heading): y1 = y + r * Sin(heading)
  530.     r = 2 * r 'lg lengths
  531.     For lg = 1 To 8
  532.         If lg < 5 Then
  533.             a = heading + .9 * lg * _Pi(1 / 5) + (lg = switch) * _Pi(1 / 10)
  534.         Else
  535.             a = heading - .9 * (lg - 4) * _Pi(1 / 5) - (lg = switch) * _Pi(1 / 10)
  536.         End If
  537.         x2 = x1 + r * Cos(a): y2 = y1 + r * Sin(a)
  538.         drawLink x1, y1, 3 * scale, x2, y2, 2 * scale, _RGB32(rred + 20, ggreen + 10, bblue + 5)
  539.         If lg = 1 Or lg = 2 Or lg = 7 Or lg = 8 Then d = -1 Else d = 1
  540.         a1 = a + d * _Pi(1 / 12)
  541.         x3 = x2 + r * 1.5 * Cos(a1): y3 = y2 + r * 1.5 * Sin(a1)
  542.         drawLink x2, y2, 2 * scale, x3, y3, scale, _RGB32(rred + 35, ggreen + 17, bblue + 8)
  543.         rd = Int(Rnd * 8) + 1
  544.         a2 = a1 + d * _Pi(1 / 8) * rd / 8
  545.         x4 = x3 + r * 1.5 * Cos(a2): y4 = y3 + r * 1.5 * Sin(a2)
  546.         drawLink x3, y3, scale, x4, y4, scale, _RGB32(rred + 50, ggreen + 25, bblue + 12)
  547.     Next
  548.     r = r * .5
  549.     Fcirc x1, y1, r, _RGB32(rred - 20, ggreen - 10, bblue - 5)
  550.     x2 = x1 + (r + 1) * Cos(heading - _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading - _Pi(1 / 12))
  551.     Fcirc x2, y2, r * .2, &HFF000000
  552.     x2 = x1 + (r + 1) * Cos(heading + _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading + _Pi(1 / 12))
  553.     Fcirc x2, y2, r * .2, &HFF000000
  554.     r = r * 2
  555.     x1 = x + r * .9 * Cos(heading + _Pi): y1 = y + r * .9 * Sin(heading + _Pi)
  556.     TiltedEllipseFill 0, x1, y1, r, .7 * r, heading + _Pi, _RGB32(rred, ggreen, bblue)
  557.  
  558. Sub Create_Board
  559.     Dim As Integer x, y
  560.     _Dest Overlay&
  561.     Line (60, 120)-Step(480, 480), _RGB32(80, 40, 20), BF
  562.     For y = 0 To 7
  563.         For x = 0 To 7
  564.             Fcirc 90 + 60 * x, 150 + 60 * y, 28, _RGB32(0)
  565.     Next x, y
  566.     _ClearColor _RGB32(0), Overlay&
  567.  
  568.  
  569.  

Zip contains Windows exe for Syntax Bomb friends and Source code for compiling in other OS.
Making this #2 for Overlay mod, thanks!

 
One Key Connect 4 Halloween Style.PNG


* 1 key Connect 4 Halloween #2.zip (Filesize: 842.96 KB, Downloads: 104)
« Last Edit: October 22, 2021, 01:57:44 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: One Key Connect 4 (8x8) Halloween Style
« Reply #14 on: October 22, 2021, 01:11:00 pm »
Quote
@bplus You might want to consider a space bar toggle for AI or two-player version. Wow, I was just thinking that it's been 20 years since I did networking routines for home networks. I mean it certainly could be used by two people on one computer, but over home network would be cool.

Over Internet might be cool, at home, I just have AI to play.

PS I have real Wheel of Fortune Game I made last year but did not work too well with family members, no AI for that one!