6

As someone new to programming, I am building a chess web application in JavaScript, both for fun and to learn more about design patterns. I keep running into a wall, which is how to decompose the program.

To start, I have picked a straightforward representation of a chessboard, here:

Board = function() {
  var turn = 0;
  var model = [[-4, -2, -3, -5, -6, -3, -2, -4],
               [-1, -1, -1, -1, -1, -1, -1, -1],
               [ 0,  0,  0,  0,  0,  0,  0,  0],
               [ 0,  0,  0,  0,  0,  0,  0,  0],
               [ 0,  0,  0,  1,  0,  0,  0,  0],
               [ 0,  0,  0,  0,  0,  0,  0,  0],
               [ 1,  1,  1,  1,  1,  1,  1,  1],
               [ 4,  2,  3,  5,  6,  3,  2,  4]];

with some basic access routines, such as

  this.move = function(pt1, pt2) {
    turn += 1;
    model[pt2.x][pt2.y] = model[pt1.x][pt1.y];
    model[pt1.x][pt1.y] = 0;
  };
  ...

It makes sense that the board encapsulates state and is responsible for changing state but may not know the rules of the game--I like the idea of being able to plug in some sort of RulesContoller and completely change the nature of the game at runtime. But beyond that, I'm a little paralyzed as to how granular to model the pieces. I see a few options.

First, I could define a Piece constructor and instantiate a new piece for each index in the nested array, something like:

  _.each(state, function(row, y) {
    _.each(row, function(val, x) {
      state[y][x] = new Piece(x, y, val);
    });
  });

Piece could easily deduce its color, type (e.g. 'king'), and location from that information. But it also feels redundant, since I'm just translating a model that already completely represents the board. Also, it doesn't seem like the primary purpose of the Piece 'class' is this translation, e.g. "Oh, I'm a -5, must be a dark Queen."

Another option is to make the pieces dumber, i.e. not able to deduce this information from the model. But then I just build the array in-line, like

  var model = [new Rook(1,1,'dark'), new Knight(1,2,'dark'), new Bishop(1,3,'dark')... ],
  ...

This seems closer to the way a chessboard is actually setup: there isn't some elegant formula; rather, you just put pieces in their correct location. But it's also just brute force. There are a few symmetries involved and patterns that might be simplified.

Anyway, I'm just spitballing at this point. Any ideas would be useful. Thanks.

13

The answer is to stop designing, since you don't have enough experience to know what to do, and start coding something. Maybe start with just pawns; add functions that can calculate the legal moves if there are only pawns on the board. Then add a king and see what that does to your code. And so on.

I have a lot of experience coding, and I still mostly work like this, implementing one thing at a time, and cleaning up as I go. A lot of complex applications have been built incrementally.

  • +1 for "code something", but don't stop designing. It's still good to have a rough idea of what you want to end up with/work towards in your head when you start. – Andy Hunt Feb 12 '14 at 8:39
  • @Andy: For small projects, it is entirely possible to just code and refactor until a design emerges. Even for experienced programmers, this often produces better code than they would get by following some preconceived design. – kevin cline Feb 14 '14 at 18:56
1

This sort of application is perfectly suited for functional programming. Create a few data structures (using prototypal inheritance pseudo classes) that track the state of the game: essentially the board state and the turn state. Board state tracks where all the pieces are. Turn state tracks whose turn it is. Together these two structures make up game state.

var state = new Game(new Board());
console.log(state.activePlayer) //white
console.log(state.board) //multi-dimensional array or some other construct
state = state.board.move(["Kf5", "Kd5"]);

All your persistent data structures supports is the actual visible state of the game. You never actually change the values of the data structure, but instead copy them into a new, but modified version of the data structure. This is ideal for allowing the computer to explore different moves (inside Web Workers?).

Then all you need to do is to start developing a few supporting functions that actually do the work of proposing moves. The most generic would be:

var suggest = AI.suggestMove(state); // ["Kf5", "Kd5"]
state = state.board.move(suggest);

Using functional techniques you're left only with data structures and functions and you won't need too many object constructors. This leaves you primarily to think about your functions (how to make the AI smart enough to win).

  • For this particular question, I found Kevin's answer more useful. But now that I've made some progress and have quite a bit of state-change going on, I'm finding your post useful as well. I'm trying to simplify my application so that side effects are restricted to only certain areas of the code. This is a good start, so thanks. – gwg Feb 27 '14 at 19:38
-2

The design of the board object should reflect somewhat to how it is viewed in the real world. A square on the chess board is defined by a x,y cord where one is a alphabetic character and the other being a integer. Each "space" in the data structure can be a pointer to a piece object. The Piece should be able to get its position on the board, but does not change the state of the board itself. The Rules Controller idea sounds good, it can take a piece look up its legal moves and then relocate the piece on the board. It can hit up any rules configuration you throw at it, like, replacing the pawn pieces with checkers.

  • 3
    "The design [...] of the [...] object should reflect somewhat to how it is viewed in the real world." - Why is this nessecary? Do you suggest, we should prefer real-world-alikeness of data structures over efficient and clean implementations? – JensG Feb 8 '14 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.