• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 11:17
CEST 17:17
KST 00:17
  • Home
  • Forum
  • Calendar
  • Streams
  • Liquipedia
  • Features
  • Store
  • EPT
  • TL+
  • StarCraft 2
  • Brood War
  • Smash
  • Heroes
  • Counter-Strike
  • Overwatch
  • Liquibet
  • Fantasy StarCraft
  • TLPD
  • StarCraft 2
  • Brood War
  • Blogs
Forum Sidebar
Events/Features
News
Featured News
Code S Season 1 (2026) - RO4 & Finals Preview1[ASL21] Ro4 Preview: On Course12Code S Season 1 - RO8 Preview7[ASL21] Ro8 Preview Pt2: Progenitors8Code S Season 1 - RO12 Group A: Rogue, Percival, Solar, Zoun13
Community News
Code S Season 1 (2026) - RO8 Results2Weekly Cups (May 4-10): Clem, MaxPax, herO win1Maestros of The Game 2 announcement and schedule !11Weekly Cups (April 27-May 4): Clem takes triple0RSL Revival: Season 5 - Qualifiers and Main Event12
StarCraft 2
General
Code S Season 1 (2026) - RO4 & Finals Preview Code S Season 1 (2026) - RO8 Results Code S Season 1 (2026) - RO12 Results Team Liquid Map Contest #22 - The Finalists MaNa leaves Team Liquid
Tourneys
Sparkling Tuna Cup - Weekly Open Tournament KSL Week 89 2026 GSL Season 2 Qualifiers Maestros of The Game 2 announcement and schedule ! $5,000 WardiTV Spring Championship 2026
Strategy
Custom Maps
[D]RTS in all its shapes and glory <3 [A] Nemrods 1/4 players
External Content
Mutation # 525 Wheel of Misfortune The PondCast: SC2 News & Results Mutation # 524 Death and Taxes Mutation # 523 Firewall
Brood War
General
vespene.gg — BW replays in browser Pros React to: TvT Masterclass in FlaSh vs Light BGH Auto Balance -> http://bghmmr.eu/ BW General Discussion ASL21 General Discussion
Tourneys
[ASL21] Semifinals B Escore Tournament StarCraft Season 2 [Megathread] Daily Proleagues [ASL21] Semifinals A
Strategy
Muta micro map competition Fighting Spirit mining rates [G] Hydra ZvZ: An Introduction Simple Questions, Simple Answers
Other Games
General Games
Path of Exile Stormgate/Frost Giant Megathread Nintendo Switch Thread Warcraft III: The Frozen Throne Starcraft Tabletop Miniature Game
Dota 2
The Story of Wings Gaming
League of Legends
Heroes of the Storm
Simple Questions, Simple Answers Heroes of the Storm 2.0
Hearthstone
Deck construction bug Heroes of StarCraft mini-set
TL Mafia
Vanilla Mini Mafia Mafia Game Mode Feedback/Ideas TL Mafia Community Thread Five o'clock TL Mafia
Community
General
US Politics Mega-thread Russo-Ukrainian War Thread UK Politics Mega-thread YouTube Thread European Politico-economics QA Mega-thread
Fan Clubs
The herO Fan Club!
Media & Entertainment
[Manga] One Piece Anime Discussion Thread [Req][Books] Good Fantasy/SciFi books
Sports
2024 - 2026 Football Thread McBoner: A hockey love story Formula 1 Discussion
World Cup 2022
Tech Support
streaming software Strange computer issues (software) [G] How to Block Livestream Ads
TL Community
The Automated Ban List
Blogs
How EEG Data Can Predict Gam…
TrAiDoS
ramps on octagon
StaticNine
Funny Nicknames
LUCKY_NOOB
Customize Sidebar...

Website Feedback

Closed Threads



Active: 2016 users

FreeCell written in C

Blogs > Zephirdd
Post a Reply
Barbiero
Profile Blog Joined September 2010
Brazil5259 Posts
April 21 2013 01:05 GMT
#1
Hi, I am Zephirdd and I am a Computer Science graduate.

I received an assignment to create the game FreeCell in either C or Pascal. We are not allowed to use any graphical interface other than the console, and we MUST use pointer stacks to organize our cards. These are the conditions of our assignment.

And I had a week to do it.


Now, a little background. I had some experience in programming with C when I was very young, but ever since I got into the university, all I could use was Pascal. And I HATE Pascal.
Furthermore, I haven't programmed in forever. And I had a week to write the whole freaking game. Well fuck, I thought.


