SyntaxBomb - Indie Coders

Languages & Coding => BlitzMax / BlitzMax NG => Topic started by: TomToad on August 24, 2019, 21:22:01

Title: Four in a row
Post by: TomToad on August 24, 2019, 21:22:01
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) Select
'**********************************************************
'*
'*    Four in a Row
'*    by TomToad
'*    Adapted from code by James L Murphy which appears in
'*       More Basic Computer Games
'*   https://www.atariarchives.org/morebasicgames/showpage.php?page=63
'*
'**********************************************************
SuperStrict

Graphics 800,600
While Not MouseHit(1)
If KeyHit(KEY_ESCAPE) Or AppTerminate() Then End
Cls
SetScale 3,3
DrawText "Four in a Row",10,10
SetScale 2,2
DrawText "Click mouse button to continue",10,100
Flip
Wend

SetScale 1,1
Local BoardImage:TImage = CreateImage(512,512)
Cls
SetColor 255,255,0
DrawRect 0,0,512,512
SetColor 0,0,0
For Local x:Int = 0 To 7
For Local y:Int = 0 To 7
DrawOval x*64+8,y*64+8,48,48
Next
Next
SetColor 255,255,255
GrabImage BoardImage,0,0

Global Board:Int[8,8], l:Int[8], s:Int[4], f:Int[4], v:Int[16], n:Int[4]
DefData 1,100,500,2^20,1,800,4000,2^20
DefData 1,75,900,2^18,1,450,3000,2^18

For Local i:Int = 0 To 15
ReadData v[i]
Next

For Local i:Int = 0 To 7
For Local j:Int = 0 To 7
board[i,j] = 0
Next
l[i] = 0
Next

Local State:Int, MX:Int, MY:Int
Const STATE_PICKTURN:Int = 0
Const STATE_PLAYERTURN:Int = 1
Const STATE_COMPTURN:Int = 2
Const STATE_PLAYERANIM:Int = 3
Const STATE_CHECKPLAYER:Int = 4
Const STATE_COMPANIM:Int = 5
Const STATE_CHECKCOMP:Int = 6
Const STATE_PLAYERWINS:Int = 7
Const STATE_COMPWINS:Int = 8
Const STATE_TIE:Int = 9

While State = STATE_PICKTURN
If KeyHit(KEY_ESCAPE) Or AppTerminate() Then End
Cls
SetScale 4,4
DrawText "Who goes first?",10,10
SetScale 1,1
DrawRect 10,100,400,60
DrawRect 10,170,400,60
SetColor 0,0,0
SetScale 3,3
DrawText "Me!!!!",15,105
DrawText "Computer",15,175
Flip
SetColor 255,255,255
If MouseHit(1)
MX:Int = MouseX()
MY:Int = MouseY()

If MX > 10 And MX < 410 And MY > 100 And MY < 160 Then State = STATE_PLAYERTURN
If MX > 10 And MX < 410 And MY > 170 And MY < 230 Then State = STATE_COMPTURN
End If
Wend

SetScale 1,1

Local Animate:Int = False, Column:Int, Drop:Int, Result:Int[]
Local AnimX:Float, AnimY:Float, AnimStartTime:Int, AnimTime:Int,dy:Float,Delta:Float
While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
MX = MouseX()
MY = MouseY()
Cls
If state = STATE_PLAYERANIM Or State = STATE_COMPANIM
AnimTime = MilliSecs() - AnimStartTime
If STate = STATE_PLAYERANIM
SetColor 192,192,192
Else
SetColor 192,0,0
End If
delta = Float(AnimTime)/500
dy:Float = delta*512.0
DrawOval Animx,dy,60,60
If State = STATE_PLAYERANIM
SetColor 255,255,255
Else
SetColor 255,0,0
End If
DrawOval Animx+2,dy+2,56,56
If dy >= AnimY
If State = STATE_PLAYERANIM
State = STATE_CHECKPLAYER
Else
State = STATE_CHECKCOMP
End If
End If
End If
SetColor 255,255,255
DrawImage BoardImage,144,64
For Local x:Int = 0 To 7
For Local y:Int = 0 To 7
Select Board[x,y]
Case 0
SetColor 0,0,0
Case 1
SetColor 255,255,255
Case 2
SetColor 255,0,0
End Select
If Board[x,y] > 0 Then DrawOval x*64+152,y*64+72,48,48
Next
Next
SetColor 0,0,255
DrawRect 124,576,552,24
If State = STATE_PLAYERTURN
SetColor 192,192,192
DrawOval MX-30,MY-30,60,60
SetColor 255,255,255
DrawOval MX-28,MY-28,56,56
End If
If State = STATE_PLAYERWINS
SetColor 255,255,255
SetScale 2,2
DrawText "Player Wins!!!!",10,10
SetScale 1,1
End If
If State = STATE_COMPWINS
SetColor 255,0,0
SetScale 2,2
DrawText "Computer Wins!!!!",10,10
SetScale 1,1
End If
If State = STATE_TIE
SetColor 0,255,0
SetScale 2,2
DrawText "Tie Game!!!!!!",10,10
SetScale 1,1
End If
Flip

