I'm going to assume that you have a fixed, small set of fruits, each with an associated id. The simplest way to implement this would be an enum:
enum Fruit {
APPLE,
PEAR,
BANANA
};
This way, APPLE
has the value 0, PEAR
is 1, and BANANA
is 2. Now you can represent any sack pair or card by an array telling how many occurrences there is of each fruit (each element would tell the number of occurrences of the fruit that corresponds to the index). For example, a card with two apples would be {2, 0, 0}
, and a sack pair with apples and bananas would be {1, 0, 1}
. For each sack pair, you would also keep track of the "visible" fruits: if the aforementioned sack pair hasn't been opened, we have {0, 0, 0}
, and when we have only revealed the apples, we would have {1, 0, 0}
.
Now, all you need to do to figure out whether a given card is compatible with what we know about a given sack pair is to check each pair of elements and see if all elements from the sack pair's array is less than or equal to the corresponding element of the card's array. No recursion needed:
bool isCompatible(const vector<int> & card, const vector<int> & sack) {
for (int i = 0; i < card.size(); i++) {
if (card[i] < sack[i])
return false;
}
return true;
}
bool isLegalMove(const vector<int> & movedCard, const vector<vector<int> > & otherCards, const vector<int> & sack) {
if (!isCompatible(movedCard, sack))
return false;
for (int i = 0; i < otherCards.size(); i++) {
if (isCompatible(otherCards[i], sack))
return false;
}
return true;
}
Edit: I still don't quite understand the mechanics of your game, but here's the general approach for simulating possible game moves until the game ends. The code assumes that any move will always make the game progress closer to the end, i.e. that it's not possible to go around in circles (if it were, you'd need additional code to keep track of which game states you've tried out).
I'm assuming that all of your game state is wrapped up in a class called GameState
, and that a move can be represented by Move
. In your case, you might have two subclasses of Move
, namely OpenSack
(containing the sack index) and MoveCard
(containing the original and final positions of the card being moved). You need a function vector<Move *> generateMoves(GameState &)
that can generate the moves that are possible in a given game state (note that if the game state is a "game over", this function should return an empty vector). Move
needs an abstract function GameState perform(const GameState &)
, to be implemented by each subclass, that will actually perform the move and create a new GameState
(rather than modifying the existing state) that represents the game state after the move. (In a game with a larger state, it would be better to actually modify the state, and to have a reverse()
method that would undo the effects of a move.) Then, the simulation can be implemented like this:
bool isSolvable(const GameState & currentState) {
if (currentState.isValidFinalState())
return true;
vector<Move *> moves = generateMoves(currentState);
for (int i = 0; i < moves.size(); i++) {
GameState stateAfterMove = moves[i]->perform(currentState);
if (isSolvable(stateAfterMove))
return true;
}
return false;
}
This will play out all possible moves (this is feasible only because it's such a "small" game), and if any sequence of moves leads to a valid solution, the function will return true
.