Turns out three half-nights were enough. Who'd tell, FreeCell is a fairly simple game!
When I searched the interwebs for this specific project - FreeCell in C - in order to blatantly stealresearch the method, I couldn't find any satisfactory one. I found a guy who spammed every single programming forum asking for it though lol.

So, for the programming enthusiasts, I decided to post this. If you are a beginner, this is a fairly simple project which you can look on. If you are an advanced programmer, well... this is useless for you, but you can get some good laughter.

Because I need to send the source code to my professor, all of the comments are in Portuguese, but I believe the functions are enough

The project was made via Code::Blocks, compiled with the mingw that comes with it. It's a great IDE for beginners IMO.

Without further ado, here you go!

main.c
+ Show Spoiler +
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <math.h>
#include <time.h>
#include "main.h"

/////////////////////////////////
// Cartas são enumeradas de 0 a 51
// 0 = A Copas
// 51 = K Espadas
// 0-12 = copas
// 13-25 = ouros
// 26-38 = paus
// 39-51 = espadas

// (valor+1)/13 = categoria(copas/espadas/ouros/paus); 0=C 1=O 2=P 3=E
// (valor+1)%13 = número(A,2,3,4,5,6,7,8,9,10,J,Q,K)
/////////////////////////////////

// void cardToStr(Item *card, char *c)
// transforma *c na carta
void cardToStr(Item *card, char *c)
{
if(card == NULL)
{
strcpy(c, " ");
return;
}

int category = getCardNipe(card);
int value = getCardNumber(card);
c[0] = ' '; c[1] = ' '; c[2] = ' ';
switch(value)
{
case 0: c[1] = 'A'; break; //A
case 9: c[0] = '1'; c[1] = '0'; break; //10
case 10: c[1] = 'J'; break; //J
case 11: c[1] = 'Q'; break; //Q
case 12: c[1] = 'K'; break; //K
default: c[1] = '1'+value; break; //Isto só é possível pois os casos para números > 9 já foram cobertos acima

}

switch(category)
{
case 0: c[2] = '\3'; break;
case 1: c[2] = '\4'; break;
case 2: c[2] = '\5'; break;
case 3: c[2] = '\6'; break;
default: c[2] = ' '; break;
}
}

void shuffleArray(int *arr, size_t n)
{
if(n>1)
{
size_t i, j;
for(i = 0; i < n-1; i++)
{
j = i + (rand() / (RAND_MAX / (n - i) + 1));
int t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
}

void initializeCards()
{
srand(time(NULL)); //modifica a base do gerador aleatório para não sair a mesma combinação para toda execução
int ar[52];
size_t i;
//Baralho padrão, não embaralhado
for(i=0; i<52; i++)
{
ar[i] = i;
}

shuffleArray(ar, 52); // Embaralhado


for(i=0; i<=3; i++)
{
top_slots[i] = createPile();
base_slots[i] = createPile();
mid_slots[i] = createPile();
mid_slots[i+4] = createPile(); //Não precisa de 2 loops
}

//Colocar as cartas nos mid_slots
for(i=0; i<52; i++){
addNewItemPile(mid_slots[i%8], ar[i]);
}

//Inicializar status do jogo
gameStatus = GAME_STATUS_START;
}

void writeCards()
{
if(!mid_slots[0])
return;

int i;
Item* item;
char *c = malloc(sizeof(char[3]));

for(i=0; i<8; i++)
{
if(mid_slots[i])
{
item = mid_slots[i]->start;
while(item->next != NULL)
{
cardToStr(item, c);
printf("%s ", c);
item = item->next;
}
printf("\n");
}
}
free(c);
}

//int moveCardToPile(Pile* from, Pile* to)
//Move a carta do topo da pilha from para a pilha to
//retorna -1 se nao conseguir, 0 se conseguir
int moveCardToPile(Pile* from, Pile* to)
{
if(from == NULL || to == NULL)
return -1;

Item *prev = removeTopItemPile(from);
if(prev == NULL)
return -1;

return addItemPile(to, prev);
}

int moveCardToBase(Pile *from)
{
if(from == NULL)
return -1;

Item *prev = removeTopItemPile(from);
if(prev == NULL)
return -1;

return addItemPile(base_slots[getCardNipe(prev)], prev);
}


//int getCardNipe
//retorna 0 para copas, 1 para ouros, 2 para paus, 3 para espadas, -1 para erro
int getCardNipe(Item* card)
{
if(card != NULL)
return (int)(card->value / 13);
return -1;
}

//int getCardNumber
//retorna o número da carta, de 0 a 12
//0=A, 1=2, 2=3, etc...
int getCardNumber(Item* card)
{
if(card != NULL)
return (int)(card->value % 13);
return -1;
}

//int canMove(Pile *from, Pile *to)
//retorna 1 se é possível mexer a carta do topo de from para to
//retorna 0 se não
//Toma como base apenas as regras do jogo para as pilhas do meio
//Não leva em consideração as pilhas do topo direito, que têm funcionamento diferente.
int canMove(Pile *from, Pile *to)
{
if(from == NULL || to == NULL)
return 0;

if(from->start == NULL)
return 0;

Item *toMove = from->start;
Item *toReceive = to->start;
if(toReceive == NULL)
return 1; //Sem carta = pode mecher qualquer carta

//verificar se o número é válido
if(getCardNumber(toMove) != getCardNumber(toReceive)-1)
return 0; //só pode mexer uma carta 1 numero menor do que a carta alvo, ex 2 para 3

//verificar se o nipe é válido
//0 não pode combinar com 1, 2 não pode combinar com 3.
//A XOR C, pois se o bit da esquerda é diferente, torna o movimento válido
if((getCardNipe(toMove) ^ getCardNipe(toReceive)) > 1) //>1 significa 10 ou 11 vs 00 ou 01
return 1;

return 0;
}

//int canMoveToBase(Pile *from)
//retorna 1 de a carta pode ser posta em uma pilha base
//retorna 0 se não
int canMoveToBase(Pile *from)
{
if(from == NULL || base_slots[0] == NULL)
return -1;

Item *toMove = from->start;
if(toMove == NULL)
return -1;


//Verifica na pilha do nipe da carta
Item *toReceive = base_slots[getCardNipe(toMove)]->start;
if(toReceive != NULL)
{
if(getCardNumber(toReceive) == getCardNumber(toMove)-1)
return 1;
}
else if(getCardNumber(toMove) == 0)
return 1;

//Verifica se a carta na pilha é antecessora a esta


return 0;
}

// Função main() executa o programa.
int main()
{
initializeCards();
drawBoard();
//writeCards();
return 0;
}

main.h
+ Show Spoiler +


#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED

#include "pilha.h"

//Slot é a casa onde as cartas são postas
//Em FreeCell, você tem 8 slots vazios na primeira linha(sendo 4 "bases") e 8 slots com cartas

Pile *top_slots[4]; //Slots da esquerda de cima, inicialmente vazios
Pile *base_slots[4]; //Slots base, para onde as cartas vão. Talvez não precise utilizar Pile aqui?
Pile *mid_slots[8]; //Slots do meio. No inicio do jogo, têm as cartas distribuídas neles


//Funções de main.c
void cardToStr(Item *card, char *c);
void shuffleArray(int *arr, size_t n);
void initializeCards();
int moveCardToPile(Pile *from, Pile *to);
int moveCardToBase(Pile *from);
int getCardNipe(Item *card);
int getCardNumber(Item *card);
int canMove(Pile *from, Pile *to);
int canMoveToBase(Pile *from);



#define NOMINMAX 1
//Usarei minha própria função max
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })


void drawCard(Item *card);
void drawBoard();
void drawMiddle();
void drawRequestHandle();
void receiveUserInput();
void checkGameStatus();


int gameStatus; //estado do jogo
#define GAME_STATUS_START 0
#define GAME_STATUS_CHOSECARD 1
#define GAME_STATUS_CHOSETARGET 2
#define GAME_STATUS_DEFEAT 3
#define GAME_STATUS_VICTORY 4

Pile *selectedSlot; //pilha selecionada para mover

#endif // MAIN_H_INCLUDED


pilha.c
+ Show Spoiler +
#include "pilha.h"

// Pile* createPile();
// Retorna uma NOVA pilha inicializada
// Retorna NULL caso não consiga criar uma nova pilha
Pile* createPile()
{
Pile* newPile = (Pile*)malloc(sizeof(Pile));
if(newPile == NULL) //se não puder achar memória no sistema
return NULL;

newPile->start = NULL;
newPile->length = 0;
return newPile;
}


// int addItemPile(Pile* pile, int value)
// Cria e adiciona um novo item à pilha, com valor value
// Retorna -1 se não for bem sucedido, 0 se for bem sucedido
int addNewItemPile(Pile* pile, int value)
{
Item* newItem;
if(pile == NULL)
return -1;

newItem = (Item*)malloc(sizeof(Item));
if(newItem == NULL)
return -1;

newItem->value = value;
newItem->next = pile->start;
pile->start = newItem;
pile->length++;
return 0;
}

int addItemPile(Pile* pile, Item* item)
{
if(item == NULL)
return -1;

if(item->next != NULL) //se o next != NULL, ele está em alguma pilha
return -1;

item->next = pile->start;
pile->start = item;
pile->length++;
return 0;
}

// Item* removeTopItemPile(Pile* pile)
// remove o primeiro item da pilha
// retorna NULL se houver algum erro, ou o item removido para uso futuro
// O "next" do item removido vira NULL, pois ele é removido da pilha.
// Nota: o item NÃO É DELETADO DA MEMÓRIA.
Item* removeTopItemPile(Pile* pile)
{
Item* removedItem;
if(pile == NULL || pile->length <= 0)
return NULL;

removedItem = pile->start;
pile->start = removedItem->next;
pile->length--;
removedItem->next = NULL;
return removedItem;
}

// int deleteItem(Item* item)
// deleta e remove o item da memória
// retorna -1 se o next não for NULL, pois siginifica que ainda está em uma pilha
// retorna 0 se for bem sucedido
int deleteItem(Item* item)
{
if(item == NULL || item->next != NULL)
return -1;

free(item);
return 0;
}

// int deletePile(Pile* pile)
// deleta a pilha e remove da memória
// remove e deleta qualquer item que esteja na pilha
// retorna -1 se a pilha não existir
int deletePile(Pile* pile)
{
Item* item;
if(pile == NULL)
return -1;

while(pile->length > 0)
{
item = removeTopItemPile(pile); //reduz o valor da pilha automaticamente
if(item != NULL)
deleteItem(item);
}

free(pile);
return 0;
}

//Item* getPreviousItemOnPile(Item *item, Pile *pile)
// retorna o item anterior ao item requerido na pilha
// retorna o próprio item se ele for o topo da pilha
// retorna NULL se não for possível, ou se o item não estiver na pilha
Item* getPreviousItemOnPile(Item *item, Pile *pile)
{
if(item == NULL || pile == NULL)
return NULL;

Item* Q = pile->start;
if(Q == NULL) return NULL;
if(Q == item) return item;

while(Q->next != NULL)
{
if(Q->next == item) return Q;

Q = Q->next;
}

return NULL;
}


pilha.h
+ Show Spoiler +
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//////////////////////////Funcoes de Pilha(stack)//////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////


#ifndef PILHA_H_INCLUDED
#define PILHA_H_INCLUDED

#include <stdlib.h>

// Definir Pilha(Pile) e suas funções para o uso no jogo
// Usar nomes genéricos para usos futuros

typedef struct ItemList
{
int value; //No futuro, achar um método de transformar este tipo em algo mais dinâmico
struct ItemList *next;
}Item;

typedef struct PileStructure
{
Item *start;
int length; // length ao inves de size, pois size ja é definido para outras coisas
}Pile;


// Pile* createPile();
// Retorna uma NOVA pilha inicializada
// Retorna NULL caso não consiga criar uma nova pilha
Pile* createPile();


// int addItemPile(Pile* pile, int value)
// Cria e adiciona um novo item à pilha, com valor value
// Retorna -1 se não for bem sucedido, 0 se for bem sucedido
int addNewItemPile(Pile* pile, int value);
int addItemPile(Pile* pile, Item* item);

// Item* removeTopItemPile(Pile* pile)
// remove o primeiro item da pilha
// retorna NULL se houver algum erro, ou o item removido para uso futuro
// O "next" do item removido vira NULL, pois ele é removido da pilha.
// Nota: o item NÃO É DELETADO DA MEMÓRIA.
Item* removeTopItemPile(Pile* pile);

// int deleteItem(Item* item)
// deleta e remove o item da memória
// retorna -1 se o next não for NULL, pois siginifica que ainda está em uma pilha
// retorna 0 se for bem sucedido
int deleteItem(Item* item);

