Connect 4
#1
Having just recently worked out AI for Tic Tac Toe Game and Sudoku Puzzles with Solver, I am now wondering about taking another stab at Connect 4 Game.

Not that much different from Tic Tac Toe:

Presented with a grid to play a game on, each player takes turns placing their token on a square until one gets 4 in a row, column of diagonal or the board is full and there is a draw.

The difference is that in Connect 4 the game tokens are stacked in columns and I think the basic game has 8 columns. Nope, boards pictured are 7 across and 6 high mostly but some are 8 x 8. Does it make a difference?

So the basic game is:

Code:
while play 
  setup a board, players colors and who goes first, player or AI?
  the game main loop:
     display board
     get players move
     check if win if so exit loop
     get AI move 
     check if win if so exit loop
     check if board is full, if so exit loop
   loop
   report winner
    play again? if not > done
loop

Make const N the number of columns and rows.
Make const player color red
Make const AI color blue
Make const Grid color and narration green
Make const player token = 1
Make const AI token = -1
so that if we add 4 squares a win = 4 or -4

Code to display board, color stack squares, show bare bones grid in middle of screen, with space above for messages to player and space below for Hollywood like title CONNECT4? 

SQ = square size,  60 is nice so how big a screen for that?
N * SQ + SQ margin on each side = 10 * SQ for Screen Width = SW
Add 2 more SQ on Screen Height = 12 *SQ for Screen Height = SH

Well that's a good start.
B += x
Reply
#2
Starter started no real AI yet:
Code:
' Connect4 start.bas for SmallBASIC 0.12.11 (B+=MGA) 2018-01-25

' like Tic Tac Toe only 4 in row, column or diagonal and stack blocks

const SQ = 60       'square or grid cell
const SW = SQ * 10  'screen width
const SH = SQ * 12  'screen height
const  N = 8        'number of rows and columns
const NM1 = N - 1   'N minus 1

const  P = 1   'Player is 1 on grid
const AI = -1  'AI is -1 on grid
const GC = 10  'Grid Color Green
const AC = 9   'AI color = blue
const PC = 12  'player color = red

const XO = SQ        'x offset for grid
const YO = 2 * SQ    'y offset for grid

'dim shared grid(NM1, NM1) ' for QB643

'while play
gameOn = "y"
while gameOn = "y"

 '  setup a board, players colors and who goes first, player or AI?
 dim grid(NM1, NM1)  'clear board
 'erase grid 'for QB64
 
 
 'test some winners debug
 'grid(0, 1) = 1
 'grid(0, 2) = 1
 'grid(0, 3) =1
 'grid(0, 4) =1
 
 
 winner = 0 : turn = P : update = 1
 
 ' the game main loop:
 while 1
   
   ' display board
   if update then showgrid
   
   ' get players move
   ' by mouse
   if pen(3) and turn = P then
     while pen(3) : mx = pen(4) : my = pen(5) : delay 30 : wend
     row = (my - YO)/SQ : if row > 0 then row = int(row) else row = -1
     col = (mx - XO)/SQ : if col > 0 then col = int(col) else col = -1
     
     'locate 1, 1 :  print col : delay 500 'debug ha! int(-.5) = 0 not -1
     
     if col >= 0 and col <= NM1 and row >= 0 and row < 8 then
       'find next space open on board
       r = getOpenRow(col)
       if r <> N then
         grid(col, r) = P : update = 1
         lastMove = r * N + col 'save this for AI
         ' check if win if so exit loop
         winner = checkwin
         if winner then exit loop else turn = AI
       end if
     else
       beep
     end if
   end if
   
   ' get AI move
   if turn = AI then
     makeAImove
     winner = checkwin
     if winner then exit loop else turn = P
   end if
   ' check if win if so exit loop

   ' check if board is full, if so exit loop
   'winner will report N when grid is full
   
   delay 30
   '   loop
 wend
 showGrid  'in case update was not updated
 ' report winner
 if winner = 9 then
   s = "No winner and board is full."
 elseif winner = -4 then
   s = "AI is Winner!"
 elseif winner = 4 then
   s = "Human is Winner!"
 end if
 locate 2, 2 : ? s
 
 ' play again? if not > done
 locate 4, 2
 input "Play again, enter y for yes (all else quits) ";gameOn

 'loop
wend

sub showGrid
 'global grid, update
 local i, r, c
 cls
 update = 0
 for i = 0 TO N
   line SQ * i + XO, YO, step 0, N * sq, GC
   line XO, SQ * i + YO, step N * SQ, 0, GC
 next

 for r = NM1 to 0 step -1
   for c = 0 to NM1
     'in grid rows are reversed 0 is top row
     if grid(c, r) = P then
       rect c * SQ + XO+1, r * SQ + YO+1, step SQ-1, SQ-1, PC filled
     elseif grid(c, r) = AI
       rect c * SQ + XO+1, r * SQ + YO+1, step SQ-1, SQ-1, AC filled
     end if
   next
 next
end sub

func checkwin()
 local gridFull, r, c, s
 gridFull = N
 for r = NM1 to 0 step -1 'bottom to top
   for c = 0 to NM1
     if grid(c, r) then
       'check if c starts a row
       if c < NM1 - 2 then
         s = 0
         for i = 0 to 3
           s = s + grid(c + i, r)
         next
         if s = 4 or s = -4 then checkwin = s : exit func
       end if
       'check if c starts a col
       if r > 2 then
         s = 0
         for i = 0 to 3
           s = s + grid(c, r - i)
         next
         if s = 4 or s = -4 then checkwin = s : exit func
       end if
       'check if c starts diagonal up to right
       if r > 2 and c < NM1 - 2 then
         s = 0
         for i = 0 to 3
           s = s + grid(c + i, r - i)
         next
         if s = 4 or s = -4 then checkwin = s : exit func
       end if
       'check if c starts a diagonal up to left
       if r > 2 and c > 2 then
         s = 0
         for i = 0 to 3
           s = s + grid(c - i, r - i)
         next
         if s = 4 or s = -4 then checkwin = s : exit func
       end if
     else
       gridFull = 0
     end if 'grid is something
   next
 next
 checkwin = gridFull
end func

sub makeAImove
 local lastCol, ro
 
 'when in doubt move on top of lastMove
 lastCol = lastMove mod N
 ro = getOpenRow(lastCol)
 if ro <> N and rnd < .25 then 'not all the time
   grid(lastCol, ro) = AI : update = 1 : exit sub
 end if
 'still here ? just find next open col
 for c = 0 to NM1
   ro = getOpenRow(c)
   if ro <> N then grid(c, ro) = AI : exit for
 next
 update = 1
end sub

func getOpenRow(forCol)
 local i
 getOpenRow = N 'assume none open
 for i = NM1 to 0 step -1
   if grid(forCol, i) = 0 then getOpenRow = i : exit func
 next
end func


Attached Files Thumbnail(s)

B += x
Reply