December 09, 2019, 10:18:23 PM

Author Topic: Four in a row  (Read 330 times)

Offline TomToad

  • Sr. Member
  • ****
  • Posts: 451
Four in a row
« on: August 24, 2019, 09:22:01 PM »
Was digging through some old programs of mine and found this one.  It is a port from "More Basic Computer Games" converted to BlitzMax.  Game is similar to Connect 4.  Complete with computer AI.
Code: BlitzMax
  1. '**********************************************************
  2. '*
  3. '*    Four in a Row
  4. '*    by TomToad
  5. '*    Adapted from code by James L Murphy which appears in
  6. '*       More Basic Computer Games
  7. '*   https://www.atariarchives.org/morebasicgames/showpage.php?page=63
  8. '*
  9. '**********************************************************
  10. SuperStrict
  11.  
  12. Graphics 800,600
  13. While Not MouseHit(1)
  14.         If KeyHit(KEY_ESCAPE) Or AppTerminate() Then End
  15.         Cls
  16.         SetScale 3,3
  17.         DrawText "Four in a Row",10,10
  18.         SetScale 2,2
  19.         DrawText "Click mouse button to continue",10,100
  20.         Flip
  21. Wend
  22.  
  23. SetScale 1,1
  24. Local BoardImage:TImage = CreateImage(512,512)
  25. Cls
  26. SetColor 255,255,0
  27. DrawRect 0,0,512,512
  28. SetColor 0,0,0
  29. For Local x:Int = 0 To 7
  30.         For Local y:Int = 0 To 7
  31.                 DrawOval x*64+8,y*64+8,48,48
  32.         Next
  33. Next
  34. SetColor 255,255,255
  35. GrabImage BoardImage,0,0
  36.  
  37. Global Board:Int[8,8], l:Int[8], s:Int[4], f:Int[4], v:Int[16], n:Int[4]
  38. DefData 1,100,500,2^20,1,800,4000,2^20
  39. DefData 1,75,900,2^18,1,450,3000,2^18
  40.  
  41. For Local i:Int = 0 To 15
  42.         ReadData v[i]
  43. Next
  44.  
  45. For Local i:Int = 0 To 7
  46.         For Local j:Int = 0 To 7
  47.                 board[i,j] = 0
  48.         Next
  49.         l[i] = 0
  50. Next
  51.  
  52. Local State:Int, MX:Int, MY:Int
  53. Const STATE_PICKTURN:Int = 0
  54. Const STATE_PLAYERTURN:Int = 1
  55. Const STATE_COMPTURN:Int = 2
  56. Const STATE_PLAYERANIM:Int = 3
  57. Const STATE_CHECKPLAYER:Int = 4
  58. Const STATE_COMPANIM:Int = 5
  59. Const STATE_CHECKCOMP:Int = 6
  60. Const STATE_PLAYERWINS:Int = 7
  61. Const STATE_COMPWINS:Int = 8
  62. Const STATE_TIE:Int = 9
  63.  
  64. While State = STATE_PICKTURN
  65.         If KeyHit(KEY_ESCAPE) Or AppTerminate() Then End
  66.         Cls
  67.         SetScale 4,4
  68.         DrawText "Who goes first?",10,10
  69.         SetScale 1,1
  70.         DrawRect 10,100,400,60
  71.         DrawRect 10,170,400,60
  72.         SetColor 0,0,0
  73.         SetScale 3,3
  74.         DrawText "Me!!!!",15,105
  75.         DrawText "Computer",15,175
  76.         Flip
  77.         SetColor 255,255,255
  78.         If MouseHit(1)
  79.                 MX:Int = MouseX()
  80.                 MY:Int = MouseY()
  81.                
  82.                 If MX > 10 And MX < 410 And MY > 100 And MY < 160 Then State = STATE_PLAYERTURN
  83.                 If MX > 10 And MX < 410 And MY > 170 And MY < 230 Then State = STATE_COMPTURN
  84.         End If
  85. Wend
  86.  
  87. SetScale 1,1
  88.  
  89. Local Animate:Int = False, Column:Int, Drop:Int, Result:Int[]
  90. Local AnimX:Float, AnimY:Float, AnimStartTime:Int, AnimTime:Int,dy:Float,Delta:Float
  91. While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
  92.         MX = MouseX()
  93.         MY = MouseY()
  94.         Cls
  95.         If state = STATE_PLAYERANIM Or State = STATE_COMPANIM
  96.                 AnimTime = MilliSecs() - AnimStartTime
  97.                 If STate = STATE_PLAYERANIM
  98.                         SetColor 192,192,192
  99.                 Else
  100.                         SetColor 192,0,0
  101.                 End If
  102.                 delta = Float(AnimTime)/500
  103.                 dy:Float = delta*512.0
  104.                 DrawOval Animx,dy,60,60
  105.                 If State = STATE_PLAYERANIM
  106.                         SetColor 255,255,255
  107.                 Else
  108.                         SetColor 255,0,0
  109.                 End If
  110.                 DrawOval Animx+2,dy+2,56,56
  111.                 If dy >= AnimY
  112.                         If State = STATE_PLAYERANIM
  113.                                 State = STATE_CHECKPLAYER
  114.                         Else
  115.                                 State = STATE_CHECKCOMP
  116.                         End If
  117.                 End If
  118.         End If
  119.         SetColor 255,255,255
  120.         DrawImage BoardImage,144,64
  121.         For Local x:Int = 0 To 7
  122.                 For Local y:Int = 0 To 7
  123.                         Select Board[x,y]
  124.                                 Case 0
  125.                                         SetColor 0,0,0
  126.                                 Case 1
  127.                                         SetColor 255,255,255
  128.                                 Case 2
  129.                                         SetColor 255,0,0
  130.                         End Select
  131.                         If Board[x,y] > 0 Then DrawOval x*64+152,y*64+72,48,48
  132.                 Next
  133.         Next
  134.         SetColor 0,0,255
  135.         DrawRect 124,576,552,24
  136.         If State = STATE_PLAYERTURN
  137.                 SetColor 192,192,192
  138.                 DrawOval MX-30,MY-30,60,60
  139.                 SetColor 255,255,255
  140.                 DrawOval MX-28,MY-28,56,56
  141.         End If
  142.         If State = STATE_PLAYERWINS
  143.                 SetColor 255,255,255
  144.                 SetScale 2,2
  145.                 DrawText "Player Wins!!!!",10,10
  146.                 SetScale 1,1
  147.         End If
  148.         If State = STATE_COMPWINS
  149.                 SetColor 255,0,0
  150.                 SetScale 2,2
  151.                 DrawText "Computer Wins!!!!",10,10
  152.                 SetScale 1,1
  153.         End If
  154.         If State = STATE_TIE
  155.                 SetColor 0,255,0
  156.                 SetScale 2,2
  157.                 DrawText "Tie Game!!!!!!",10,10
  158.                 SetScale 1,1
  159.         End If
  160.         Flip
  161.        
  162.         Select State
  163.                 Case STATE_PLAYERTURN
  164.                         State = STATE_TIE
  165.                         For Local i:Int = 0 To 7
  166.                                 If l[i] < 7
  167.                                         State = STATE_PLAYERTURN
  168.                                         Exit
  169.                                 End If
  170.                         Next
  171.                         If State = STATE_TIE Then Continue
  172.                         If MouseHit(1)
  173.                                 Column = (MX - 144)/64
  174.                                 If Column < 0 Or Column > 7 Or MY > 64 Or Board[Column,0] <> 0 Then Continue
  175.                                 State = STATE_PLAYERANIM
  176.                                 AnimX = Column * 64 + 144
  177.                                 AnimY = (8-l[Column])*64
  178.                                 AnimStartTime = MilliSecs()
  179.                         End If
  180.                 Case STATE_CHECKPLAYER
  181.                         Drop:Int = 7 -l[Column]
  182.                         Board[Column,Drop] = 1
  183.                         l[Column] :+ 1
  184.                         'Check for four in a row
  185.                         Local Result:Int[] = CheckConnect(Column,Drop,State)
  186.                         State = STATE_COMPTURN
  187.                         For Local i:Int = 0 To 3
  188.                                 If Result[i] >= 4
  189.                                         State = STATE_PLAYERWINS
  190.                                         Exit
  191.                                 End If
  192.                         Next
  193.                 Case STATE_COMPTURN
  194.                         State = STATE_TIE
  195.                         For Local i:Int = 0 To 7
  196.                                 If l[i] < 7 Then State = STATE_COMPTURN
  197.                                 Exit
  198.                         Next
  199.                         If State = STATE_TIE Then Continue
  200.                         Local MaxValue:Int = 0, Move:Int = -1
  201.                         For Column = 0 To 7
  202.                                 Local CheckValue:Int = 0
  203.                                 Drop = 7 - l[Column]
  204.                                 If Drop > 7 Then Continue
  205.                                 Result = CheckConnect(Column,Drop,State)
  206.                                 Local Bonus:Int = 0
  207.                                 For Local Count:Int = 1 To 4
  208.                                         For Local i:Int = 0 To 3
  209.                                                 If Result[i] = Count
  210.                                                         CheckValue :+ V[(Count-1)+4*Bonus]
  211.                                                         Bonus = 1
  212.                                                 End If
  213.                                         Next
  214.                                 Next
  215.                                 Result = CheckConnect(Column,Drop,STATE_CHECKPLAYER)
  216.                                 Bonus:Int = 0
  217.                                 For Local Count:Int = 1 To 4
  218.                                         For Local i:Int = 0 To 3
  219.                                                 If Result[i] = Count
  220.                                                         CheckValue :+ V[(Count-1)+4*Bonus+8]
  221.                                                         Bonus = 1
  222.                                                 End If
  223.                                         Next
  224.                                 Next
  225.                                 If CheckValue > MaxValue
  226.                                         MaxValue = CheckValue
  227.                                         Move = Column
  228.                                 Else If CheckValue = MaxValue
  229.                                         If Rand(0,1) Then Move = Column
  230.                                 End If
  231.                         Next
  232.                         Column = Move
  233.                         State = STATE_COMPANIM
  234.                         AnimX = Move * 64 + 144
  235.                         AnimY = (8-l[Move])*64
  236.                         AnimStartTime = MilliSecs()
  237.                 Case STATE_CHECKCOMP
  238.                         Drop = 7 - l[Column]
  239.                         Board[Column,Drop] = 2
  240.                         l[Column] :+ 1
  241.                         Result = CheckConnect(Column,Drop,State)
  242.                         State = STATE_PLAYERTURN
  243.                         For Local i:Int = 0 To 3
  244.                                 If Result[i] >= 4 Then State = STATE_COMPWINS
  245.                         Next                           
  246.  
  247.         End Select
  248. Wend
  249.                        
  250. Function CheckConnect:Int[](Column:Int, Drop:Int, State:Int)
  251.         Local Result:Int[4]
  252.         Local Check:Int
  253.        
  254.         If State = STATE_CHECKPLAYER
  255.                 Check = 1
  256.         Else
  257.                 Check = 2
  258.         End If
  259.        
  260.         Result[0] = CheckDirection(Column,Drop,1,0,Check)
  261.         Result[1] = CheckDirection(Column,Drop,1,1,Check)
  262.         Result[2] = CheckDirection(Column,Drop,0,1,Check)
  263.         Result[3] = CheckDirection(Column,Drop,-1,1,Check)
  264.         Return Result
  265. End Function
  266.  
  267. Function CheckDirection:Int(Column:Int, Drop:Int, DirX:Int, DirY:Int, Check:Int)
  268.         Local Total:Int = 1
  269.         For Local d:Int = 0 To 1
  270.                 For Local i:Int = 1 To 3
  271.                 If Total = 4 Then Exit
  272.                         Local x:Int = Column+DirX*i, y:Int = Drop+DirY*i
  273.                         If x < 0 Or x > 7 Or y < 0 Or y > 7 Then Exit
  274.                         If Board[x,y] = Check
  275.                                 Total :+ 1
  276.                         Else
  277.                                 Exit
  278.                         End If
  279.                 Next
  280.                 DirX = -DirX
  281.                 DirY = -DirY
  282.         Next
  283.         Return Total
  284. End Function
  285.                
  286.  