// int deletePile(Pile* pile)
// deleta a pilha e remove da memória
// remove e deleta qualquer item que esteja na pilha
// retorna -1 se a pilha não existir
int deletePile(Pile* pile);

//Item* getPreviousItemOnPile(Item *item, Pile *pile)
// retorna o item anterior ao item requerido na pilha
// retorna o próprio item se ele for o topo da pilha
// retorna NULL se não for possível, ou se o item não estiver na pilha
Item* getPreviousItemOnPile(Item *item, Pile *pile);

#endif // PILHA_H_INCLUDED

ui.c
+ Show Spoiler +
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include "main.h"
#include "pilha.h"

void drawCard(Item *card)
{
if(card != NULL)
{
char *c = malloc(sizeof(char[3]));
cardToStr(card, c);
printf("{%s} ", c);
free(c);
}
else
printf("{ } ");
}


void drawBoard()
{
system("cls");
int i;

if(top_slots[0] == NULL)
return;
/*

#1 #2 #3 #4 C O P E
{ } { } { } { } | { } { } { } { }
-------------------------------------------------
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
{ } { } { } { } { } { } { } { }
a b c d e f g h

In which column is the card you want to take? _

(depois de selecionar a carta)
To where you want to send this card?
Valid options: 1,2,3,4,a,b,c,d,e,f,g,h,BASE
Enter with the target: _


// NOTA: opções possíveis também são o, out, base, nipe


*/

printf(" #1 #2 #3 #4 \3 \4 \5 \6 \n");
for(i=0;i<4;i++)
drawCard(top_slots[i]->start);

printf("| ");

for(i=0;i<4;i++)
drawCard(base_slots[i]->start);
//base e topo escritas

printf("\n");
printf("------------------------------------------------- \n");

//escrever o meio
drawMiddle();

printf("\n\n");
//Perguntas
drawRequestHandle();

//Solicitar o usuário a executar um comando
if(gameStatus != GAME_STATUS_DEFEAT && gameStatus != GAME_STATUS_VICTORY)
receiveUserInput();
}



void drawMiddle()
{
//Função separada para organizar
//Para o jogo, é mais fácil manter pilhas de baixo para cima(pelo display)
//Porém para escrever, é mais fácil utilizar pilhas de cima para baixo

//Então vou criar novas pilhas temporárias que são cópias das globais
//E utilizar estas para imprimir
if(mid_slots[0] == NULL)
return;

Pile *tempPile[8];
Item *tempItem;
Item *tmpVector[8];
int i, j, max_length;
max_length = -1; //Inicialização necessária para garantir o uso

for(i=0;i<8;i++)
{
//Terei de criar NOVAS cartas, pois as originais precisam manter seus atributos
//Lembrar de deletar tudo ao fim da função
tempPile[i] = createPile();
tempItem = mid_slots[i]->start;
while(tempItem != NULL)
{
addNewItemPile(tempPile[i], tempItem->value);
tempItem = tempItem->next;
}

max_length = max(max_length, tempPile[i]->length); //será usado mais tarde

}

//Desenhar
for(i = 0; i < max_length; i++)
{
for(j = 0; j < 8; j++)
{
if(i == 0)
tmpVector[j] = tempPile[j]->start;
else if(tmpVector[j] != NULL){
tmpVector[j] = tmpVector[j]->next;
}

drawCard(tmpVector[j]);
if(j == 3)
printf(" "); //Alinhar as cartas
}
printf("\n");
}


printf(" a b c d e f g h \n");

//deletar pilas temporárias
for(i= 0; i < 8; i++)
deletePile(tempPile[i]);
//funçoes em pile.h já lidam com os items criados
}

void drawRequestHandle()
{
//Função para escrever as perguntas
switch(gameStatus)
{
case GAME_STATUS_START:
printf("Welcome to FreeCell! Above you will see your cards!\n");
case GAME_STATUS_CHOSECARD:
printf("Please chose which card you want to move!\n");
printf("Valid options: a, b, c, d, e, f, g, h, 1, 2, 3, 4\n");
break;
case GAME_STATUS_CHOSETARGET:
printf("Please chose to where you want to move ");
drawCard(selectedSlot->start);
printf("\nValid options: a, b, c, d, e, f, g, h, 1, 2, 3, 4, base\n");
break;
case GAME_STATUS_DEFEAT:
printf("No more possible moves. Game over!");
break;
case GAME_STATUS_VICTORY:
printf("Congratulations, you won!");
break;
}
}

