> show canvas only <


/* built with Studio Sketchpad: 
 *   https://sketchpad.cc
 * 
 * observe the evolution of this sketch: 
 *   https://studio.sketchpad.cc/sp/pad/view/ro.jc0NSHwjnqf/rev.544
 * 
 * authors: 
 *   Farshid Naderi
 *   Sina Seifee
 *   Sina

 * license (unless otherwise specified): 
 *   creative commons attribution-share alike 3.0 license.
 *   https://creativecommons.org/licenses/by-sa/3.0/ 
 */ 



int   cellCount = 6;                   //min 3, max 20
color[]  colors = {color(50),          //default color
                   color(255,0,0,30),  //player one color
                   color(0,0,255,30)}; //player tow color
char[]   turnXO = {' ','X','O'};       //player names

int[]    score  = new int[3];
int      turn, cSize, frame;
Cell[][] grid;

void setup() {
  
  if (cellCount>=20)cellCount = 20;
  if (cellCount<= 3)cellCount = 3;

  size(400,430);
  smooth();
  frameRate(30);
  background(10);
  score[1] = 0;
  score[2] = 0;
  turn     = 0;    
  cSize    = width;
  grid     = new Cell[cellCount][cellCount];

  rectMode (CORNER);
  stroke(255);
  strokeWeight(2);
  
  for (int r = 0; r < cellCount; r+=1) {
    for (int c = 0; c < cellCount; c+=1) {
      grid[c][r] = new Cell(c, r);
  }}
}

void draw() {
  
  fill(10);
  rect (0,cSize,cSize,(cSize/10)); 
  if(turn <= cellCount*cellCount){
    for (int r = 0; r < cellCount; r+=1) {
      for (int c = 0; c < cellCount; c+=1) {
        grid[c][r].display();
        winCheck(c, r);
  }}}
  if(turn >= cellCount*cellCount) showWinner();
  if(frameCount>frame)
    if(turn%2 == 1 && turn <= cellCount*cellCount)moveAI();
  textSize(cSize*.04);
  textAlign(LEFT, TOP); 
  text("score "+str(turnXO[1])+" ("+score[1] +")  "+str(turnXO[2])+" ("+score[2]+")",5,cSize+(cSize/100));
}

void mousePressed() {
  if(turn%2 == 0){
    if(turn < cellCount*cellCount) {
      for (int r = 0; r < cellCount; r++) {
        for (int c = 0; c < cellCount; c++) {
          if(grid[c][r].sel==true) {
            grid[c][r].val=turn%2+1;
            turn++;
            //cursor(WAIT);
            frame = frameCount + int(random(3,20));
    }}}}else setup();}
}

void showWinner(){
  turn++;
  String winText;
  int win =0;
  if(score[1]+score[2] > 0){
    win = (score[1]>score[2])?1:2;
    winText = str(turnXO[win]) + " is winner Score: ";
    if(score[1]==score[2])
      winText = ":) who's winner? Score: ";
  }else{
    winText = "Sorry...! no one won Score: ";   
  }
  fill(blendColor(colors[win],color(50,50,50), MULTIPLY),20);
  rect(0,0,cSize,cSize);
  fill(255);
  textAlign(CENTER, CENTER);
  textSize(cSize*.05);
  text(winText+score[1] +"/"+score[2],cSize/2,cSize/2);
  textSize(cSize*.04);
  text("Click for reset",cSize/2,cSize/2+(cSize*.06));
} 

void winCheck(int cID, int rID){
  int ci, ri, cn, rn;
  int won  = 0, mx = cellCount-1;
  int[] c  = {-1,  0, +1, +1};
  int[] r  = {-1, -1, -1,  0};
  int[] id = new int[0];
  if( grid[cID][rID].val>0 ){
    for (int i = 0; i < 4 ; i++){
      ci = cID+c[i]; cn = cID+(c[i]*-1);
      ri = rID+r[i]; rn = rID+(r[i]*-1);
      if ( ci < 0 || cn < 0 || ci > mx || cn > mx ) continue;
      if ( ri < 0 || rn < 0 || ri > mx || rn > mx ) continue;
      if (grid[ci][ri].val == grid[cID][rID].val && grid[cn][rn].val == grid[cID][rID].val){
        if (grid[cID][rID].scr || grid[ci][ri].scr || grid[cn][rn].scr) {  
          line(grid[ci][ri].centerX, grid[ci][ri].centerY, grid[cn][rn].centerX, grid[cn][rn].centerY);
          id = append(id, cID+cellCount*rID);
          id = append(id,  ci+cellCount*ri);
          id = append(id,  cn+cellCount*rn);
          won = grid[cID][rID].val;
          score[won]++;
    }}}
  for(int i = 0; i < id.length; i++){
    ci  = id[i]%cellCount;
    ri  = floor(id[i]/cellCount);
    grid[ci][ri].scr = false;
  }}  
}

