unknown bug in program (chess engine)

edited March 2018 in Questions about Code

I am trying to build a simple chess engine, but the check function isn't working. I have checked everything and the code makes sense, but it just doesn't work sometimes. It usually works, but there are a few exceptions. I have been trying to fix this bug, but no luck. Help is greatly appreciated!

void img() {
  wpawn = loadImage("whitepawn.png");
  bpawn = loadImage("blackpawn.png");
  bqueen = loadImage("blackqueen.png");
  wknight = loadImage("whiteknight.png");
  wbishop = loadImage("whitebishop.png");
  bknight = loadImage("blackknight.png");
  wrook = loadImage("whiterook.png");
  brook = loadImage("blackrook.png");
  wking = loadImage("whiteking.png");
  bking = loadImage("blackking.png");
  bbishop = loadImage("blackbishop.png");
  wqueen = loadImage("whitequeen.png");
  bpawn.resize(100, 100);
  wknight.resize(100, 100);
  bknight.resize(100, 100);
  wbishop.resize(100, 100);
  bbishop.resize(100, 100);
  wrook.resize(100, 100);
  brook.resize(100, 100);
  wking.resize(100, 100);
  bking.resize(100, 100);
  wqueen.resize(100, 100);
  bqueen.resize(100, 100);
  wpawn.resize(100, 100);
  locationsglobal[0][0] = wrook;
  locationsglobal[0][1] = wknight;
  locationsglobal[0][2] = wbishop;
  locationsglobal[0][4] = wqueen;
  locationsglobal[0][3] = wking;
  locationsglobal[0][5] = wbishop;
  locationsglobal[0][6] = wknight;
  locationsglobal[0][7] = wrook;
  locationsglobal[1][0] = wpawn;
  locationsglobal[1][1] = wpawn;
  locationsglobal[1][2] = wpawn; 
  locationsglobal[1][3] = wpawn;
  locationsglobal[1][4] = wpawn;
  locationsglobal[1][5] = wpawn;
  locationsglobal[1][6] = wpawn;
  locationsglobal[1][7] = wpawn;
  locationsglobal[7][0] = brook;
  locationsglobal[7][1] = bknight;
  locationsglobal[7][2] = bbishop;
  locationsglobal[7][4] = bqueen;
  locationsglobal[7][3] = bking;
  locationsglobal[7][5] = bbishop;
  locationsglobal[7][6] = bknight;
  locationsglobal[7][7] = brook;
  locationsglobal[6][0] = bpawn;
  locationsglobal[6][1] = bpawn;
  locationsglobal[6][2] = bpawn;
  locationsglobal[6][3] = bpawn;
  locationsglobal[6][4] = bpawn;
  locationsglobal[6][5] = bpawn;
  locationsglobal[6][6] = bpawn;
  locationsglobal[6][7] = bpawn;
}
PImage[][] movepiece(int y, int x, int y1, int x1, boolean side, PImage[][] locations) {
  if (side==white) {
    if (locations[y][x] == wqueen) {
      locations[y][x] = null;
      locations[y1][x1] = wqueen;
    } else if (locations[y][x] == wbishop) {
      locations[y][x] = null;
      locations[y1][x1] = wbishop;
    } else if (locations[y][x] == wknight) {     
      locations[y][x] = null;
      locations[y1][x1] = wknight;
    } else if (locations[y][x] == wrook) {
      locations[y][x] = null;
      locations[y1][x1] = wrook;
    } else if (locations[y][x] == wpawn) {
      locations[y][x] = null;
      locations[y1][x1] = wpawn;
    } else if (locations[y][x] == wking) {
      locations[y][x] = null;
      locations[y1][x1] = wking;
    }
  } else {
    if (locations[y][x] == bqueen) {
      locations[y][x] = null;
      locations[y1][x1] = bqueen;
    } else if (locations[y][x] == bbishop) {
      locations[y][x] = null;
      locations[y1][x1] = bbishop;
    } else if (locations[y][x] == bknight) {     
      locations[y][x] = null;
      locations[y1][x1] = bknight;
    } else if (locations[y][x] == brook) {
      locations[y][x] = null;
      locations[y1][x1] = brook;
    } else if (locations[y][x] == bpawn) {
      locations[y][x] = null;
      locations[y1][x1] = bpawn;
    } else if (locations[y][x] == bking) {
      locations[y][x] = null;
      locations[y1][x1] = bking;
    }
  }
  return locations;
}
PImage[][] locationsglobal = new PImage [8][8];
PImage wpawn, bpawn, wknight, bknight, wbishop, bbishop, wrook, brook, wqueen, bqueen, wking, bking;
boolean white = true, turn = white, black = false, click = false;
int clickx, clicky, clickx1, clicky1;
player john = new player(0, true);//0 is black, 1 is white
player ai = new player(1, false);
void setup() {
  size(800, 800);
  img();
  textSize(100);
}
void draw() {//------------------------------------------------------------------
  john.move();
  ai.move();
  showboard();
  noStroke();
}
void mousePressed() {
  if (click) {
    clickx1 = round(mouseX / (width/8)-0.5);
    clicky1 = round(mouseY / (height/8)-0.5);
    if (legal(clicky,clickx,clicky1,clickx1,black)) {
      locationsglobal=movepiece(clicky, clickx, clicky1, clickx1, black, locationsglobal);
      turn=white;
    }
    click= false;
  } else {
    clickx = round(mouseX / (width/8)-0.5);
    clicky = round(mouseY / (height/8)-0.5);
    click = true;
  }
}
void showboard() {
  for (int i = 0; i<=7; i++)
    for (int j = 0; j<=7; j++) { 
      if ((i+j)%2 == 0) fill(180, 180, 255);
      else fill(200, 115, 115);
      rect(j*width/8, i*height/8, width/8, height/8);//chessboard
      if (locationsglobal[i][j] != null) image(locationsglobal[i][j], j*width/8, i*height/8);//board
      if (click) {
        if (legal(clicky,clickx,i,j,black)) {
          fill(50, 175, 50, 150);
          ellipse(j*width/8+50, i*height/8+50, 20, 20);
        }
        if (legal(clicky,clickx,i,j,white)) {
          fill(50, 175, 50, 150);
          ellipse(j*width/8+50, i*height/8+50, 20, 20);
        }
        if (j == clickx && i == clicky && locationsglobal[i][j] != null) {
          fill(0, 0, 255, 100);
          rect(j*width/8, i*height/8, width/8, height/8);
        }
      }
      if (check(white, locationsglobal)) {
        fill(0, 255, 0);
        text("CHECK", width/2, height/2, width, height);
      } else if (check(black, locationsglobal)) {
        fill(0, 255, 0);
        text("CHECK", width/2, height/2, width, height);
      }
    }
}
boolean legal(int y,int x, int y1, int x1,boolean side){
  return (!incheck(y,x,y1,x1,side)&&validmove(y,x,y1,x1,side,locationsglobal));
}
boolean check(boolean side, PImage[][] locations) {
  int i, j = 0;
  boolean detected = false;
  for (i = 0; i<7; i++) {
    for (j = 0; j<7; j++) {
      if (side == white) {
        if (locations[i][j] == wking) { 
          detected = true;
          break;
        }
      } else {
        if (locations[i][j] == bking) { 
          detected = true;
          break;
        }
      }
    }
    if (detected == true) break;
  }
  for (int i2 = 0; i2<7; i2++) {
    for (int j2 = 0; j2<7; j2++) {
      if (side == white) {
        if (black(i2, j2, locations)) {
          if (validmove(i2, j2, i, j, black, locations)) {   
            return true;
          }
        }
      } else {
        if (white(i2, j2, locations)) {
          if (validmove(i2, j2, i, j, white, locations)) {
            return true;
          }
        }
      }
    }
  }
  return false;
}
boolean incheck(int y, int x, int y1, int x1, boolean side) {
  PImage[][] locations2= new PImage[8][8];
  for (int i = 0; i<7; i++) {
    for (int j = 0; j<7; j++) {
      locations2[i][j] = locationsglobal[i][j];
        locations2 = movepiece(y, x, y1, x1, side, locations2);
    }
  }
  if (check(side, locations2))return true;
  return false;
}
//boolean mate(
boolean validmove(int y, int x, int y1, int x1, boolean side, PImage[][] locations) {
  if (side==white) {
    if (notwhite(y1, x1, locations)) {
      if (locations[y][x] == wpawn) {
        if (y!=7) {
          if ((x-x1==1||x-x1==-1)&&y-y1==-1&&black(y1, x1, locations)) return true;//take
          if (locations[y1][x1] == null&&x==x1) {//no block
              if (y == 1 &&(y-y1 ==-1||y-y1==-2) ) {
                return true;
              } else return (y-y1 == -1&&x==x1);
          } else return false;//no block
        } else { 
          locations[y][x]=wqueen;
          return false;
        }
      } else if (locations[y][x] == wbishop) {
        if (notblocked(x, y, x1, y1, 1, 1, true, locations)) return true;//bottom right
        if (notblocked(x, y, x1, y1, -1, 1, true, locations)) return true;//top right
        if (notblocked(x, y, x1, y1, 1, -1, true, locations)) return true;//bottom left
        if (notblocked(x, y, x1, y1, -1, -1, true, locations)) return true;//top left
        return false;
      } else if (locations[y][x] == wrook) {
        if (notblocked(x, y, x1, y1, 0, 1, true, locations)) return true;//right
        if (notblocked(x, y, x1, y1, 0, -1, true, locations)) return true;//left
        if (notblocked(x, y, x1, y1, 1, 0, true, locations)) return true;//down
        if (notblocked(x, y, x1, y1, -1, 0, true, locations)) return true;//up
        return false;
      } else if (locations[y][x]==wqueen) {
        if (notblocked(x, y, x1, y1, 1, 1, true, locations)) return true;//bottom right
        if (notblocked(x, y, x1, y1, -1, 1, true, locations)) return true;//top right
        if (notblocked(x, y, x1, y1, 1, -1, true, locations)) return true;//bottom left
        if (notblocked(x, y, x1, y1, -1, -1, true, locations)) return true;//top left
        if (notblocked(x, y, x1, y1, 0, 1, true, locations)) return true;//right
        if (notblocked(x, y, x1, y1, 0, -1, true, locations)) return true;//left
        if (notblocked(x, y, x1, y1, 1, 0, true, locations)) return true;//down
        if (notblocked(x, y, x1, y1, -1, 0, true, locations)) return true;//up
        return false;
      } else if (locations[y][x]==wknight) {
        return((abs(y-y1)==2&&abs(x-x1)==1)||(abs(y-y1)==1&&abs(x-x1)==2));
      } else if (locations[y][x]==wking) {
        if (dist(x, y, x1, y1)<2) {
          return true;
        } else return false;
      } else return false;
    } else return false;
  } else {
    if (notblack(y1, x1, locations)) {
      if (locations[y][x] == bpawn) {
        if (y!=0) {
          if ((x-x1==1||x-x1==-1)&&y-y1==1&&white(y1, x1, locations)) return true;//take
          if (locations[y1][x1] == null&&x==x1) {//no block
              if (y == 6 &&(y-y1 ==1||y-y1==2) ) {
                return true;
              } else return (y-y1 == 1&&x==x1);
          } else return false;//no block
        } else { 
          locations[y][x]=bqueen;
          return false;
        }
      } else if (locations[y][x] == bbishop) {
        if (notblocked(x, y, x1, y1, 1, 1, false, locations)) return true;//bottom right
        if (notblocked(x, y, x1, y1, -1, 1, false, locations)) return true;//top right
        if (notblocked(x, y, x1, y1, 1, -1, false, locations)) return true;//bottom left
        if (notblocked(x, y, x1, y1, -1, -1, false, locations)) return true;//top left
        return false;
      } else if (locations[y][x] == brook) {
        if (notblocked(x, y, x1, y1, 0, 1, false, locations)) return true;//right
        if (notblocked(x, y, x1, y1, 0, -1, false, locations)) return true;//left
        if (notblocked(x, y, x1, y1, 1, 0, false, locations)) return true;//down
        if (notblocked(x, y, x1, y1, -1, 0, false, locations)) return true;//up
        return false;
      } else if (locations[y][x]==bqueen) {
        if (notblocked(x, y, x1, y1, 1, 1, false, locations)) return true;//bottom right
        if (notblocked(x, y, x1, y1, -1, 1, false, locations)) return true;//top right
        if (notblocked(x, y, x1, y1, 1, -1, false, locations)) return true;//bottom left
        if (notblocked(x, y, x1, y1, -1, -1, false, locations)) return true;//top left
        if (notblocked(x, y, x1, y1, 0, 1, false, locations)) return true;//right
        if (notblocked(x, y, x1, y1, 0, -1, false, locations)) return true;//left
        if (notblocked(x, y, x1, y1, 1, 0, false, locations)) return true;//down
        if (notblocked(x, y, x1, y1, -1, 0, false, locations)) return true;//up
        return false;
      } else if (locations[y][x]==bknight) {
        return((abs(y-y1)==2&&abs(x-x1)==1)||(abs(y-y1)==1&&abs(x-x1)==2));
      } else if (locations[y][x]==bking) {
        if (dist(x, y, x1, y1)<2) {
          return true;
        } else return false;
      } else return false;
    } else return false;
    // if
  }
}
boolean notblocked(int x, int y, int x1, int y1, int horizontal, int vertical, boolean side, PImage[][]locations) {
  for (int i = y + vertical, j  = x + horizontal; i <= 7 && j <= 7 && i >= 0 && j >= 0; i+= vertical, j+= horizontal) {
    if (side==white) {
      if (white(i, j, locations)) break;
      if (black(i, j, locations)) {
        if (i == y1 && j == x1)return true;
        break;
      }
    } else {
      if (black(i, j, locations)) break;
      if (white(i, j, locations)) {
        if (i == y1 && j == x1)return true;
        break;
      }
    }
    if (i == y1 && j == x1)return true;//no piece
  }
  return false;
}
class player {
  boolean ai, Break=false;
  int colour, y, x, x1, y1, val, valx, valy;
  player(int team, boolean computer) {
    colour = team;
    ai = computer;
  }
  void move() {
    if (ai&&frameCount%10==0) {
      if (turn==white) {
        while (turn==white) {
          Break=false;
          y = int(random(8));
          y1 = int(random(8));
          x = int(random(8));
          x1 = int(random(8));
          if (legal(y,x,y1,x1,white)) {

            locationsglobal=movepiece(y,x,y1,x1, white, locationsglobal);
            turn = black;
            print("yay");  
            break;
          }
        }
      }
      //if (frameCount%20==0&&turn==black) {
      //  while (turn==black) {
      //    Break=false;
      //    y = int(random(8));
      //    y1 = int(random(8));
      //    x = int(random(8));
      //    x1 = int(random(8));

      //    if (legal(y,x,y1,x1,black)) {

      //      locationsglobal=movepiece(x, y, x1, y1, black, locationsglobal);
      //      turn = white;
      //      print("yay");  
      //      break;
      //    }
      //  }
      //}
    }
  }
}
boolean black (int y, int x, PImage[][] locations) {
  return (locations[y][x] == bqueen || locations[y][x] == bknight || locations[y][x] == bpawn || locations[y][x] == brook || locations[y][x] == bbishop || locations[y][x] == bking);
}
boolean white (int y, int x, PImage[][] locations) {
  return (locations[y][x] == wqueen || locations[y][x] == wknight || locations[y][x] == wpawn || locations[y][x] == wrook || locations[y][x] == wbishop || locations[y][x] == wking);
}
boolean notblack (int y, int x, PImage[][] locations) {
  return (white(y, x, locations) || locations[y][x] ==null);
}
boolean notwhite (int y, int x, PImage[][] locations) {
  return (black(y, x, locations) || locations[y][x] ==null);
}
Tagged:

Answers

  • but it just doesn't work sometimes. It usually works, but there are a few exceptions

    Provide details about your bug and how to trigger it. This is important specially in those cases when "it doesn't work sometimes".

    Kf

  • the program occasionally works, and occasionally doesn't work, I do not know how to trigger the bug, but if you play against the random moving ai, you will see that the bug occurs sometimes

  • You haven't told us what the bug is!

  • which line numbers are involved?

    when it's a bug, is it a false positive or a false negative?

    which other figure is involved, pawn?

  • we can't run your code since we don't have the images.

    maybe you use several tabs instead of only one and upload to github?

    https://github.com

    Chrisir

  • edited March 2018

    The other thing that really bothers me is that your functions are passing arround 2D arrays of PImages! Can't you just enumerate the pieces and store a chessboard state in a 2D array of ints?

  • The bug is that the check function isn't working.

  • I don't really get what you mean, tfguy44

  • I only used one tab.

  • the figure that is involved is the king, it is the one that is being checked. also, any other piece that checks it is also involved.

  • The bug is that the check function isn't working.

    That's not enough.

    Does it say chess when there is none (false positive) OR does it say no check when there is a check (false negative)

    And if possible to say:

    In which circumstances does it occur, when the chess is given by a pawn or rook or... ?

  • I like your game!

    It's fun.

    But to control the check function you need to play an entire game

    But you should be able to load a game when it's very close to a check

  • Unbenannt

    Hm, it's check (and he recognized it correctly) but the white king on E1 is not shown anymore

  • edited March 2018

    Hm, it's check (and he recognized it correctly) but the white king on E1 is not shown anymore

    it's even check mate but he didn't say that

  • here he didnt'say check - false negative

    Unbena2nnt

  • he has issue if white king is on the 8 line

    Unbena2nnt

  • technically when it's check and he moves the king out of it, the message check appears only briefly

    instead you could have a String variable that is shown 30 secs with a timer and says it was check

    but nothing to do with the issue, I think

  • this looks suspicious but could work anyway

          for (int i = y + vertical, j  = x + horizontal; 
                i <= 7 && j <= 7 && i >= 0 && j >= 0; 
                i+= vertical, j+= horizontal) {
    
  • these are better colors for the board

    // color for Board (from Wikipedia)
    int col1 = #d18b47; 
    int col2 = #ffce9e;   
    
  • it both says check when there is none and sometimes doesn't say check. I don't know how to trigger the bug, but it appears several times in each game, you just need to observe.

  • if you don't want to constantly play the ai, you can uncomment the lines between 354 and 370, and change the speed with the framecounts. I find that the bug occurs a lot more when there are two ais playing.

  • nothing to do with your problem

    I think here

        boolean incheck(int y, int x, int y1, int x1, boolean side) {
    
          PImage[][] locations2= new PImage[8][8];
    
          for (int i = 0; i<7; i++) {
            for (int j = 0; j<7; j++) {
              locations2[i][j] = locationsglobal[i][j];
              locations2 = movepiece(y, x, y1, x1, side, locations2);
            }
          }
          if (check(side, locations2))
            return true;
          return false;
        }
    

    you want

    boolean incheck(int y, int x, int y1, int x1, boolean side) {
    
      PImage[][] locations2= new PImage[8][8];
    
      for (int i = 0; i<7; i++) {
        for (int j = 0; j<7; j++) {
          locations2[i][j] = locationsglobal[i][j];
        }
      }
    
      locations2 = movepiece(y, x, y1, x1, side, locations2);
    
      if (check(side, locations2))
        return true;
      return false;
    }
    

    instead

  • i got a lot not detected

    detected 03
    not detected
    not detected
    detected 03
    detected 03
    not detected
    not detected
    detected 03
    detected 03
    not detected
    not detected
    

    using this:

    boolean check(boolean side, 
      PImage[][] locations) {
    
      int i, j = 0;
      boolean detected = false;
    
      for (i = 0; i<7; i++) {
        for (j = 0; j<7; j++) {
          if (side == white) {
            if (locations[i][j] == wking&&!detected) { 
              detected = true;
              break;
            }
          } else if (side == black) {
            if (locations[i][j] == bking&&!detected) { 
              detected = true;
              break;
            }
          } else {
            println ("error 10179");
          }
        }//for
        if (detected)
          break;
      }//for
    
      if (detected) {
        println ("detected "+i+j); 
        for (int i2 = 0; i2<7; i2++) {
          for (int j2 = 0; j2<7; j2++) {
            if (side == white) {
              if (black(i2, j2, locations)) {
                if (validmove(i2, j2, i, j, black, locations)) {   
                  return true;
                }
              }
            } else {
              if (white(i2, j2, locations)) {
                if (validmove(i2, j2, i, j, white, locations)) {
                  return true;
                }
              }
            }
          }
        }
      } else {
        println("not detected");
      }
      return false;
    }
    
  • Ah all 4 for loops must have <= not only < !!!!!

  • no, that gives me a out of bound exeption for some reason

  • I think

  • and for your first solution, I have tried it before, it did not work. and the incheck function is not the only one that doesn't work, occassionally the check function also doesn't work.

  • ??

    you got <= in your others for loops - then the out of bound error is caused elsewhere in black or validmove?

    Also my other advice is valid: movepiece outside the nested for loop: otherwise you make the same error again and again

  • I have tried, I will try again, but so far nothing. and yes, the out of bounds error occurs in the black() and white() functions.

  • edited March 2018

    I have decided not to use openprocessing

  • actually chrisir I think your <= is the solution. I will message you again if it doesn't work, but at the moment it appears to be working, thanks

  • nevermind, there are still some bugs

  • nevermind, there are no more bugs hahah

  • Answer ✓

    THAT‘s a great achievement

  • thanks!

Sign In or Register to comment.