Next page | Contents page |

Click and move a group of cards

Now suppose there are several exposed cards in a column and we want to move all of the cards starting from one of those which is not the last card. This is slightly more complicated because we need a way to handle part of a column and test whether it is movable. To be movable all the cards down from the clicked one must be of the same suit and in descending consecutive order.

Do we need a new type, Subcolumn?

Several times now I have shown code for something we need to do and deduced from that the things we need to add to certain objects. This is often how it works: don't try to work the other way round, guessing what might be needed as you write one type of object. You may spend time writing things that turn out not to be needed at all.

So first see how the onClick() function has to change and then decide how to deal with subcolumns and moveability. This is what I did for onClick():


function onClick (e)
{ var xy = getMousePoint (e);
  console.log ("click");
  var target = findTarget (xy.x, xy.y, GAME.targets);
  if (null === target) return;
  var card = target.card;
  if (!card.faceUp) return;
  var cards = card.column.getSublist (card.columnIndex);
                         // array of cards, not a Column
  if (!isMovable (cards)) return;
  var card = cards [0];
  for (const COL of GAME.COLUMNS)
  { var last = COL.getLastCard ();
    if (null !== last)
    { if (last.suit === card.suit && last.value - 1 === card.value)
      { recordHistory ();
        for (var i = cards.length - 1; i >= 0; i--)
		{ cards [i].column.removeCard (cards [i]); }
        for (i = 0; i < cards.length; i++) COL.addCard (cards [i]);
        GAME.game.draw ();
        return;
  } } } // Not exact match, so try value match only (not suit):
  for (const COL of GAME.COLUMNS)
  { var last = COL.getLastCard ();
    if (null !== last)
    { if (last.value - 1 === card.value)
      { recordHistory ();
        for (var i = cards.length - 1; i >= 0; i--)
		{ cards [i].column.removeCard (cards [i]); }
        for (i = 0; i < cards.length; i++) COL.addCard (cards [i]);
        GAME.game.draw ();
        return;
  } } } // Is there an empty column to move to?
  for (const COL of GAME.COLUMNS)
  { if (null === COL.getLastCard ())
    { recordHistory ();
      for (var i = cards.length - 1; i >= 0; i--)
	  { cards [i].column.removeCard (cards [i]); }
      for (i = 0; i < cards.length; i++) COL.addCard (cards [i]);
      GAME.game.draw ();
      return;
  } }   
}

The new things here (compared to the previous page) are Column.getSublist(), isMovable() and recordHistory(). The last of those will be dealt with on the next page, so here are the other two:


Column.prototype.getSublist = function (startIndex)
{ return this.CARDS.slice (startIndex); 
  // a list of cards, not a true Column:
  // values of card.columnIndex will be irrelevant
};

That's very simple and of course it goes in the Column file. The other one is Spider-specific and should be in the Spider file:


// Array of cards must all be same suit and 
// consecutive descending values
function isMovable (cards)
{ if (1 === cards.length) return true;
  var SUIT = cards [0].suit;
  var VALUE = cards [0].value;
  for (var i = 1; i < cards.length; i++)
  { if (cards [i].suit !== SUIT) return false;
    if (cards [i].value !== VALUE - i) return false;
  }
  return true;
}

Note the value testing line: that's i at the end, not 1.

For beginners: starting the names of functions or methods with words such as "is" or "has" implies that the return value will be a boolean (keywords true or false: don't use numbers). This is another naming convention that helps to see easily what is going on.

Next we will see what recordHistory() is about...

Next page | Contents page |