Connect Four: simple java 2 processing

edited December 2014 in How To...

Hi

I found tutorials to help me learn the basics of programming, to help me go ahead in my processing project. But due to the difference between bare java and processing, I can't implement some of the code I learned to processing. It seems to me that it is a problem of the program not stopping when asking for the user input

Here it is, can you guys help ?

///DECLARE
int EMPTY = 0;
int YELLOW = 1;
int RED = 2;
//the grid has lines et 7 colonnes
int [][] grid = new int [6][7];


void setup() {
  initialise(grid);
  display(grid);
}

void draw() {
  int playerColor = YELLOW;
  boolean won;

  //ask for a play
  //play 
  //display the game
  //switch player

  do {
    askandPlay(grid, playerColor);

    display (grid);

    won = isItWon(grid, playerColor);

    //switch color / player
    if (playerColor == YELLOW) {
      playerColor = RED;
    } else {
      playerColor = YELLOW;
    }
  }
  while (!won && !full (grid));

  if (won) {
    // it's inverted because we switched the players
    if (playerColor==YELLOW) {
      println("player 0 won !");
    } else {
      println("player X won !");
    }
  } else {
    println("match nul !");
  }


  //noLoop();
}


//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

boolean full (int [][] grid) {
  //if we find an empty cell on line 0 the grid is not full
  for (int i = 0; i< grid.length; i++) {
    if (grid[0][i] == EMPTY) {
      return false;
    } 
  }
  return true;
}

boolean isItWon(int [][] grid, int playerColor) {
  for (int line = 0; line < grid.length; ++line) {
    for (int colonne = 0; colonne < grid.length; ++colonne) {
      int cellColor = grid [line][colonne];
      //check if four are aligned
      if (cellColor == playerColor) {

        int lineMax = grid.length -4;
        int colonneMax = grid[line].length -4;

        if (
        // diago UP RIGHT
        (line >= 3 && colonne <= colonneMax &&
          count(grid, line, colonne, -1, +1) >= 4) ||
          // HORI RIGHT
        (colonne <= colonneMax &&
          count(grid, line, colonne, 0, +1) >= 4) ||
          // diago DOWN RIGHT
        (line <= lineMax && colonne <= colonneMax &&
          count(grid, line, colonne, +1, +1) >= 4) ||
          // DOWN
        (line <= lineMax &&
          count(grid, line, colonne, +1, 0) >= 4) 
          ) {
          //  if yes send true
          return true;
        }
      }
    }
  }
  return false;
}  

int count(int [][] grid, int startLine, int startCol, int dirline, int dirCol) {
  int counter = 0;
  int line = startLine;
  int colonne = startCol;
  while ( grid[line][colonne] == grid[startLine][startCol] &&
    line >= 0 && line < grid.length &&
    colonne >=0 && colonne < grid[line].length ) {
    ++counter;
    line   = line   + dirline;
    colonne = colonne + dirCol;
  }
  return counter;
}


void askandPlay(int [][] grid, int playerColor) 
{
  boolean valide;
  do {
    print ("playur ");
    if (playerColor == YELLOW) {
      print ("X");
    } else {
      print ("O");
    }
    println(" : entrez un numéro de colonne");
    /////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////input problem//////////////////////////////
    /////////////////////the program should wait for user input//////////////////
    /////////////////////////////////////////////////////////////////////////////
    int colonne = key;
    //arrays cells start from 0
    --colonne;
    println (colonne);
     valide = play (grid, colonne, playerColor);
    if (!valide) {
      println("ce coup n'est pas valide");
    }
  } 
  while (!valide);
}


boolean play (int [][] grid, int colonne, int couleur) {
  //if colonne number is not valide, the play is not
  if (grid[0][colonne] != EMPTY) {  
    return false;
  }
  //looking for first empty cell
  int line = grid.length -1;
  while (grid[line][colonne]!= EMPTY) {
    --line;
  }
  //filling the cell
  grid[line][colonne] = couleur;
  return true;
}


