• Post Reply Bookmark Topic Watch Topic
  • New Topic

Chess program getting out of hand?  RSS feed

 
Louis Lewis
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello, I am currently writing a chess app in java swing. The application is just supposed to be a desktop chess program in which you can play against another person (on the same computer) by clicking the board, or against a computer. I have written most of the stuff required for it to play human v human already; basically, it has a jpanel with an 8 by 8 array of jlabels that I set to a set of chess Icons with black white and blue backgrounds (blue for when a piece is selected). With some minor glitches, right now you can start a new game, which sets up the board, and then you click on a piece to select and then move it, while the program checks to make sure you only do legal moves. However, I wanted the program to be really accurate, so I added in castling, and en passant, etc. I am currently trying to add in making the computer recognize check and checkmate, but realized something; my program is reaaallly long.

Although I made a separate class to make all the decisions as to whether or not a move is legal, the way I have the program set up, I still need to change a bunch of variables to pass into the methods from this rulebook class every time I try to make a move (I keep track of the pieces with several arrays, one that holds the actual jlabels and thus icons, one that holds which pieces are at which squares on the board, but stored in such a way that I can actually access the data for processing, and finally, one that holds the position of each piece (named based on original position) so that I can easily loop through all the pieces locations to do things like check and checkmate. As a consequence, in my main class, the method for handling when the board clicked is almost a thousand lines long, and as a consequence, is really hard to troubleshoot.

I'm relatively new to writing this kind of program, so I'm sure there's a more concise way to write my program at least to some extent, but I was just wondering, is this at least close to how long you might expect a program with these capabilities to be? I want to add in algorythms for determining check and checkmate, and then add a computer opponent, and I'm worried because as my program gets larger and larger it gets increasingly difficult to troubleshoot it.

Any advice?
 
Jeanne Boyarsky
author & internet detective
Marshal
Posts: 37462
537
Eclipse IDE Java VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Louis,
I'd expect it to be fairly substantial. (order of magnitude 1000 lines). Big programs aren't necessarily hard to read and troubleshoot though. I've worked on systems with hundreds of thousands of lines of code. The bigger the program is, the more important good design becomes.

Although I made a separate class to make all the decisions as to whether or not a move is legal, the way I have the program set up, I still need to change a bunch of variables to pass into the methods from this rulebook class every time I try to make a move (I keep track of the pieces with several arrays, one that holds the actual jlabels and thus icons, one that holds which pieces are at which squares on the board, but stored in such a way that I can actually access the data for processing, and finally, one that holds the position of each piece (named based on original position) so that I can easily loop through all the pieces locations to do things like check and checkmate. As a consequence, in my main class, the method for handling when the board clicked is almost a thousand lines long, and as a consequence, is really hard to troubleshoot.

This is a problem. A method stops being readable around 50-100 lines most of the time. A 1000 line method is going to be hard to deal with.

It sounds like your program isn't object oriented. This may because you haven't learned about that yet. At a minimum, you could make the state of the pieces instance (or static) variables or put them in a separate class. This lets you start splitting up your code into easily named methods.

If you want to post a snippet of your long method, we can give some more specific refactoring suggestions. [Please don't post more than 100 lines though - nobody wants to read 1000 line post ]
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jeanne Boyarsky wrote:It sounds like your program isn't object oriented...

To me too.

I suspect also that you've taken on an awful lot by trying to include the GUI straight away. If I was developing something like this - and you've chosen a pretty tough assignment for someone who's "relatively new" (not that there's anything wrong with that) - I'd keep GUI code out of it completely until I knew that my logic worked with good old keyboard input and a terminal display.

Since we don't have anything to go on, a few questions for you:
  • Do you have classes for the different types of piece? ie: Knight, Pawn, Bishop...
  • Do you have a class that describes a Piece?. eg: "White's left-hand Knight", "Black's 'A' Pawn".
  • Do you have a class that describes a direction? For example, I have a generic one (called Direction) that I use quite a lot that describes the 8 major directions as points on a compass: North, East, Southwest, etc; but you could just as easily use Left, Right, Up, Down and combinations to describe diagonals.
  • Do you have a Board? If I was doing this, I'd probably have this as a wrapper class to a Square[8][8], where each Square has a colour and a "position" (eg, "E4", but I might hold it as two integers that specify the row and column index) and possibly a Piece.

  • This is by no means the only way to do it, I just offer them as examples of the sort of things I'd be thinking about if I was designing a chess game - ie, I'd be looking at "what do I need to play a game of chess?", not "how am I going to code it?".

    For example: once you have a type of piece, you can then describe the way it moves as part of its class.

    Just one other point: Storing "moves" is very easy. Just use the notation that they do in actual chess games: Nb4d5 - ie, A "move" is simply the start and end points of a piece. Even the "N" is redundant, because the move simply applies to whatever piece was on "b4" at the start and, providing all stored moves are legal, you can replay a Game (another possible class to think about) by simply running through its moves.

    HIH

    Winston
     
    Louis Lewis
    Ranch Hand
    Posts: 86
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Well, I would say my program is object oriented to some degree, but apparently not to the degree that it could be. Currently I have the program set up with a RuleBook class, which contains methods that build on each other to eventually determine if a given move is legal based on arguments of the attempted move, and the current board position/piece positions array (which is an array I made as an alternative way of storing the board info--it contains the location of each piece (or null if the piece has been taken), named in the array based on the original piece position). These methods build as follows:

    emptyPath() determines if there is an empty path between a particular starting square and destination square (only used for rooks bishops and queens)
    pieceCapability() determines, based on the type of piece, attempted move, and board array, if a piece has the technical capability to execute the desired move
    reviewPosition() reviews a particular board array, and decides if either king is in check (or checkmate, although this part doesn't work yet)
    reviewMove() fully reviews any non special move (excluding en passant and castling, and decides if the move is legal based on the pieceCapability and reviewPosition methods

    Then, in the mainGUI class, inside the boardClicked method, the program determines which square was clicked based on the clicked coordinates, and current size of the board, and decides how to respond, using the reviewMove() method from the rulebook class. However, this method is super long, partially because, as I now realize, it includes all the special moves as separate if else statements (I think I should probably somehow move these to the RuleBook class somehow), appropriately modifies all the variables keeping track of the game before feeding them into the reviewMove() method, and then modifies the actual board variables appropriately once a move has been deemed legal.

    I didn't really understand how I would go about doing what Winston is suggesting, but maybe, as a start, I could move the special moves into the reviewMove() method, and then also add a method in another class for actual moving the pieces on the real board (using static variables as Jeanne suggests). Oh and I appreciate the offer, but I don't think I want to post actual snippets of the program since it would be pretty hard to find 100 lines representative of the overall program structure. Hopefully just describing the structure as I have above works.

    Thanks
     
    Campbell Ritchie
    Marshal
    Posts: 56529
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    To continue from what Winston said:
    Not only am I unconvinced you are using OO design, but also I am convinced that you are developing the app the wrong way round. you should be able to run it the way you read about chess games in the newspaper, eg “p→K4” (or “e4”) without a GUI at all. You should not even think about clicking a square until that is working correctly.

    Also remember that chess is incredibly complicated and you cannot expect to create a comprehensive chess program unless you spend months or years on it.
     
    Louis Lewis
    Ranch Hand
    Posts: 86
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Maybe I just don't understand OOP design then. My impressioin of it was just that it was using classes methods and objects to break parts of a larger program into chunks and then finally to make the actual implimentation of all these methods via objects fairly readable/understandable in the main class. Perhaps you guys could elaborate on what an object oriented chess program might be designed, at least in terms of checking move legality?

    Also, perhaps I should have started doing it newsprint style at first, but this is where I'm at right now and I feel like it might be a waste of all that I've done so far to go back now (in reponse to your other comment, I am slightly past the one year mark on this program right now).
     
    Campbell Ritchie
    Marshal
    Posts: 56529
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Dividing the processing into parts is only a part of what OO programming means. It means yuo create entities which mirror real‑life entities, each encapsulating its data and behaviour with those data.
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Louis Lewis wrote:Maybe I just don't understand OOP design then. My impressioin of it was just that it was using classes methods and objects to break parts of a larger program into chunks and then finally to make the actual implimentation of all these methods via objects fairly readable/understandable in the main class.

    Well, the first part of that sounds OK, but the second part doesn't. Your "main class" (at least the one that contains main()) should almost always be tiny. The logic for the one that actually "plays" the game - and since I assume you aren't trying to recreate Deep Blue here, let's call it the "robot" or "referee" - will be slightly more complex, but still pretty straightforward. Basically:
    For each move:
    1. Alternate the "current" Player.
    2. Accept a "move" from that Player.
    3. Validate it.
    4. Store it somewhere.

    Also, like Campbell, I'm not convinced that your design does actually use objects to break up the logic. It sounds much more as though you've treated the whole thing as a procedure (ie: code), and simply used methods to break up all that code into manageable chunks - ie, this program could just as easily have been written in C, which doesn't have either classes or objects.

    Don't worry, it's a common mistake, because we puny humans tend to think procedurally (do this; then do that; then do something else...). The problem is that it doesn't translate well to something like chess, which starts out with 32 pieces, each of which has it's own position and procedures, so trying to keep track of all of them in your head will drive you insane.

    Perhaps you guys could elaborate on what an object oriented chess program might be designed, at least in terms of checking move legality?

    Well, that's a huge subject, but let's start with the basics:
    Forget all about code for the moment (including move validation), and concentrate on WHAT you need to play a game of chess. Imagine you were trying to describe the game to a young child: Would you immediately dive into things like "check" and "threats" and "castling" and "en passant"?
    No.

    You might start out by describing the pieces and their types, but even before that you have the board. How big is it? Are all the squares the same colour? How are those colours arranged? Can you simply slap a chess board down any old way you like? Actually, logically you probably can; but convention says that the top-left square must be white.

    Then you'd probably describe the pieces: 32 units divided equally into 2 colours (1 for each Player) and consisting of 6 types. Then you'd probably name and describe each type, and their initial positions, and probably only then how each one moves...

    Do you see what's happening? You're describing what every chess player needs to know before they make their first move; and you can use precisely the same strategy for designing your program - ie, write down WHAT it needs before you write a single line of code.

    One approach is to write down all those instructions (or you could possibly use the Wiki page), and then read them through, several times, noting down all the major nouns (names) and verbs you can find.
    Nouns tend to equate to classes, and verbs to actions or methods, but it's not a hard-and-fast rule. You can also have events, which can be a bit tougher to spot - but examples in chess might be things like "threat" or "check". It's by no means fullproof, but it can often give you somewhere to start from, and it's a pretty simple exercise. And that's how you might get a list like the one I suggested above.

    And now to movement: What determines how a piece can move? What other constraints are there on movement? (Is the board infinitely large? Is the piece being moved the only one on the board? If a piece is blocked, does it matter what colour the "blocking" piece is?). Are there any exceptions to a "normal" move?

    These are a lot more complex than "what" questions, but a general approach is to start simple, and then refine. For example:
  • Start with a single piece on an infinitely large board.
  • Work out the "normal" move (or moves) for that piece before you start dealing with the exceptions. Eg: What is the "normal" move for a Pawn? How do you describe it?

  • I suspect you'll find that you end up with words like "direction" and "distance" (ie, how far you can move) which, in the case of a Knight, involves two values. In the case of a Rook, Bishop or Queen, "distance" isn't really a factor, since you can move it as far as you like - ie, it can only be stopped by "something else" (a blocking piece, or the edge of the board), but it'll sure as hell have a "direction'.

    Obviously I've left out an awful lot of stuff, but hopefully it gives you a taster. And just to recap:
  • Start out with WhatNotHow (←click).
  • Base your classes around what you need, not how you're going to code. And I'd say that if you don't have at least a dozen to start with, you probably don't have enough.
  • Any time you run into a problem, start simple, and deal with one thing at a time. Want to describe how to move a piece? Start with a Rook (or a Pawn) and describe THAT; and don't move on to the next one until you know it works - every single time and in every situation.

  • HIH

    Winston

    PS: Just one final point: Unfortunately, when it comes to describing "legal" movement, Pawns are probably the most difficult piece to describe (Sod's Law) since their "direction" is based on their colour, and they have a pile of exceptions, such as: opening move, capturing, en passant and "queening", so I suspect, following the principle of "simplest first" that you might be better off starting with Bishops and Queens; then maybe Knights...
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Louis Lewis wrote:Perhaps you guys could elaborate on what an object oriented chess program might be designed, at least in terms of checking move legality?

    I've been thinking about this a bit since I posted, and I wonder if it might not be possible to simplify the process.

    Rather than trying to describe exactly how each piece can move (you'll still need some of that) and then trying to fit it to the move that was made, why not start out with the move itself.

    Take the move above: Nb4d5, which we'll shorten to 'b4d5'. There are several things you can do right off the top:
  • Are 'b4' and 'd5' both valid squares? If not, the move is invalid.
  • Are 'b4' and 'd5' the same square? If so, the move is invalid.
  • Is there a piece on 'b4'? If not, the move is invalid.
  • Is there a piece of the same colour on 'd5'? If so, the move is invalid.
  • Is there a piece of any kind on 'd5'? If so, the move is a capture.

  • Note that we haven't even considered what type of piece is on b4 yet, but we've already eliminated 4 possible mistakes. We've also worked out whether the move - if valid - is a capture or not (with the sole exception of 'en passant').

    Next - work out the effect of the move as a vector: b4 → d5 is 1 row up and 2 across, so it would be [1, 2]. If it was d4 → b5, it would be [1, -2], and so on. (Unfortunately, chess notation is column-row, rather than row-colum, and goes bottom-left to top-right, but it doesn't really matter).

    Why do this? Well, think about the rules of chess: Every piece, apart from a Knight, moves either on a file, a rank, or a diagonal (or some combo thereof, but NOT in the same move).
  • What will the vector for a file move (eg, b4b6) look like? Answer: [x, 0], where 'x' is a value between -7 and +7 (not including 0).
  • What will the vector for a rank move (eg, b4d4) look like? Answer: [0, x].
  • What will the vector for a diagonal move (eg, b4d2) look like? Answer: [x, x] or [x,-x].
  • The only other possible valid vector is the one for a Knight, which will be some combination of ±1 and ±2.

    And a bit of manipulation can help you to reduce the things you need to check considerably:
    1. Replace each value in the vector with its absolute equivalent.
    2. Sort the resulting values.
    Now a rank OR file move will be [0, x] - where 'x' is now a value between 1 and 7 - a diagonal will be [x, x], and a Knight will be precisely [1, 2].

    So:
  • If the result is [1,2] and the piece on b4 is a Knight, the move is basically valid because a Knight can't be blocked; if it isn't, it's invalid.
  • If the result is not [0, x] or [x, x], it cannot be valid. So, for example, the move b4e5, which would produce the "normalized" vector [1, 3], can't be valid.
  • If any square between the start and endpoint has a piece in it, the move is invalid because it's "blocked".
  • If the piece on b4 is a Queen, the move is basically valid.
  • If the piece on b4 is a Bishop and the result is [x, x], the move is basically valid; otherwise it's invalid.
  • If the piece on b4 is a Rook and the result is [0, x], the move is basically valid; otherwise it's invalid.

  • Note that I said "basically valid" because there is one last (and rather nasty) check required for any move: Does it expose the King to threat?

    There's a few more checks needed for a Pawn (including 'en passant'), and lots more for a King, because it's not allowed to move into or through a threatened square, and for that reason (and the one above) I think I might be tempted to add an isThreatened() method to my Square class (and it might be quite hefty ). You also have the business of castling (long and short) to consider, but I'll leave that to your ingenuity. The only thing I can suggest is to treat it primarily as a King's move.

    There's no doubt that above approach is quite procedural, but it'll still benefit from having classes designed along the lines I suggested previously.

    HIH

    Winston
     
    Campbell Ritchie
    Marshal
    Posts: 56529
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Winston Gutkowski wrote: . . . I've been thinking about this a bit since I posted, and . . .
    …that is the way to make progress in coding.

    As Fred R often says, you spend most of your time thinking and little actually writing code. If you end up with a waste paper basket full of bits of paper with chess boards scribbled on, that is a good sign.
     
    Louis Lewis
    Ranch Hand
    Posts: 86
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    okay, I think I am going to try right rewrite the program in the fashion that you just described. However, I hope one more question. I understand the business of creating classes and objects analogous to real life, but I don't quite understand how this actually translates to displaying things that the user can see. For example, I don't think I would have a problem creating a class that stores information for a type of piece, and then creating an instance that represents a specific piece on the board, but I don't understand how the information stored in the object's class would be used to validate its move ( I don't really get where this code would actually go).

    Thanks though!
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Louis Lewis wrote:I understand the business of creating classes and objects analogous to real life, but I don't quite understand how this actually translates to displaying things that the user can see. For example, I don't think I would have a problem creating a class that stores information for a type of piece, and then creating an instance that represents a specific piece on the board, but I don't understand how the information stored in the object's class would be used to validate its move ( I don't really get where this code would actually go).

    I think there are two questions there:
    1. How do I translate objects to something the user can see?
    2. How do I store information (or possibly: WHAT information do I need to store) in a Piece class in order to validate a move?

    My answers:
    1. The simple answer is to come up with a symbol. For a GUI that might be an icon, for a console display it might be a letter: R=rook, Q-Queen, N=Knight...and so on. But the main thing is not to obsess about it too much. You need to understand the mechanics of the game, and how you translate them to a program (or class; or (probably) many classes), before you worry about display.

    One of the basic problems with translating games is that they ARE visual, so beginners tend to spend all their time thinking about what it should look like, rather than concentrating on what's important, which is: How does it work? ie - What makes it "tick"?

    Unfortunately, for something like chess, that involves quite a lot of stuff (that I hope we've covered somewhat; if not, please tell) but, just for example, there's one basic fact that you know about the game: It's played on an 8x8 "board" or grid. Not 9x6, or 100x100, but 8x8; and, since a "move" involves transferring a "piece" from one location to a different one (another part of the mechanics) in a diagonal or straight line (except for a Knight), it stands to reason that the new location can't be more than 7 places away. EVER. And since Java has a perfect mechanism for storing grids - a 2D array - it probably makes sense to represent your Board that way in the program.

    Now whether you decide to "display" that board as some combination of '.'s and letters on a console, or blue and pink bubbles in a GUI makes not a scrap of difference to the business of playing of the game.

    2. That's a bit harder, but the simple fact is that if you don't have a Piece object, you won't be able to store any information about it. And that's why working out what classes you're going to need is so important. However, here's a few suggestions:
  • It's type: (Knight, Pawn, Bishop etc).
  • It's colour.
  • It's starting position. That should allow you to determine its file (for a Pawn) or whether it's "King-side" or "Queen-side" for pieces where that's significant.
  • The number of moves that it's made so far. That will help to know, for example, whether a castling move is allowed, or whether a Pawn can move two spaces or not. For other pieces it's probably redundant, but it's only an extra int, so do you really care?

  • There are probably others that I've missed, but you can generally add them as you find a need. The main thing to make sure is that you have a class to put them in to begin with.

    It's a very difficult thing to get to grips with when you're starting out, but in general, when you're designing, you don't need to know exactly what a class is going to look like, or how you're going to code it, when you start out. The important thing to know is that it's required...and even that can be changed if you find a need - just add a new class.

    You might want to have a look at the WhereDoIStart page, which goes into this stuff (and the business of "stubbing") in a bit more detail.

    HIH

    Winston
     
    Louis Lewis
    Ranch Hand
    Posts: 86
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Alright, thanks for all the help, I think I am going to get going on trying to rewrite this program in an object oriented fashion.
     
    Winston Gutkowski
    Bartender
    Posts: 10575
    66
    Eclipse IDE Hibernate Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Louis Lewis wrote:Alright, thanks for all the help, I think I am going to get going on trying to rewrite this program in an object oriented fashion.

    It's probably worth keeping a copy of your old program even if you do, because you may actually be able to use some of its code. Just because a design is faulty doesn't mean to say that all the code you wrote for it is.

    Winston
     
    Giovanni Montano
    Ranch Hand
    Posts: 428
    7
    Android Open BSD Slackware
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Best all,
    there is a long lesson video on youtube on a Java Chess App in Swing, I guess is efficient.
    and is in my pipeline as well because chess is divine
    https://www.youtube.com/watch?v=cYn7NaUUZDw
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!