Skip to content

Instantly share code, notes, and snippets.

@stravant
Created November 27, 2012 17:47
Show Gist options
  • Save stravant/4155826 to your computer and use it in GitHub Desktop.
Save stravant/4155826 to your computer and use it in GitHub Desktop.
Arduino Solitaire Logic
struct Card {
CardColor Color;
CardSuit Suit;
CardValue Value;
//
bool FaceUp;
//
Card* Next;
Card* Prev;
//
CardLocation Location; // Deck | Stack |
//
static Card* getCard(CardValue, CardSuit);
};
struct BoardState {
Card* Stacks[4];
Card* Board[7];
//
Card* TopOfDeck;
Card* DeckCurrentPos;
//
Card* Disc;
} state;
//description of a move to do
struct SubMove {
Card* From;
Card* To;
};
struct MoveDescription {
Card* From;
Card* To;
size_t SubmoveCount;
SubMove* SubmoveList;
};
void hint_get_tomove(Card* dest[7], int* count) {
int put_inx = 0;
for (int i = 0; i < 7; ++i) {
Card* c = state.Board[i];
while (c->Next && c->Next.FaceUp && c->Next.Value != 0)
c = c->Next;
if (c->Value != 0)
dest[put_inx++] = c;
}
*count = put_inx;
}
void hint_get_dest(Card* source[11], int* count) {
int put_inx = 0;
//places to put down a card on the board
for (int i = 0; i < 7; ++i) {
dest[put_inx++] = state.Board[i];
}
//places to put down a card on the stacks
for (int i = 0; i < 7; ++i) {
dest[put_inx++] = state.Stacks[i];
}
*count = put_inx;
}
//check if a given card is `available`, that is, if it is face up
//on the board, or in the stack.
Card* hint_isavailable(CardValue, CardColor) {
}
Card* hint_isavailable(CardValue, CardSuit) {
}
//can we "pull" a card from the deck onto some spot on the field
//(in order to make a get a card in the deck that we want into a
//position where we can take it.)
Card* can_pull_from_deck(Card*) {
}
//red => black, black => red
CardColor hint_otherColor(CardColor) {
}
void hint(Card** move_from, Card** move_to, bool do_move) {
//get cards to move and places to move them to
Card* toMove[7];
int toMoveN;
hint_get_moves(toMove, &toMoveN);
//
Card* dest[11];
int destN;
hint_get_dest(dest, &destN);
//
struct HintRecord {
Card* From;
Card* To;
int Difficulty;
bool Possible;
};
int hintRecordComparator(const HintRecord* a, const HintRecord* b) {
if (a->Possible && !b->Possible) {
return 1;
} else if (!a->Possible && b->Possible) {
return -1;
} else if (a->Possible && b->Possible) {
return b->Difficulty - a->Difficulty;
}
}
HintRecord moveArray[toMoveN];
moveArrayN = 0;
//
for (int i = 0; i < toMoveN; ++i) {
Card* cardToMove = toMove[i];
//stats on the best move to do
Card* whereToMove = 0;
int moveDifficulty = 100; //large value to start
bool requiresUnrevealed = true;
//
for (int j = 0; j < destN; ++j) {
Card* cardDest = dest[j];
//
int difficulty = 100; //intial difficulty, larger
bool reqUnrevealed = false;
//
if (cardDest.Location == LocationStack) {
//on the stacks, we need to be the same color and +n
if (cardToMove->Suit == cardDest->Suit || cardDest->Value == 0) {
difficulty = cardToMove->Value - cardDest->Value - 1
//Search to see if the between cards are available
for (int value = cardDest->Value+1; value < cardToMove->Value; ++value) {
if (!hint_isavailable(i, cardDest->Suit))
reqUnrevealed = true;
}
}
} else if (cardDest.Location == LocationBoard) {
//on the board, we need to have alternating colors per stack, which
//is a bit more complicated logic
int cardsBetween = cardToMove->Value - cardDest->Value - 1
if (cardsBetween >= 0) {
if (cardDest->Value > 0) {
//normal placement on a stack
if ((cardsBetween%2 == 1) == (cardToMove->Color == cardDest->Color)) {
difficulty = cardsBetween;
//Search to see if the between cards are available
CardColor oddColor = hint_otherColor(cardToMove->Color);
CardColor evenColor = cardToMove->Color;
for (int ofs = 1; ofs <= cardsBetween; ++ofs) {
if (!hint_isavailable(cardToMove->Value+ofs, (i%2==0)?evenColor:oddColor))
reqUnrevealed = true;
}
}
} else {
//placement of a king in an empty stack
if (cardToMove->Value == 13) {
//king, can move
difficulty = 0;
reqUnrevealed = false;
}
}
}
} else {
assert(false && "Unreachable");
}
//update the best move if we are "better" than it with this move
if (difficulty < moveDifficulty && (!reqUnrevealed || requiresUnrevealed)) {
moveDifficulty = difficulty;
requiresUnrevealed = reqUnrevealed;
whereToMove = cardDest;
}
}
//update the hintRecord if we found a way to move this item
if (whereToMove) {
HintRecord& rec = moveArray[moveArrayN++];
rec.From = cardToMove;
rec.To = whereToMove;
rec.Difficulty = moveDifficulty;
rec.Possible = !requiresUnrevealed;
}
}
//now sort the hintrecords by difficulty
qsort(moveArray, moveArrayN, sizeof(HintRecord), hintRecordComparator);
//sorted, see if we have a 0 difficulty item
if (moveArray[0].Difficulty == 0) {
//with a 0 difficult move we can just do it
*move_from = moveArray[0].From;
*move_to = moveArray[0].To;
return;
} else {
//otherwise, we need a more complex logic to test the constraints of the move.
//we can't just pull any old card out of the deck, so we may need to
//for each move, test if each of the constraints can be met
for (int i = 0; i < moveArrayN; ++i) {
HintRecord& rec = moveArrayN[i];
//now, find the constraints, exactly which cards we need
if (rec.To->Location == LocationStack) {
//stack, constraints are on-suit
} else if (rec.To->Location == LocationBoard) {
//board, constraints are alternating color
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment