QB64.org Forum

Active Forums => Programs => Topic started by: bplus on October 19, 2021, 08:09:18 pm

Title: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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)
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt 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.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: jack on October 19, 2021, 08:19:04 pm
hi bplus
the game play would be better if you could also select the row
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete 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: 🎃🎃🎃🎃🎃 
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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:
 


For friends at Syntax Bomb the Windows compiled version and source:
(Updated just before midnight, only one download before update)
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete 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
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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.  


Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete 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!
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt 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.  
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete 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
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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!

 


Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus 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!
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 01:16:26 pm
Oh I just had interesting idea, since the board is now see through, you should be able to see your opponent!
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Dav on October 22, 2021, 01:17:36 pm
Good halloween game!  Plays strong too.  Still trying to beat it...

- Dav
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 02:25:00 pm
Rats that overlay screwed up the timing for the drop, sorry Pete I just noticed.

PS well it was slowing down the more pieces you put on the board anyway.

Back to the drawing board. ;(
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 22, 2021, 02:54:46 pm
Ironic. Hardware acceleration creates pumpkin deceleration. Maybe Steve can help. Oh wait, he only raises pumpkins, he doesn't drop them.

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 03:12:28 pm
Naw, no wonder here. I was re-drawing all the pieces live, to keep them moving. That's pretty intense processing time. Should be able to fix with static pieces with solid backgrounds as pieces would appear in real game, if I want to fool around with this.

I do have an image of the opponent the human sees (and sees through overlay) that I'd love to use with this!
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 22, 2021, 03:31:55 pm
Yeah, but what ya doesn't haz is my permyission ta use it!

 - Sam :D
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt on October 22, 2021, 08:06:48 pm
Naw, no wonder here. I was re-drawing all the pieces live, to keep them moving. That's pretty intense processing time. Should be able to fix with static pieces with solid backgrounds as pieces would appear in real game, if I want to fool around with this.

I do have an image of the opponent the human sees (and sees through overlay) that I'd love to use with this!

Yeah, time to add layering

putimage opponent
putimage tiles
putimage overlay
show the tile and text on top of the screen
display to screen

the problem with that though is the animation on the tiles, what you could do though is pre-render the animations on still more layers and just use putimage to place them to the tile layer. I think the Fill routines are a bit slower than just putimage? Then you could use a timer to cycle the frames.

I just wish your variable naming convention was a bit more descriptive. ¯\_(ツ)_/¯

Although this is one reason I don't use _DISPLAY in that manner. if the program window hits the edge of the screen this happens.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 22, 2021, 08:18:31 pm
It looks like your CPU may be running a bit too hot @ melting effect. Wow, I never imagined a situation like that could happen, but then I don't get out of SCREEN 0, much.

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Dav on October 22, 2021, 08:31:08 pm
Getting a sticky spider image on the screen once in a while.  My pumpkin falls right through it when it happens.

Still haven't won yet.  :(

- Dav

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 22, 2021, 08:42:49 pm
You're probably playing it while on the web!

Mark put together a really good AI algorithm. I played about 8 times and only one once.

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 09:27:23 pm
I was hoping to get something like this going. It's nice to be able to see your opponent.
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 22, 2021, 09:37:31 pm
Doesn't Steve have a more recent photo? Anyway, I'd prefer Marvin.

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 09:56:46 pm
@Cobalt Did you insert resizable in code?

I tried dragging and banging title bar around and don't have a melting problem on my system. Other apps do stick and expand to fill side of screen but not my QB64.

@Dav I've never seen the spider stick like that in my games.

@Pete where we are playing Connect 4 there is hardly any gravity, so maybe it's OK if pieces float down.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Dav on October 22, 2021, 10:12:30 pm
@bplus:  when it happened, it was when a new game has started, and the leftover spider was from the previous game but didnt erase off the screen.  Only happened a couple times.

EDIT: Finally won one!  Now my wife can stop laughing at me.  I agree @Pete, the AI algo is really great (or I just really bad).  Good job @bplus.

- Dav
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 22, 2021, 11:05:46 pm
@Dav you had it figured out some time ago, my guess your memory getting like mine. This is old Connect 4 posted almost year ago but now we see our opponent!

 


Just can't see it's pieces as well ;-))
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 23, 2021, 01:17:00 am
Ah, you did find a more recent picture of Steve. Thanks!

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt on October 23, 2021, 12:33:40 pm
@Cobalt Did you insert resizable in code?

