FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Connect 4 tutorial

 
Post new topic   Reply to topic     Forum Index -> Tutorials
View previous topic :: View next topic  
Author Message
DonAman



Joined: 27 Nov 2011
Posts: 4

PostPosted: Tue Dec 06, 2011 6:08 am    Post subject: Connect 4 tutorial Reply with quote

As 2nd year students in ENSICAEN (a french engineering school) we are supposed to work on a one-year project which we must choose the topic from a given list. We had the opportunity to choose a project concerning the YAGE 3D engine, beeing supervised by 'Anarky' on this forum. As a first step, we have been asked to write some tutorials to help beginners to create a simple D program...

Please don't hesitate to express your suggestions about this tutorial in order to be able to improve it.
______________________________________________________________________________________

Here is a small tutorial to develop a 'Connect4' game in D language.

To do this, we will use the Tango library.

D is an object-oriented language, so we create a class 'Connect4' that
will contain all the necessary to model the game:

attributes:

-a matrix 7*6 filled with characters that represent the game board itself
-the current player (2 possible values)

methods:

-switch player: method that switches from player 1 to player 2 or player 2 to player 1
-addPawn: method that adds a pawn in a column of the game
-isPlayable: indicates if the selected column is playable: it checks if the column where to play exists and if it's not full already.
-draw: checks if it's still possible to add pawns in the game.
-play: plays the whole game until someone win or until all cells are filled with pawns.

Here is the code with descriptive comments:

Code:

import tango.io.Stdout;
import tango.stdc.stdio;

/*Change it if you want to specify a different board size*/
const int WIDTH = 7;
const int HEIGHT = 6;

/*definition of directions, used as iterators to check a winning move: CHK_DIR = [a,b] where a and b are respectively horizontal and vertical elementary displacements:*/ 

/*to move on a same row (row number is untouched)*/
const int[2] CHK_ROW = [0,1];
/*to move on a same col (col number is untouched)*/
const int[2] CHK_COL = [1,0];
/*to move on a ascending diagonal*/
const int[2] CHK_DIAG_ASC = [-1,1];
 /*to move on a descending diagonal*/
const int[2] CHK_DIAG_DSC = [1,1];

/*class describing the whole game*/
class Connect4 {
   
   private:

   /*represents the board*/
   char m[HEIGHT][WIDTH];

   /*the current player*/
    char player;
   
   /*to switch from a player to another */
    void switchPlayer(){
      if (player == 'x'){
         player = 'o';
      }
      else {
         player = 'x';
      }   
    }
   
   /*Checks if at least 4 pawns are aligned among the 4 possible directions*/
    bool isWinningMove(uint row,uint col,char player){
   
         /*Checks if a least 4 pawns are aligned for a specific direction (Nested function are allowed in D)*/
         bool check(int[] direction){
         
    /*moves and counts forwards in the given direction*/
            int nextRow = row+direction[0];
            int nextCol = col+direction[1]; 
       /*counts the pawn that has just been added*/
            int total = 1;
                   
            /*while we stay in the bounds of the board and while the neighbor in the given direction belongs to the current player, we keep on counting*/
            while(nextCol<WIDTH && nextRow<HEIGHT && nextRow>= 0 &&
                  m[nextRow][nextCol] == player){   
                             
                total++;
                nextRow+= direction[0];
                nextCol+= direction[1];                       
            }       
           
        /*moves and counts backwards in the given direction*/
            nextRow = row-direction[0];
            nextCol = col-direction[1];
           
             while(nextRow<HEIGHT && nextCol>= 0 && nextRow>= 0 &&
                  m[nextRow][nextCol] == player){   
                             
                total++;
                nextRow-= direction[0];
                nextCol-= direction[1];                       
            }
           
            return total>= 4;       
         }
         /*Returns true if at least 4 pawns are aligned among the 4 possible directions*/
         return check(CHK_ROW)||check(CHK_COL)||check(CHK_DIAG_ASC)||check(CHK_DIAG_DSC);               
     }
     