Original Basic code: https://www.atariarchives.org/morebasicgames/showpage.php?page=63
------------------------------------------------
8 rabbits equals 1 rabbyte.

Online Steve Elliott

  • Hero Member
  • *****
  • Posts: 2117
  • elgol developer
Re: Four in a row
« Reply #1 on: August 25, 2019, 08:29:53 AM »
Very nice, and from the few goes I've just had quite challenging too.   :)

You did well to convert it to BM because the original BASIC version was awful!  No indentation and frequent use of the goto command!   :o
Windows 10, 64-bit, 16Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb).
MacOS Mojave, 64-bit, 8Gb RAM, CPU Intel i5, 2.3 Ghz, Intel Iris Plus Graphics 640 1536 MB.
Linux Mint 19.2, 64-bit, 16Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb).
Raspberry pi4 4Gb RAM

Offline TomToad

  • Sr. Member
  • ****
  • Posts: 451
Re: Four in a row
« Reply #2 on: August 25, 2019, 12:43:50 PM »
Quote
the original BASIC version was awful!  No indentation and frequent use of the goto command!   :o
That was pretty much necessary with BASIC back in the early 80's and earlier.  No way to indent, which would only result in slower code anyway as the interpreter would have to spend time skipping the spaces.  Also, early BASIC was not structured, so you would require goto for IF/THEN/ELSE structures and WHILE/DO/REPEAT type structures. Another problem with most implementation of BASIC is variable names.  Usually, only the first 2 characters are significant, so VEC1, VEC2, and VEC3 would all refer to the same variable, you had to use V1, V2, and V3 instead.  Also, variables couldn't contain keywords within them, so TOP couldn't be a variable as it contained the keyword TO.

I wrote many programs on my C64 this way.  Had both the books, "BASIC Computer Games" and "More BASIC Computer Games," and had typed many of the programs into my C64. 
------------------------------------------------
8 rabbits equals 1 rabbyte.

Online Steve Elliott

  • Hero Member
  • *****
  • Posts: 2117
  • elgol developer
Re: Four in a row
« Reply #3 on: August 25, 2019, 01:06:54 PM »
Quote
That was pretty much necessary with BASIC back in the early 80's and earlier.

Yes I know, I used those types of BASIC back then too.  It's just a shock seeing how atrocious that mass of characters looks these days.
Windows 10, 64-bit, 16Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb).
MacOS Mojave, 64-bit, 8Gb RAM, CPU Intel i5, 2.3 Ghz, Intel Iris Plus Graphics 640 1536 MB.
Linux Mint 19.2, 64-bit, 16Gb RAM, CPU Intel i5, 3.2 GHz, Nvidia GeForce GTX 1050 (2Gb).
Raspberry pi4 4Gb RAM