/////////////////////////////////////////
//// start Artificial intelligence //////
//
void moveAI() {
  cursor(WAIT);
  int[] priority = new int[cellCount*cellCount];

  for (int r = 0; r < cellCount; r+=1) {
    for (int c = 0; c < cellCount; c+=1) {
      if (grid[c][r].val == 0)
        grid[c][r].AI = priorityAI(c, r);
      else
        grid[c][r].AI = 0;
      priority[c+cellCount*r] = grid[c][r].AI;
    }
  }
  int maxP = max(priority);

  int[] listID = new int[0];
  for (int r = 0; r < cellCount; r+=1) {
    for (int c = 0; c < cellCount; c+=1) {
      if (grid[c][r].AI == maxP)
        listID = append(listID, c+cellCount*r);
    }
  }
  int id = listID[floor(random(listID.length-1))];
  int c  = id%cellCount;
  int r  = floor(id/cellCount);
  grid[c][r].val = 2;
  turn++;
  cursor(ARROW);
}

int priorityAI(int cID, int rID) {
  int p = 1;
  int[] c1 = { -1, 0, +1, +1, +1, 0, -1, -1 };
  int[] r1 = { -1, -1, -1, 0, +1, +1, +1, 0 };
  int[] c2 = { -2, 0, +2, +2, +2, 0, -2, -2 };
  int[] r2 = { -2, -2, -2, 0, +2, +2, +2, 0 };
  int ci1, ri1, cin, rin, ci2, ri2;     
  for (int i = 0; i < 8 ; i++) {
    ci1 = cID+c1[i]; cin = cID+(c1[i]*-1);
    ri1 = rID+r1[i]; rin = rID+(r1[i]*-1);
    ci2 = cID+c2[i]; ri2 = rID+r2[i];
    if ( ci1 < 0 || ci1 > cellCount-1)continue;
    if ( ri1 < 0 || ri1 > cellCount-1)continue;
    p++;
    if ( cin > 0 && cin < cellCount && rin > 0 && rin < cellCount )
      if ( grid[ci1][ri1].val == 2 && grid[cin][rin].val == 2 )
        p+=40;
    if ( cin > 0 && cin < cellCount && rin > 0 && rin < cellCount )
      if ( grid[ci1][ri1].val == 1 && grid[cin][rin].val == 1  )
        p+=80;
    if ( ci2 < 0 || ci2 > cellCount-1)continue;
    if ( ri2 < 0 || ri2 > cellCount-1)continue;
    p++; 
    if ( grid[ci1][ri1].val == 2 && grid[ci2][ri2].val == 2 ) p+= 80;
    if ( grid[ci1][ri1].val == 1 && grid[ci2][ri2].val == 1 ) p+= 160;
  }
  return p;
}
//
//////////////////////////////end AI.////
/////////////////////////////////////////
  
/////////////////////////////////////////
//// start class Cell ///////////////////
//
class Cell { 
  boolean sel,     scr;
  float   startX,  startY;
  float   len,     rand;
  float   centerX, centerY;
  int     AI,      val;      
  int     cID,     rID;
  char    stringXO;  
  color   col;
  
  Cell(int columnID, int rowID) {
    col = color(50);      
    AI  = 0; 
    cID = columnID;
    rID = rowID;
    val = 0;
    sel = false; 
    scr = true;
    len = (cSize /cellCount);
    rand= random(500);
    startX  = (cSize /cellCount*cID);
    startY  = (cSize/cellCount*rID);
    centerX = startX+(len/2);
    centerY = startY+(len/2);
    stringXO= ' ';
  }  
  void display(){
    sel = false;
    col = colors[val];
    stringXO  = turnXO[val];
    
    if( mouseX > startX &&  mouseX < startX+len)
      if( mouseY > startY &&  mouseY < startY+len)   
        if(val==0){
          col = blendColor(colors[turn%2+1],color(50,50,50), MULTIPLY);
          sel = true;
          stringXO  = turnXO[turn%2+1];
        }
    fill(col);
    stroke(255);
    rect(startX, startY, len, len);
    fill(255);
    textSize ((cSize*.5)/(cellCount));
    textAlign(CENTER, CENTER);
    float noiseX = map( noise(.03*frameCount+rand     ), 0, 1, len*-.2, len*.2);
    float noiseY = map( noise(.02*frameCount+rand*rand), 0, 1, len*-.2, len*.3);    
    text(stringXO, centerX+noiseX, centerY-noiseY);
    //textSize ((cSize*.25)/(cellCount));
    //text(AI,centerX,centerY-(len/3*0));
    //text(cID+" "+rID,centerX,centerY+(len/3.5));
  }      
}
//
//////////////////////end class Cell.////
/////////////////////////////////////////