void receiveUserInput()
{
char *c = malloc(sizeof(char[5]));
int i;
scanf("%5s", c);
//verificar estado do jogo
if(gameStatus == GAME_STATUS_START || gameStatus == GAME_STATUS_CHOSECARD)
{
//if(c[0] == 'a') i = 0;
//if
if(c[0] >= 'a' && c[0] <= 'h')
{
i = (int)(c[0] - 'a'); //a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7
selectedSlot = mid_slots[i];
}
else if(c[0] >= '1' && c[0] <= '4')
{
i = (int)(c[0] - '1');
selectedSlot = top_slots[i];
}
else{
printf("Invalid selection! \nValid options are a,b,c,d,e,f,g,h,1,2,3,4!\n");
free(c);
receiveUserInput();
return;
}


if(selectedSlot->start == NULL)
{
printf("This pile has no cards! Please select another slot.\n");
free(c);
receiveUserInput();
return;
}

gameStatus = GAME_STATUS_CHOSETARGET;
}
else if(gameStatus == GAME_STATUS_CHOSETARGET)
{
Pile *targetSlot;
if(strcasecmp(c, "base") == 0)
{
strcpy(c, " ");
free(c);
if(canMoveToBase(selectedSlot) == 1)
{
moveCardToBase(selectedSlot);
checkGameStatus();
selectedSlot = NULL;
drawBoard();
return;
}
else
{
selectedSlot = NULL;
printf("Invalid move! Please select another card.\n");
gameStatus = GAME_STATUS_CHOSECARD;
receiveUserInput();
return;
}

}
else if(c[0] >= 'a' && c[0] <= 'h')
{
i = (int)(c[0] - 'a'); //a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7
targetSlot = mid_slots[i];
}
else if(c[0] >= '1' && c[0] <= '4')
{
i = (int)(c[0] - '1');
targetSlot = top_slots[i];
//top_slots may only receive one card at a time
if(targetSlot->length > 0)
{
printf("Invalid move! Please select another card to move.\n");
free(c);
selectedSlot = NULL;
gameStatus = GAME_STATUS_CHOSECARD;
receiveUserInput();
return;
}
}
else{
printf("Invalid selection! \nValid options are a,b,c,d,e,f,g,h,1,2,3,4,base!");
free(c);
receiveUserInput();
return;
}

if(canMove(selectedSlot, targetSlot) == 1)
{
moveCardToPile(selectedSlot, targetSlot);
checkGameStatus();
}
else{
printf("Invalid move! Please select another card to move.\n");
free(c);
selectedSlot = NULL;
gameStatus = GAME_STATUS_CHOSECARD;
receiveUserInput();
return;
}
}

free(c);
drawBoard();
}

void checkGameStatus()
{
//Ler os slots e verificar se o jogo acabou, e determinar o status do jogo

//se o length dos top_slots for 13, eles estão cheios e o jogo acabou em vitória
if(top_slots[0]->length == 13 && top_slots[1]->length == 13 && top_slots[2]->length == 13 && top_slots[4]->length == 13){
gameStatus = GAME_STATUS_VICTORY;
return;
}

//Se nenhum movimento for possível, o jogo resulta em derrota
Pile *a, *b;
int j;
int isDefeat = 1; //Assume que é derrota inicialmente; se achar um movimento válido, vira vitória

a = mid_slots[0];
for(j=0; j<8; j++)
{
b = mid_slots[j];
if(canMove(a, b) == 1 || canMove(b, a) == 1){
isDefeat = 0;
break; //Já foi determinado que não é derrota
}
if(j<4)
{
b = top_slots[j];
if(top_slots[j]->length == 0)
{
isDefeat = 0;
break;
}
}
}

if(isDefeat == 1)
gameStatus = GAME_STATUS_DEFEAT;
else
gameStatus = GAME_STATUS_CHOSECARD;

}



This was the very first full project I've done by myself. I feel proud :3

One thing I wanted to make was an actual cursor to select the cards and move them, but I figured it would be far too much work for something like this. From what I've researched, cursors are actually really complicated o-o'

Also you may notice that I never created an "exit" function and deleted the piles and items created in this. Ctrl+C seems to do the work fine, and I'm lazy lol.

I could upload the built .exe file, but it would look shady. So you can compile the above code instead :D

Thanks for reading~