   /*Displays the board*/
     void display(){   
     
        /*upper delimiter*/
         for(uint j = 0;j<WIDTH;j++){
       Stdout("--");
         }
    Stdout.newline();
         
        /*The board itself*/
         for(uint i = 0;i<HEIGHT;i++){
            for(uint j = 0;j<WIDTH;j++){
          Stdout(m[i][j]~" ");          
            }
       Stdout.newline();
         }

         /*lower delimiter*/
         for(uint j = 0;j<WIDTH;j++){
       Stdout("--");
         }
               
    Stdout.newline();

         /*display column labels*/
         for(uint j = 0;j<WIDTH;j++){
       Stdout.format("{} ",j);
         }
         Stdout.newline();
     }
     
   /*Adds a pawn to a given column*/
     bool addPawn(uint col,char player){
         uint i = 0;
         
         /*The pawn is going down until it can't go further*/
         while(i<HEIGHT && m[i][col] == '.'){
            i++;
         }
         i--;
    /*Puts the pawn*/
         m[i][col] = player;
    /*Checks if it's a winning move*/     
         return isWinningMove(i,col,player);                     
     }
     
   /*Checks if a column is playable (must be in bounds and not fully filled up)*/
     bool isPlayable(uint col){
     
         return (col>= 0 && col<WIDTH && m[0][col] == '.');     
     }   
     

   /*Checks if it's still possible to add a pawn on the board*/
     bool draw(){
     
         for(int j = 0;j<WIDTH;j++){
       /*if a top row containing a free cell exists, the game continues*/
            if(m[0][j] == '.'){
               return false;
            }
         }
         /*if none of the top rows contains a free cell, then the game is a draw*/
         return true;
     }
   
   public:
   
   /*Constructs the board of the game and initializes variables*/
     this(){
   /*the first player to play is player 'x'*/
        player = 'x';
        for(int i = 0;i<HEIGHT;i++){
            for(int j = 0;j<WIDTH;j++){
          /*empty cells are filled with '.'*/
             m[i][j] = '.';
            }
        }
     }
   
   /*Plays the  whole game until someone win or until all cells are filled up with pawns.*/
     void play(){   
   /*will contain the column number where the player wants to play (read from input stream). Initialization with an out-of-bound value*/
   uint colToPlay = WIDTH;
   /*no winner at the beginning*/
   char winner = '_';

        /*While it's still possible to play and nobody wins:*/
         while(!draw() && winner == '_'){
            /*Tries to read the column where to play from the input buffer until the user make a possible choice: */
            do{
                display();
      Stdout.format("Player '"~player~"' plays: enter a column number where to play.").newline();
                scanf("%u",&colToPlay);
       /*to clean the input buffer (in case of failure)*/
                scanf("%*[^\n]");
                getchar();
      if(!isPlayable(colToPlay)){
         Stdout.format("This is not a valid move, please chose an other column where to play.").newline();
      }
             }
             while(!isPlayable(colToPlay));
        /*if the move leads to a victory:*/
             if (addPawn(colToPlay,player)){
       /*current player is the winner*/
                winner = player;
             }
             else{
      /*else we can switch players*/
               switchPlayer();
             }         
         }
         display();
    /*if still no winners a this point, it means we exited the main loop because of a draw game:*/
         if(winner == '_'){   
       Stdout("Draw!").newline();
         }
         else{
       Stdout.format("Player '{}' won!",winner).newline();
         }   
     }
}

/*let's play!*/
int main(){

   Connect4 c4 = new Connect4();
   c4.play();
   return 0;
}
Back to top
View user's profile Send private message
JoeCoder



Joined: 29 Oct 2005
Posts: 294

PostPosted: Fri Feb 17, 2012 10:00 pm    Post subject: Reply with quote

Sorry to see that nobody responded to this. In the future, you might try posting in the D newsgroup at http://forum.dlang.org. There's usually a lot more activity there than on dsource.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Tutorials All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group