Select State
Case STATE_PLAYERTURN
State = STATE_TIE
For Local i:Int = 0 To 7
If l[i] < 7
State = STATE_PLAYERTURN
Exit
End If
Next
If State = STATE_TIE Then Continue
If MouseHit(1)
Column = (MX - 144)/64
If Column < 0 Or Column > 7 Or MY > 64 Or Board[Column,0] <> 0 Then Continue
State = STATE_PLAYERANIM
AnimX = Column * 64 + 144
AnimY = (8-l[Column])*64
AnimStartTime = MilliSecs()
End If
Case STATE_CHECKPLAYER
Drop:Int = 7 -l[Column]
Board[Column,Drop] = 1
l[Column] :+ 1
'Check for four in a row
Local Result:Int[] = CheckConnect(Column,Drop,State)
State = STATE_COMPTURN
For Local i:Int = 0 To 3
If Result[i] >= 4
State = STATE_PLAYERWINS
Exit
End If
Next
Case STATE_COMPTURN
State = STATE_TIE
For Local i:Int = 0 To 7
If l[i] < 7 Then State = STATE_COMPTURN
Exit
Next
If State = STATE_TIE Then Continue
Local MaxValue:Int = 0, Move:Int = -1
For Column = 0 To 7
Local CheckValue:Int = 0
Drop = 7 - l[Column]
If Drop > 7 Then Continue
Result = CheckConnect(Column,Drop,State)
Local Bonus:Int = 0
For Local Count:Int = 1 To 4
For Local i:Int = 0 To 3
If Result[i] = Count
CheckValue :+ V[(Count-1)+4*Bonus]
Bonus = 1
End If
Next
Next
Result = CheckConnect(Column,Drop,STATE_CHECKPLAYER)
Bonus:Int = 0
For Local Count:Int = 1 To 4
For Local i:Int = 0 To 3
If Result[i] = Count
CheckValue :+ V[(Count-1)+4*Bonus+8]
Bonus = 1
End If
Next
Next
If CheckValue > MaxValue
MaxValue = CheckValue
Move = Column
Else If CheckValue = MaxValue
If Rand(0,1) Then Move = Column
End If
Next
Column = Move
State = STATE_COMPANIM
AnimX = Move * 64 + 144
AnimY = (8-l[Move])*64
AnimStartTime = MilliSecs()
Case STATE_CHECKCOMP
Drop = 7 - l[Column]
Board[Column,Drop] = 2
l[Column] :+ 1
Result = CheckConnect(Column,Drop,State)
State = STATE_PLAYERTURN
For Local i:Int = 0 To 3
If Result[i] >= 4 Then State = STATE_COMPWINS
Next

End Select
Wend

Function CheckConnect:Int[](Column:Int, Drop:Int, State:Int)
Local Result:Int[4]
Local Check:Int

If State = STATE_CHECKPLAYER
Check = 1
Else
Check = 2
End If

Result[0] = CheckDirection(Column,Drop,1,0,Check)
Result[1] = CheckDirection(Column,Drop,1,1,Check)
Result[2] = CheckDirection(Column,Drop,0,1,Check)
Result[3] = CheckDirection(Column,Drop,-1,1,Check)
Return Result
End Function

Function CheckDirection:Int(Column:Int, Drop:Int, DirX:Int, DirY:Int, Check:Int)
Local Total:Int = 1
For Local d:Int = 0 To 1
For Local i:Int = 1 To 3
If Total = 4 Then Exit
Local x:Int = Column+DirX*i, y:Int = Drop+DirY*i
If x < 0 Or x > 7 Or y < 0 Or y > 7 Then Exit
If Board[x,y] = Check
Total :+ 1
Else
Exit
End If
Next
DirX = -DirX
DirY = -DirY
Next
Return Total
End Function


Original Basic code: https://www.atariarchives.org/morebasicgames/showpage.php?page=63 (https://www.atariarchives.org/morebasicgames/showpage.php?page=63)
Title: Re: Four in a row
Post by: Steve Elliott on August 25, 2019, 08:29:53
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
Title: Re: Four in a row
Post by: TomToad on August 25, 2019, 12:43:50
Quotethe 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. 
Title: Re: Four in a row
Post by: Steve Elliott on August 25, 2019, 13:06:54
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.