*****
♥ The world needs more hearts! ♥
Birdie
Profile Blog Joined August 2007
New Zealand4438 Posts
April 21 2013 03:34 GMT
#2
Congratz, I'm a year 1 computer science student so I'll check out the code later this week if I remember and see what I can learn. I've been lazy and haven't learned pointers yet so maybe I'll use this as an example of how they can be used
Red classic | A butterfly dreamed he was Zhuangzi | 4.5k, heading to 5k as support!
docvoc
Profile Blog Joined July 2011
United States5491 Posts
April 21 2013 03:44 GMT
#3
I don't get this at all, but it looks very impressive O.o, this is awesome dude, how do I run this code?
User was warned for too many mimes.
rabidch
Profile Joined January 2010
United States20289 Posts
April 21 2013 03:54 GMT
#4
On April 21 2013 12:44 docvoc wrote:
I don't get this at all, but it looks very impressive O.o, this is awesome dude, how do I run this code?

compile the program with a C compiler and then run it
LiquidDota StaffOnly a true king can play the King.
IMlemon
Profile Blog Joined May 2008
Lithuania296 Posts
April 21 2013 10:25 GMT
#5
Please dont ever write source code in a non-english language if you want someone to understand it.
My future's so bright, I gotta wear shades.
LML
Profile Blog Joined March 2007
Germany1791 Posts
Last Edited: 2013-04-21 14:42:28
April 21 2013 14:41 GMT
#6
what's the problem with english comments just because you study in a non-english speaking country?
I use english comments in my programs for university, most professors even post their stuff with english comments, it's really not that uncommon

on a different note, why did you keep all the functions in the main.c instead of like a functions.h?
Wouldn't that be way cleaner to look at, when looking at the main?
LML
Barbiero
Profile Blog Joined September 2010
Brazil5259 Posts
April 21 2013 17:19 GMT
#7
On April 21 2013 23:41 LML wrote:
what's the problem with english comments just because you study in a non-english speaking country?
I use english comments in my programs for university, most professors even post their stuff with english comments, it's really not that uncommon

on a different note, why did you keep all the functions in the main.c instead of like a functions.h?
Wouldn't that be way cleaner to look at, when looking at the main?


My professor reads the code, and he doesnt like english

If you mean the main.h having all the functions, I dont really see an issue as its only a naming thing. But yeah, for consistency renaming it to functions.h would be better I guess

If you mean main.c, I decided to keep game rules and game interpreting functions on main.c and user related dunctions(draw/read) on ui.c . Leaving main.c empty just with the main function would look silly lol
♥ The world needs more hearts! ♥
Riccardo
Profile Joined May 2020
Italy1 Post
May 19 2020 10:48 GMT
#8
Hi, I have received an assignment similar to yours at my university. I tried to use your code initially to understand how it worked but unfortunately after building and starting it, the output is this in image.

Could you help me understand?
Thank you very much.