// display 0 for RED, X for YELLOW
void display(int [][] grid)
{
  for (int [] line : grid ) {
    print( " |" );
    for (int cellule : line ) {     
      if (cellule == EMPTY) {
        print (" ");
      } else if (cellule == RED) {
        print ("O");
      } else {
        print ("X");
      }
      print( "|" );
    }
    println();
  }

  print ("=");
  for (int i = 1; i<= grid[0].length; i++) {
    print("=" + i);
  }
  println("==");
}


void initialise(int [][] grid) {
  for (int i= 0; i < grid.length; i++) {
    for (int j= 0; j < grid[i].length; j++) {
      grid[i][j]=EMPTY;
    }
  }
}
Tagged:

Answers

  • Don't just copy and paste code and hope for the best. Try to understand what the original code is doing, and then try to recreate that yourself.

    You might think you've found a shortcut by using code you found, but really you're just heading towards a lot of headaches.

  • edited December 2014 Answer ✓

    to get an user input is not totally easy in processing

    processing doesn't wait but runs on and on (draw() is run 60 times per second)

    you have to make it so that you get the input while processing runs on and on

    this is done by the famous states... I show a simple way here....

    ;-)

    // the states of the program like start 
    // screen / pause screen / enter name screen
    // we start by giving the states names 
    final int STATEREADNAME = 0; // const 
    final int STATEPLAYGAME = 1;
    int state = STATEREADNAME;   // current state 
    
    String playerName="";
    
    void setup() {
      size(220, 220);
    }
    
    void draw() {
      // now we use state to decide what will happen 
      if (state==STATEREADNAME) {
        background(0);
        fill(255);
        text("Type your name and press enter:", 20, 20);
        fill(255, 255, 0);
        text(playerName, 20, 50);
      }
      else if (state==STATEPLAYGAME) {
        background(0);
        fill((millis()+100)%255, (millis()+200)%255, millis()%255);
        ellipse(mouseX, mouseY, 20, 20);
        fill (255);
        text (playerName + " is playing.", 10, 12);
      }
    }
    
    void keyPressed() {
      if (state == STATEREADNAME) {
        keyPressedForSTATEREADNAME();
      } // if state
    }
    
    
    void keyPressedForSTATEREADNAME() {
    
      // what key was it?   ---
      if ( (key>='a'&&key<='z') || ( key >= 'A'&&key<='Z')) {
        playerName+=key; // add this key to our name
      } // Letter 
    
      else if (key==ENTER||key==RETURN) {
        // go on to game
        state=STATEPLAYGAME;
        println ("Thank you, "+playerName+".");
      } // ENTER
    
      else if (key==BACKSPACE) {
        if (playerName.length()>0) {
          playerName=playerName.substring(0, playerName.length()-1);
        }
      } // BACKSPACE
    
      else { 
        println ("Unknow key "+ key);
      } // else
      //
      // end of check for keys ---
    }
    
    void mousePressed() {
      // return to state enter name
      if (state==STATEPLAYGAME) {
        state = STATEREADNAME;
      }
    }
    //
    
  • edited December 2014

    entrez un numéro de colonne

    so you have a state waitForInput and in draw() in this state nothing happens (or just text( "Please enter your move...", ... ); )

    in function void keyPressed() you monitor whether a key comes in

    when it does and it's correct (0..9) you set state back to statePlay in function void keyPressed() and do the move that has been entered

    you can add or rename states as you like....

    the code gets longer but is very reliable and stable.

    ;-)

  • edited December 2014

    do this only in function void keyPressed() not in normal functions (in normal functions you read in 3-5 keys, in function void keyPressed() only one each time a key is pressed)

    //////////////////////////////////////////////////////////////
    int colonne = key;
    
  • dear KevinWorkman I think you are misguided if you think that I just "copy / pasted code and wish for the best" I have been spending a month following a video course and one week on the "connect four" program alone... no code to copy was provided and I followed at least 2 times the making of each single line. I think I did my homework by looking for answers on forums and other processing dedicated pages before posting, as well as trying to implement some keyPressed() solution myself. In short, I've spent more than 15 years doing my autodidacts computer stuff training on the net :]

    I thank you very much Chrisir for your answer, It looks like it is precisely what I was looking for. To name it , this very user input question. I am going to study it :D

    cheers to you all

  • Here we go it didn't take me so long but : 1 - my internet connection was broken for 8 days 2 - I got a bug with the games code that I tried to fix... in vain but ! I got the USER INPUT part to work just as I wanted thanks to Chrisir's code here it is:

    // we start by giving the states names 
    final int STATEREADMOVE = 0; // const 
    final int STATEPLAYMOVE = 1;
    final int STATEPLAYWIN = 2;
    int state = STATEREADMOVE;   // current state 
    //////////////////////////////////////////////
    int EMPTY = 0;
    int YELLOW = 1;
    int RED = 2;
    int playerColor = YELLOW;
    //connect four has 6 lines and 7 cols
    int [][] grid = new int [6][7];
    //
    int col=0;
    //
    boolean won = false;
    boolean full = false;
    
    String playerName="";
    String pleasePlay="";
    
    void setup() {
      initialise(grid);
      display(grid);
    }
    
    void draw() {
      // now we use state to decide what will happen 
      if (state==STATEREADMOVE) {
        fill(255);
        text("readmode", 20, 50);
        /////////////////////////////////////////////////////////////
      } else if (state==STATEPLAYMOVE) {
        state=STATEREADMOVE;  //switches back to readmove, so this part won't loop !!
        won = isItWon(grid, playerColor);
        //    println(won);
        if (playerColor == YELLOW) {
          playerColor = RED;
        } else {
          playerColor = YELLOW;
        }
        display(grid);
        /////////////////////////////////////////////////////////////
      } else if (state==STATEPLAYWIN) {
        String winner = "";
        //waring the color is the oposite because we switched
        if (!full(grid)) {
          if (playerColor==YELLOW) {
            winner = "0 wins !";
          } else {
            winner = "X wins !";
          }
          background(255);
          fill(255, 0, 0);
          text(winner, 20, 50);
        } else {
          winner = "match nul !";
          background(128);
          fill(0);
          text(winner, 20, 50);
        }
      }
    }
    
    void keyPressed() {
      if (state == STATEREADMOVE) {
        keyPressedForSTATEREADMOVE(); //Chrisir's magic move
      } // if state
    }
    
    void keyReleased() {
      //check for a win each time user releases a key (move is done)
      if (won || full (grid)) {
        state=STATEPLAYWIN;
      }
    }
    
    //keyPressed fonction dedicated to the playermove (enter a col number)
    void keyPressedForSTATEREADMOVE() {
      boolean valide =false;
      if (!won) {
        // what key was it?   ---
        if ( (key>='1' && key<='7')) {
          col = char2int (key);
          --col;
          valide = play (grid, col, playerColor);
    
          if (valide) {
            state=STATEPLAYMOVE;
          }
        } //enter col number
      }
    }
    /////////////////////////////////////////////////////////////////////
    // game fonctions ///////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////
    
    boolean full (int [][] grid) {
      //if we find an empty cell on line 0, the grid isn't full
      for (int i = 0; i< grid.length; i++) {
        if (grid[0][i] == EMPTY) {
          return false;
        }
      }
      return true;
    }
    
    boolean isItWon(int [][] grid, int playerColor) {
      for (int line = 0; line < grid.length; ++line) {
        ///
        //here we have a problem with the line and col number getting out of bound
        ///
        for (int col = 0; col <  grid[line].length; ++col) {
          int coloreCase = grid [line][col];
          //check si 4 pions de meme colore sont alignés
          if (coloreCase == playerColor) {
            int lineMax = grid.length -4;
            int colMax = grid[line].length -4;
            //         print (grid.length + " / ");
            //                 println(grid[line].length);
            if (
            //UP RIGHT
            (line >= 3 && col <= colMax &&
              count(grid, line, col, -1, +1) >= 4) ||
              //RIGHT
            (col <= colMax &&
              count(grid, line, col, 0, +1) >= 4) ||
              //DOWN RIGHT
            (line <= lineMax && col <= colMax &&
              count(grid, line, col, +1, +1) >= 4) ||
              //DOWN
            (line <= lineMax &&
              count(grid, line, col, +1, 0) >= 4) 
              ) {
              return true;
            }
          }
        }
      }
      return false;
    }  
    
    int count(int [][] grid, int startLine, int startCol, int dirLine, int dirCol) {
      int counter = 0;
      int line = startLine ;
      int col = startCol;
      //println("lineDep "+ (startLine+1) + " / colDep "+  (startCol+1));
      while ( grid[line][col] == grid[startLine][startCol] &&
        line   >= 0 &&  line   < grid.length   &&
        col >= 0 &&  col < grid[line].length) {
        ++counter;
        line   = line   + dirLine;
        col = col + dirCol;
        //    print ("line "+ (line+1)  + " / ");
        //    print ("col "+ (col+1)  + ": ");
        //    println(counter);
      }
      return counter;
    }
    
    
    boolean play (int [][] grid, int col, int colore) {
      //if the col number isn't valide, the move isn't neither
      if (grid[0][col] != EMPTY) {  
        return false;
      }
      //browse the col from the bottom to find the first empty cell
      int line = grid.length -1;
      while (grid[line][col]!= EMPTY) {
        --line;
      }
      //fill the first cell found
      grid[line][col] = colore;
      return true;
    }
    
    //fonction to create the text to invit user to play
    String invite (int playerColor) {
      String who = "";
      pleasePlay = "player ";
      background(0);
      if (playerColor == YELLOW) {
        who = "X";
      } else {
        who = "0";
      }
      pleasePlay += who += " : enter a col number";
      return pleasePlay;
    }
    
    // display 0 pour une case RED, X pour une case YELLOW
    void display(int [][] grid)
    {
      for (int [] line : grid ) {
        print( " |" );
        for (int cell : line ) {     
          if (cell == EMPTY) {
            print (" ");
          } else if (cell == RED) {
            print ("O");
          } else {
            print ("X");
          }
          print( "|" );
        }
        println();
      }
      print ("=");
      for (int i = 1; i<= grid[0].length; i++) {
        print("=" + i);
      }
      println("==");
      //add invite text
      println("");
      if (!won) {
        println(invite(playerColor));
      } else {
        println("won !");
      }
    }
    
    
    void initialise(int [][] grid) {
      for (int i= 0; i < grid.length; i++) {
        for (int j= 0; j < grid[i].length; j++) {
          grid[i][j]=EMPTY;
        }
      }
    }
    
    //to read user input we have to convert keyboard char into int
    int char2int(char myChar) {
      int buffer = 0;
    
      switch (myChar) {
      case '0':
        buffer = 0;
        break; 
    
      case '1':
        buffer = 1;
        break; 
    
      case '2':
        buffer = 2;
        break; 
    
      case '3':
        buffer = 3;
        break; 
    
      case '4':
        buffer = 4;
        break; 
    
      case '5':
        buffer = 5;
        break; 
    
      case '6':
        buffer = 6;
        break; 
    
      case '7':
        buffer = 7;
        break;
    
        //    default;
        //    break;
      }
      return (buffer);
    }
    
  • edited December 2014

    a few remarks

    • char2int: this could be replaced by int(myChar) IIRC
    • what happens, when he enters 9? You gotta catch that (sorry, you have that of course)
    • text("readmode", 20, 50); - wouldn't it be more polite to write text("Please enter your move.", 20, 50); ?
    • I wonder about the global var won (and full). In theory this should be handled via states as well. Because won is the same as state=STATEPLAYWIN. But maybe you need a state STATEBOARDFULL then as well.
    • it would be nice to have a full graphical board in the main window. First line in setup(): size(700,600);

    great work!

    ;-)

  • I tried int(myChar) but couldn't get it to work using STATEPLAYWIN for both win and full is a bit of a shortcut :S, I realize this now. Don't have the time to put the graphical board together and I would have like to get the games code to be fixed first

    thank you for your remarks

Sign In or Register to comment.