@bplus nope just the code straight from the zip, course the one where I added the  overlay.

not just the sides of the screen, but anything showing up on top of the game window too.

Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 23, 2021, 12:45:31 pm
Hi Cobalt, is that Windows or Linux? If Windows what version? Those icons look different (top right corner).

I image that would mess up with any QB64 window.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 23, 2021, 12:54:39 pm
Here is version #3, here you can play any opponent you want by using a 600 X 680 pixel (or same ratio width X height for least distortion when stretching over screen)  .png file and naming it "Opponent.png". I have 3 sample scary faces in zip, just add digit to current Opponent and remove digit from 1 of the others to try 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 = 3 * 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. Dim Shared BF& 'opponent's face
  33. Screen _NewImage(SW, SH, 32)
  34. _Delay .25
  35. _ScreenMove 360, 60
  36. Overlay& = _NewImage(SW, SH, 32)
  37. BF& = _LoadImage("Opponent.png")
  38. Create_Board
  39. _Title "One Key Connect 4 (8x8) Halloween Style #3"
  40. d = 1
  41. While _KeyDown(32) = 0
  42.     Cls
  43.     pumpkin 0, _Width / 2, _Height / 2, _Height / 2.3, 3
  44.     sx = sx + d
  45.     If sx > 10 Then d = -d: sx = 10
  46.     If sx < -10 Then d = -d: sx = -10
  47.     Color &HFFFFFFFF
  48.     Locate 40, 33: Print "Spacebar Only"
  49.     _Display
  50.     _Limit 20
  51. GameOn = -1: GoFirst = AI: Turn = AI: MoveNum = 0
  52. ShowGrid
  53. place = -1
  54. t = Timer
  55. pr = (SQ - 2) / 2
  56. While GameOn
  57.     Cls
  58.     If Turn = P Then
  59.         k$ = InKey$
  60.         If k$ = Chr$(27) Then System ' emergency exit
  61.         If k$ = " " Then
  62.             t = Timer: place = place + 1
  63.             If place >= NumCols Then place = -1
  64.         Else ' watch out for midnight!
  65.             If Timer - t < 0 Then 'midnight problem
  66.                 t = Timer ' wait a little longer
  67.             Else
  68.                 If Timer - t > 2 And place <> -1 Then ' col selected
  69.                     r = GetOpenRow(place)
  70.                     If r <> NumRows Then
  71.                         y = 2 * SQ + SQ / 2
  72.                         target = r * SQ + YO + SQ / 2
  73.                         delaid = 6
  74.                         While y < target
  75.                             y = y + 1
  76.                             Cls
  77.                             ShowGrid
  78.                             pumpkin 0, place * SQ + XO + SQ / 2, y, pr, 2
  79.                             sx = Rnd * 6 - 3
  80.                             _PutImage , Overlay&, _Display
  81.                             _Display
  82.                             _Limit delaid
  83.                             delaid = delaid * 2
  84.                         Wend
  85.                         Grid(place, r) = P: Turn = AI: PlayerLastMoveCol = place: PlayerLastMoveRow = r: MoveNum = MoveNum + 1
  86.                         place = -1 ' reset back to hold area
  87.                     Else
  88.                         Beep
  89.                     End If
  90.                 End If
  91.             End If
  92.         End If
  93.     Else
  94.         AIMove
  95.         Turn = P: MoveNum = MoveNum + 1: t = Timer
  96.     End If
  97.     ShowGrid
  98.     If Turn = P Then
  99.         If place = -1 Then
  100.             s$ = "Holding area, press spacebar until over column to play."
  101.         Else
  102.             s$ = "Press Spacebar, if don't want to play" + Str$(place) + " column."
  103.         End If
  104.         dp XO + 1, YO - SQ - 16 + 1, s$
  105.     End If
  106.     pumpkin 0, place * SQ + XO + SQ / 2, 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.             Beep
  186.             dp 2 * 8, 4 * 16, "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(0): Cls
  228.     _PutImage , BF&, 0, (10, 10)-(_Width(BF&) - 20, _Height(BF&) - 50)
  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.     Color
  237.     For r = NRM1 To 0 Step -1 ''in grid rows are reversed 0 is top row
  238.         For c = 0 To NCM1
  239.             If Grid(c, r) = P Then
  240.                 'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF000000, BF
  241.                 pumpkin 0, c * SQ + XO + SQ / 2, r * SQ + YO + SQ / 2, pr, 2
  242.  
  243.             ElseIf Grid(c, r) = AI Then
  244.                 If c = AIX And r = AIY Then 'highlite last AI move
  245.                     'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF8888FF, BF  ' no overlay
  246.                     Line (c * SQ + XO, r * SQ + YO)-Step(SQ, SQ), &HFF8888FF, BF
  247.                 Else
  248.                     'Line (c * SQ + XO + 3, r * SQ + YO + 3)-Step(SQ - 6, SQ - 6), &HFF4444FF, BF  ' no overlay
  249.                     Line (c * SQ + XO, r * SQ + YO)-Step(SQ, SQ), &HFF4444FF, BF
  250.                 End If
  251.                 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)
  252.             End If
  253.             s$ = _Trim$(Str$(Scores(c)))
  254.             dp 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.         For r = 0 To NRM1
  266.             For c = 0 To NCM1
  267.                 If Record$(c, r) <> "" Then
  268.                     s$ = Mid$(Record$(c, r), 1, InStr(Record$(c, r), " ") - 1)
  269.                     dp SQ * c + XO + (SQ - Len(s$) * 8) / 2, SQ * r + YO + 22, s$
  270.                 End If
  271.             Next
  272.         Next
  273.         If check = -4 Then
  274.             s$ = " AI is Winner!"
  275.         ElseIf check = 4 Then
  276.             s$ = " Human is Winner!"
  277.         ElseIf check = NumRows Then
  278.             s$ = " Board is full, no winner." ' keep Turn the same
  279.         End If
  280.         dp (SW - Len(s$) * 8) / 2, 2 * 16, s$
  281.         s$ = " Play again? press spacebar, escape to quit... "
  282.         dp (SW - Len(s$) * 8) / 2, 4 * 16, s$
  283.         _PutImage , Overlay&, _Display
  284.         _Display
  285.         keywait:
  286.         While Len(k$) = 0
  287.             k$ = InKey$
  288.             _Limit 200
  289.         Wend
  290.         If k$ = " " Then
  291.             ReDim Grid(NCM1, NRM1), Scores(NCM1)
  292.             If GoFirst = P Then GoFirst = AI Else GoFirst = P
  293.             Turn = GoFirst: MoveNum = 0
  294.         ElseIf Asc(k$) = 27 Then
  295.             System
  296.         Else
  297.             k$ = "": GoTo keywait:
  298.         End If
  299.     End If
  300.  
  301. Function CheckWin ' return WinX, WinY, WinD along with +/- 4, returns NumRows if grid full, 0 if no win and grid not full
  302.     Dim gridFull, r, c, s, i
  303.     gridFull = NumRows
  304.     For r = NRM1 To 0 Step -1 'bottom to top
  305.         For c = 0 To NCM1
  306.             If Grid(c, r) Then ' check if c starts a row
  307.                 If c < NCM1 - 2 Then
  308.                     s = 0
  309.                     For i = 0 To 3 ' east
  310.                         s = s + Grid(c + i, r)
  311.                     Next
  312.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 0: CheckWin = s: Exit Function
  313.                 End If
  314.                 If r > 2 Then ' check if c starts a col
  315.                     s = 0
  316.                     For i = 0 To 3 ' north
  317.                         s = s + Grid(c, r - i)
  318.                     Next
  319.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 6: CheckWin = s: Exit Function
  320.                 End If
  321.                 If r > 2 And c < NCM1 - 2 Then 'check if c starts diagonal up to right
  322.                     s = 0
  323.                     For i = 0 To 3 ' north  east
  324.                         s = s + Grid(c + i, r - i)
  325.                     Next
  326.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 7: CheckWin = s: Exit Function
  327.                 End If
  328.                 If r > 2 And c > 2 Then 'check if c starts a diagonal up to left
  329.                     s = 0
  330.                     For i = 0 To 3 ' north west
  331.                         s = s + Grid(c - i, r - i)
  332.                     Next
  333.                     If s = 4 Or s = -4 Then WinX = c: WinY = r: WinD = 5: CheckWin = s: Exit Function
  334.                 End If
  335.             Else
  336.                 gridFull = 0 ' at least one enpty cell left
  337.             End If 'grid is something
  338.         Next
  339.     Next
  340.     CheckWin = gridFull
  341.  
  342.  
  343. Sub pumpkin (dh&, cx, cy, pr, limit)
  344.     Dim lastr, u, dx, i, tx1, tx2, tx3, ty1, ty2, ty3, ty22, sxs
  345.     'carve this!
  346.     Color &HFFFF0000
  347.     fEllipse cx, cy, pr, 29 / 35 * pr
  348.     Color &HFF000000
  349.     lastr = 2 / 7 * pr
  350.     Do
  351.         ellipse cx, cy, lastr, 29 / 35 * pr
  352.         lastr = .5 * (pr - lastr) + lastr + 1 / 35 * pr
  353.         If pr - lastr < 1 / 80 * pr Then Exit Do
  354.     Loop
  355.  
  356.     ' 'flickering candle light
  357.     'Color _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  358.  
  359.     ' eye sockets
  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.     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)
  363.     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)
  364.  
  365.     ' nose
  366.     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)
  367.  
  368.     ' evil grin
  369.     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)
  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.  
  372.     ' moving teeth/talk/grrrr..
  373.     u = rand%(4, 8)
  374.     dx = pr / u
  375.     For i = 1 To u
  376.         tx1 = cx - 6 * pr / 12 + (i - 1) * dx
  377.         tx2 = tx1 + .5 * dx
  378.         tx3 = tx1 + dx
  379.         ty1 = cy + 5 * pr / 12
  380.         ty3 = cy + 5 * pr / 12
  381.         ty2 = cy + (4 - Rnd) * pr / 12
  382.         ty22 = cy + (6 + Rnd) * pr / 12
  383.         ftri2 dh&, tx1, ty1, tx2, ty2, tx3, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  384.         ftri2 dh&, tx1 + .5 * dx, ty1, tx2 + .5 * dx, ty22, tx3 + .5 * dx, ty3, _RGB(Rnd * 55 + 200, Rnd * 55 + 200, 120)
  385.     Next
  386.     If limit Then
  387.         'shifty eyes
  388.         If limit = 3 Then sxs = sx Else sxs = .1 * limit * sx
  389.         pumpkin dh&, sxs + cx - 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  390.         pumpkin dh&, sxs + cx + 5 * pr / 12, cy - 2.5 * pr / 12, .15 * pr, Int(limit - 1)
  391.     End If
  392.  
  393. Sub fEllipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  394.     Dim scale As Single, x As Long, y As Long
  395.     scale = yRadius / xRadius
  396.     Line (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  397.     For x = 1 To xRadius
  398.         y = scale * Sqr(xRadius * xRadius - x * x)
  399.         Line (CX + x, CY - y)-(CX + x, CY + y), , BF
  400.         Line (CX - x, CY - y)-(CX - x, CY + y), , BF
  401.     Next
  402.  
  403. Sub ellipse (CX As Long, CY As Long, xRadius As Long, yRadius As Long)
  404.     Dim scale As Single, xs As Long, x As Long, y As Long
  405.     Dim lastx As Long, lasty As Long
  406.     scale = yRadius / xRadius: xs = xRadius * xRadius
  407.     PSet (CX, CY - yRadius): PSet (CX, CY + yRadius)
  408.     lastx = 0: lasty = yRadius
  409.     For x = 1 To xRadius
  410.         y = scale * Sqr(xs - x * x)
  411.         Line (CX + lastx, CY - lasty)-(CX + x, CY - y)
  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.         lastx = x: lasty = y
  416.     Next
  417.  
  418. Sub ftri2 (returnDest&, x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  419.     Dim a&
  420.     a& = _NewImage(1, 1, 32)
  421.     _Dest a&
  422.     PSet (0, 0), K
  423.     _Dest returnDest&
  424.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  425.     _FreeImage a& '<<< this is important!
  426.  
  427. Function rand% (lo%, hi%)
  428.     rand% = Int(Rnd * (hi% - lo% + 1)) + lo%
  429.  
  430.  
  431.  
  432. Sub drawLink (x1, y1, r1, x2, y2, r2, c As _Unsigned Long)
  433.     Dim a, a1, a2, x3, x4, x5, x6, y3, y4, y5, y6
  434.     a = _Atan2(y2 - y1, x2 - x1)
  435.     a1 = a + _Pi(1 / 2)
  436.     a2 = a - _Pi(1 / 2)
  437.     x3 = x1 + r1 * Cos(a1): y3 = y1 + r1 * Sin(a1)
  438.     x4 = x1 + r1 * Cos(a2): y4 = y1 + r1 * Sin(a2)
  439.     x5 = x2 + r2 * Cos(a1): y5 = y2 + r2 * Sin(a1)
  440.     x6 = x2 + r2 * Cos(a2): y6 = y2 + r2 * Sin(a2)
  441.     fquad x3, y3, x4, y4, x5, y5, x6, y6, c
  442.     Fcirc x1, y1, r1, c
  443.     Fcirc x2, y2, r2, c
  444.  
  445. 'need 4 non linear points (not all on 1 line) list them clockwise so x2, y2 is opposite of x4, y4
  446. 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)
  447.     ftri x1, y1, x2, y2, x4, y4, c
  448.     ftri x3, y3, x4, y4, x1, y1, c
  449.  
  450. Sub ftri (x1, y1, x2, y2, x3, y3, K As _Unsigned Long)
  451.     Dim a&
  452.     a& = _NewImage(1, 1, 32)
  453.     _Dest a&
  454.     PSet (0, 0), K
  455.     _Dest 0
  456.     _MapTriangle _Seamless(0, 0)-(0, 0)-(0, 0), a& To(x1, y1)-(x2, y2)-(x3, y3)
  457.     _FreeImage a& '<<< this is important!
  458.  
  459. Sub TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c As _Unsigned Long)
  460.     Dim max As Integer, mx2 As Integer, i As Integer, j As Integer, k As Single, lasti As Single, lastj As Single
  461.     Dim prc As _Unsigned Long, tef As Long
  462.     prc = _RGB32(255, 255, 255, 255)
  463.     If a > b Then max = a + 1 Else max = b + 1
  464.     mx2 = max + max
  465.     tef = _NewImage(mx2, mx2)
  466.     _Dest tef
  467.     _Source tef 'point wont read without this!
  468.     For k = 0 To 6.2832 + .05 Step .1
  469.         i = max + a * Cos(k) * Cos(ang) + b * Sin(k) * Sin(ang)
  470.         j = max + a * Cos(k) * Sin(ang) - b * Sin(k) * Cos(ang)
  471.         If k <> 0 Then
  472.             Line (lasti, lastj)-(i, j), prc
  473.         Else
  474.             PSet (i, j), prc
  475.         End If
  476.         lasti = i: lastj = j
  477.     Next
  478.     Dim xleft(mx2) As Integer, xright(mx2) As Integer, x As Integer, y As Integer
  479.     For y = 0 To mx2
  480.         x = 0
  481.         While Point(x, y) <> prc And x < mx2
  482.             x = x + 1
  483.         Wend
  484.         xleft(y) = x
  485.         While Point(x, y) = prc And x < mx2
  486.             x = x + 1
  487.         Wend
  488.         While Point(x, y) <> prc And x < mx2
  489.             x = x + 1
  490.         Wend
  491.         If x = mx2 Then xright(y) = xleft(y) Else xright(y) = x
  492.     Next
  493.     _Dest destHandle&
  494.     For y = 0 To mx2
  495.         If xleft(y) <> mx2 Then Line (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  496.     Next
  497.     _FreeImage tef
  498.  
  499. Sub Fcirc (CX As Long, CY As Long, R As Long, C As _Unsigned Long)
  500.     Dim Radius As Long, RadiusError As Long
  501.     Dim X As Long, Y As Long
  502.     Radius = Abs(R): RadiusError = -Radius: X = Radius: Y = 0
  503.     If Radius = 0 Then PSet (CX, CY), C: Exit Sub
  504.     Line (CX - X, CY)-(CX + X, CY), C, BF
  505.     While X > Y
  506.         RadiusError = RadiusError + Y * 2 + 1
  507.         If RadiusError >= 0 Then
  508.             If X <> Y + 1 Then
  509.                 Line (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  510.                 Line (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  511.             End If
  512.             X = X - 1
  513.             RadiusError = RadiusError - X * 2
  514.         End If
  515.         Y = Y + 1
  516.         Line (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  517.         Line (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  518.     Wend
  519.  
  520. Sub drawSpinner (x As Integer, y As Integer, scale As Single, heading As Single, c As _Unsigned Long)
  521.     Dim x1, x2, x3, x4, y1, y2, y3, y4, r, a, a1, a2, lg, d, rd
  522.     Dim rred, bblue, ggreen
  523.     Static switch As Integer
  524.     switch = switch + 2
  525.     switch = switch Mod 16 + 1
  526.     rred = _Red32(c): ggreen = _Green32(c): bblue = _Blue32(c)
  527.     r = 10 * scale
  528.     x1 = x + r * Cos(heading): y1 = y + r * Sin(heading)
  529.     r = 2 * r 'lg lengths
  530.     For lg = 1 To 8
  531.         If lg < 5 Then
  532.             a = heading + .9 * lg * _Pi(1 / 5) + (lg = switch) * _Pi(1 / 10)
  533.         Else
  534.             a = heading - .9 * (lg - 4) * _Pi(1 / 5) - (lg = switch) * _Pi(1 / 10)
  535.         End If
  536.         x2 = x1 + r * Cos(a): y2 = y1 + r * Sin(a)
  537.         drawLink x1, y1, 3 * scale, x2, y2, 2 * scale, _RGB32(rred + 20, ggreen + 10, bblue + 5)
  538.         If lg = 1 Or lg = 2 Or lg = 7 Or lg = 8 Then d = -1 Else d = 1
  539.         a1 = a + d * _Pi(1 / 12)
  540.         x3 = x2 + r * 1.5 * Cos(a1): y3 = y2 + r * 1.5 * Sin(a1)
  541.         drawLink x2, y2, 2 * scale, x3, y3, scale, _RGB32(rred + 35, ggreen + 17, bblue + 8)
  542.         rd = Int(Rnd * 8) + 1
  543.         a2 = a1 + d * _Pi(1 / 8) * rd / 8
  544.         x4 = x3 + r * 1.5 * Cos(a2): y4 = y3 + r * 1.5 * Sin(a2)
  545.         drawLink x3, y3, scale, x4, y4, scale, _RGB32(rred + 50, ggreen + 25, bblue + 12)
  546.     Next
  547.     r = r * .5
  548.     Fcirc x1, y1, r, _RGB32(rred - 20, ggreen - 10, bblue - 5)
  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.     x2 = x1 + (r + 1) * Cos(heading + _Pi(1 / 12)): y2 = y1 + (r + 1) * Sin(heading + _Pi(1 / 12))
  552.     Fcirc x2, y2, r * .2, &HFF000000
  553.     r = r * 2
  554.     x1 = x + r * .9 * Cos(heading + _Pi): y1 = y + r * .9 * Sin(heading + _Pi)
  555.     TiltedEllipseFill 0, x1, y1, r, .7 * r, heading + _Pi, _RGB32(rred, ggreen, bblue)
  556.  
  557. Sub Create_Board
  558.     Dim As Integer x, y
  559.     _Dest Overlay&
  560.     Line (XO, YO)-Step(SQ * NumCols, SQ * NumRows), _RGB32(40, 20, 10), BF
  561.     For y = 0 To NRM1
  562.         For x = 0 To NCM1
  563.             Fcirc SQ * x + XO + SQ / 2, SQ * y + YO + SQ / 2, (SQ - 2) / 2, _RGB32(0)
  564.     Next x, y
  565.     _ClearColor _RGB32(0), Overlay&
  566.  
  567. Sub dp (x, y, s$) ' double print white over black to stand out over images
  568.     Color &HFF000000
  569.     _PrintString (x + 1, y + 1), s$
  570.     Color &HFFFFFFFF
  571.     _PrintString (x, y), s$
  572.  
  573.  

I have given spiders solid background so they may be seen wiggling better.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

That's probably my final version.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 23, 2021, 01:01:07 pm
@bplus and @Cobalt

I'm using Windows 10, and I don't get the distortion effect when dragging the game to the edges, as depicted in the video. BTW @Cobalt What type of screen recorder are you using to produce the vids?

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt on October 23, 2021, 01:17:29 pm
Hi Cobalt, is that Windows or Linux? If Windows what version? Those icons look different (top right corner).

I image that would mess up with any QB64 window.

Windows.
Typically only does that on programs using the _DISPLAY keyword. And on random occasion with the IDE.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Cobalt on October 23, 2021, 01:18:41 pm

I'm using Windows 10, and I don't get the distortion effect when dragging the game to the edges, as depicted in the video. BTW @Cobalt What type of screen recorder are you using to produce the vids?

Pete

@Pete its called Active Presenter.
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 23, 2021, 01:32:08 pm
@Cobalt. Thanks, I bookmarked the download site.

@bplus

I combined Halloween with Easter and can someone tell me what month they celebrate gay pride?

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Kidding aside, I did try it with a "straight" black background, and I really liked that rendition.
 
Pete

Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Dav on October 25, 2021, 09:59:15 am
@Dav you had it figured out some time ago, my guess your memory getting like mine. This is old Connect 4 posted almost year ago but now we see our opponent!

I remember playing it before, but couldn't remember a technique that worked, but I think I found it again.  I've found if I mirror the AI play, and divide the playing field, it's easier to out think it.  Like this image shows, it drops on one side, I drop one on the opposite side. I drew boxes around the pieces to show how I matched the pieces.  This way I can beat it pretty often.

Had fun playing this.

- Dav

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 25, 2021, 12:26:46 pm
@Dav you might be onto how to play a perfect game! Supposedly it's been proved that for 8x8 Connect 4 Boards the 2nd player always wins in perfect game.

DaiHard at Syntax Bomb pointed me to a link about proof
https://tromp.github.io/c4/c4.html

and code for 8x8 game, I think? :)
https://github.com/tromp/fhourstones88/commit/8378b3256e9dcb79d90b856820cbcc7cef31e66f
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: Pete on October 25, 2021, 01:38:12 pm
Nice work, Dav!

I noticed the A.I. would almost always stack on top. I figured this was a vulnerability that could be exploited, but I wasn't willing to investigate it further. I also "felt" there was a distinct advantage to going second.

So if we use your strategy, maybe Mark should code in a "Screw you, I quit!" message from the A.I.? Hey, he already uses a variable named "Stupid" to track our mistakes. :D

Pete
Title: Re: One Key Connect 4 (8x8) Halloween Style
Post by: bplus on October 25, 2021, 03:16:59 pm
Or the Board could suddenly be overrun by spiders!

The Stupid subroutine is to avoid making a stupid move ie putting a piece upon which the opponent may place his piece and win, sometimes stupid moves can't be avoided, that's when board should be overrun by spiders LOL!

I wish the human could use the Stupid sub too, hey maybe another mod! ;-))