• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 10:36
CEST 16:36
KST 23:36
  • 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
[ASL22] Ro8 Preview: Within Reach5[ASL22] Ro8 Preview: In A Tizzy11[ASL22] Ro16 Preview: Holy Diver5[ASL22] Ro16 Preview: Rough Waters10[ASL22] Ro24 Preview: Siren's Call8
Community News
SC4ALL: II SC2 Complete Invited Player Lineup4StarCraft II 5.0.17 PTR Patch Notes (Sept 30, 2026)66Weekly Cups (Sept 21-27): herO and ByuN double2Weekly Cups (Sep 13-20): herO scores triple3BSL Season 2315
StarCraft 2
General
SC4ALL: II SC2 Complete Invited Player Lineup StarCraft II 5.0.17 PTR Patch Notes (Sept 30, 2026) How do you feel about the mass reverts in the 5.0.17 PTR? Awesome/Confusing SC2 BM [Old] StarCraft 3 Reportedly in Development
Tourneys
Stellar Fest TWO the Moon (Dec 16-20) Sparkling Tuna Cup - Weekly Open Tournament 2026 GSTL Grand Finals Sea Duckling Open (Global, Bronze-Diamond) SC2 INu's Battles#21 [ 3-Days tournament ]
Strategy
[H] ZvP Mid-Late Game: Stalkers Collossi HT
Custom Maps
[M] (2) Sweltering Sands [M] (2) Frigid Storage
External Content
The PondCast: SC2 News & Results Mutation # 545 And Drops and Rifts Mutation # 544 Double Trouble Mutation # 543 Enhanced Defenses
Brood War
General
BSL Season 23 Klaucher discontinued / in-game color settings BW General Discussion Bot on ladder ASL22 General Discussion
Tourneys
[ASL22] Ro8 Day 4 [Megathread] Daily Proleagues [ASL22] Ro8 Day 3 [ASL22] Ro8 Day 2
Strategy
Cliff Jump Revisited (1 in a 1000 strategy) Replay Review Process - What do you do? Simple Questions, Simple Answers Odyssey Mineral Stack Saturation
Other Games
General Games
Nintendo Switch Thread General RTS Discussion Thread Warcraft III: The Frozen Throne Stormgate/Frost Giant Megathread Total Annihilation Zero
Dota 2
Dota 2 Champions League Season 3 Begins April 25! Official 'what is Dota anymore' discussion
League of Legends
[TL LoL EUW IHs] Teemo shall perish
Heroes of the Storm
Heroes of the Storm 2.0
Hearthstone
Deck construction bug
TL Mafia
TL Mafia Community Thread
Community
General
Things Aren’t Peaceful in Palestine US Politics Mega-thread Russo-Ukrainian War Thread Canadian Politics Mega-thread Artificial Intelligence Thread
Fan Clubs
Serral Fan Club
Media & Entertainment
Movie Discussion! [Manga] One Piece Diablo Animated Series on Netflix
Sports
Football (Soccer) Thread MLB/Baseball 2023
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread
TL Community
Recent Gifted Posts
Blogs
[ASL22] Ro4 Day1 Ticket Giv…
bITt.mAN
Escaping Into Video Games: G…
TrAiDoS
38 yo Retired SWE loo…
PurE)Rabbit-SF
Can Bots Beat Pros?? Starcr…
namkraft
[meme] I finally understa…
LUCKY_NOOB
Regacy Esports:Our Goa…
regacyesports
Customize Sidebar...

Website Feedback

Closed Threads



Active: 8112 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
Germany1794 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
3837 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
Online Event
20:00
BamsPatch 1.0 Weekly #3
Liquipedia
CranKy Ducklings
19:00
Sea Duckling Open #150 (SHIN Mod Edition)
LiquipediaDiscussion
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
mouzHeroMarine 389
ProTech143
StarCraft: Brood War
Britney 33413
Bisu 2990
Shuttle 1721
Hyuk 1321
EffOrt 695
Mini 683
Larva 347
Soma 286
ZerO 257
firebathero 241
[ Show more ]
hero 92
Zeus 91
Last 85
Sexy 80
Mong 42
Hyun 42
Killer 39
Pusan 35
Trap 34
Bale 33
ToSsGirL 33
Hm[arnc] 31
Aegong 27
PianO 27
sorry 24
zelot 16
Rock 14
Noble 9
ajuk12(nOOB) 8
Sacsri 8
JulyZerg 8
Icarus 7
Terrorterran 1
Dota 2
Gorgc7346
qojqva1440
Dendi835
Counter-Strike
fl0m2053
Heroes of the Storm
Khaldor1355
crisheroes937
Liquid`Hasu575
Lowko401
Other Games
singsing2636
B2W.Neo1314
Beastyqt393
Livibee204
Hui .189
Liquid`VortiX161
ArmadaUGS90
KnowMe90
Mew2King88
elazer64
CosmosSc2 24
ZerO(Twitch)8
Organizations
Dota 2
PGL Dota 2 - Main Stream68
[ Show 14 non-featured ]
StarCraft 2
• StrangeGG 37
• Adnapsc2 2
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• Migwel
StarCraft: Brood War
• Michael_bg 15
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• C_a_k_e 9058
• WagamamaTV181
League of Legends
• Jankos1924
Upcoming Events
FEL
1h 24m
AI Arena Tournament
2h 24m
BSL: Ladder Tournament
4h 24m
Sparkling Tuna Cup
19h 24m
INu's Battles
21h 24m
herO vs Classic
Percival vs Rogue
BSL Open Qualifier
1d 4h
BSL Open Qualifier
1d 4h
Replay Cast
1d 9h
Afreeca Starleague
1d 19h
Rush vs Light
WardiTV Weekly
1d 20h
[ Show More ]
Monday Night Weeklies
2 days
Afreeca Starleague
2 days
Soma vs Soulkey
INu's Battles
2 days
SHIN vs Cure
ByuN vs Zoun
PiGosaur Cup
3 days
The PondCast
4 days
INu's Battles
4 days
Liquipedia Results

Completed

Proleague 2026-10-02
Blizzard Classic Cup 2026
Calamity Invitational

Ongoing

ASL Season 22
Super Anchor Qualifying S3
CSL 2026 AUTUMN (S22)
Acropolis #5
Acropolis #5 - GSB
Copium Cup
ESL Pro League Season 24
Stake Ranked Episode 4
1win Private Club #1
Logitech G Play Connect 2026
SL StarSeries Fall 2026
FISSURE Playground #3
BLAST Open Fall 2026
Esports World Cup 2026
BLAST Bounty Summer 2026
BLAST Bounty Summer Qual

Upcoming

Acropolis #5 - GSC
BSL Season 23
SC4ALL II: Brood War
BSL 23: Non-Korean Championship
HSC XXX
Stellar Fest 2: Lunar Cup
SC4ALL II: StarCraft II
Kung Fu Cup 2026 Grand Finals
RSL Offline Finals
Custodian Cup
eXTREMESLAND 2026
PGL Major Singapore 2026
Stake Ranked Episode 6
BLAST Rivals Fall 2026
IEM Beijing 2026
Stake Ranked Episode 5
PGL Masters Bucharest 2026
1win Private Club #2
Thunderpick World Champ. '26
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.