[image loading]
catplanetcatplanet
Profile Blog Joined March 2012
3836 Posts
Last Edited: 2020-05-20 03:22:53
May 20 2020 03:22 GMT
#9
Hi Riccardo. I'm afraid the guy you necro'd hasn't been active here for more than 4 years. Speaking from experience, copying an entire codebase you find online and then asking why it doesn't run out of the box (without even googling your error to see if there's a very simple solution) doesn't tend to be the most productive approach. Try solving the assignment on your own, see what you get hung up on, and consult with your peers and professors. That's how learning at university works!
I think it's finally time to admit it might not be the year of Pet
Urth
Profile Blog Joined November 2007
United States1256 Posts
May 29 2020 16:14 GMT
#10
Lol nice necro
BY.HERO FIGHTING!!!!
decembre
Profile Joined January 2024
1 Post
January 11 2024 15:21 GMT
#11
hi I read your code and I want tothank you but I have a problem that I didn't understand it
jacksmith1221
Profile Joined January 2024
1 Post
January 12 2024 10:19 GMT
#12
QuickBooks Error H505 is a common issue that occurs when a user tries to access a company file that is located on another computer, and QuickBooks cannot establish a connection with the server. This error is part of the H series errors in QuickBooks, which are related to hosting issues.
Here is a step-by-step solution to fix QuickBooks Error H505:
Step 1: Check Hosting Settings
Open QuickBooks on all computers.
Go to the 'File' menu and select 'Utilities.'
Verify that the host computer is set as the host in multi-user mode.
If not, choose 'Host Multi-User Access.'
Step 2: Update QuickBooks
Ensure you are using the latest version of QuickBooks.
Go to the 'Help' menu and select 'Update QuickBooks Desktop.'
Choose the 'Update Now' tab and click 'Get Updates.'
Restart QuickBooks after the update is complete.
Please log in or register to reply.
Live Events Refresh
WardiTV Qualifier
13:00
Spring Champs Qualifier
WardiTV750
LiquipediaDiscussion
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
Serral 2352
ProTech160
BRAT_OK 3
StarCraft: Brood War
Britney 41968
Mini 807
BeSt 373
hero 189
firebathero 186
Mind 130
Zeus 98
Last 96
Pusan 59
ToSsGirL 33
[ Show more ]
Aegong 28
Rock 22
Sacsri 22
Hm[arnc] 22
Shine 20
yabsab 19
soO 16
Terrorterran 14
Nal_rA 11
Dota 2
Gorgc7235
qojqva1293
monkeys_forever90
Counter-Strike
pashabiceps1424
Heroes of the Storm
Trikslyr57
Other Games
Grubby17177
singsing2334
Beastyqt890
B2W.Neo665
Liquid`RaSZi454
Lowko324
Sick213
KnowMe106
ArmadaUGS76
FrodaN50
Organizations
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
[ Show 16 non-featured ]
StarCraft 2
• Adnapsc2 33
• Dystopia_ 1
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• LaughNgamezSOOP
• Migwel
• sooper7s
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• WagamamaTV247
League of Legends
• Nemesis2347
• Jankos2035
Other Games
• Shiphtur78
Upcoming Events
IPSL
43m
Dewalt vs nOmaD
Ret vs Cross
BSL
43m
Artosis vs Sterling
eOnzErG vs TBD
BSL
3h 43m
Bonyth vs Doodle
Dewalt vs TerrOr
Patches Events
7h 28m
GSL
16h 43m
Cure vs herO
SHIN vs Maru
IPSL
1d
Bonyth vs Napoleon
G5 vs JDConan
BSL
1d 3h
OyAji vs JDConan
DragOn vs TBD
Replay Cast
1d 17h
Monday Night Weeklies
2 days
Replay Cast
2 days
[ Show More ]
The PondCast
2 days
Kung Fu Cup
2 days
GSL
3 days
Replay Cast
4 days
GSL
4 days
WardiTV Spring Champion…
4 days
Replay Cast
5 days
Sparkling Tuna Cup
5 days
WardiTV Spring Champion…
5 days
Replay Cast
6 days
RSL Revival
6 days
Classic vs SHIN
Rogue vs Bunny
Liquipedia Results

Completed

Escore Tournament S2: W7
WardiTV TLMC #16
Nations Cup 2026

Ongoing

BSL Season 22
ASL Season 21
IPSL Spring 2026
KCM Race Survival 2026 Season 2
Acropolis #4
KK 2v2 League Season 1
BSL 22 Non-Korean Championship
SCTL 2026 Spring
RSL Revival: Season 5
2026 GSL S1
Heroes Pulsing #1
Asian Champions League 2026
IEM Atlanta 2026
PGL Astana 2026
BLAST Rivals Spring 2026
IEM Rio 2026
PGL Bucharest 2026
Stake Ranked Episode 1
BLAST Open Spring 2026
ESL Pro League S23 Finals
ESL Pro League S23 Stage 1&2

Upcoming

YSL S3
Escore Tournament S2: W8
CSLAN 4
Kung Fu Cup 2026 Grand Finals
HSC XXIX
uThermal 2v2 2026 Main Event
Maestros of the Game 2
WardiTV Spring 2026
2026 GSL S2
BLAST Bounty Summer Qual
Stake Ranked Episode 3
XSE Pro League 2026
IEM Cologne Major 2026
Stake Ranked Episode 2
CS Asia Championships 2026
TLPD

1. ByuN
2. TY
3. Dark
4. Solar
5. Stats
6. Nerchio
7. sOs
8. soO
9. INnoVation
10. Elazer
1. Rain
2. Flash
3. EffOrt
4. Last
5. Bisu
6. Soulkey
7. Mini
8. Sharp
Sidebar Settings...

Advertising | Privacy Policy | Terms Of Use | Contact Us

Original banner artwork: Jim Warren
The contents of this webpage are copyright © 2026 TLnet. All Rights Reserved.