• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 02:18
CEST 08:18
KST 15:18
  • 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
Serral wins HomeStory Cup 2915Serral wins Maestros of the Game 243ByuL, and the Limitations of Standard Play3Team Liquid Map Contest #22: Results and Winners7Code S Season 2 (2026): RO4 and Finals Preview12
Community News
GSTL Returns in 2026!38Weekly Cups (Aug 3-9): Protoss get shut out7RSL goes to London! 2026 Offline Finals Nov 21-2212Weekly Cups (July 27-Aug 2): SHIN's big week0SC4ALL II: Brood War - $2500 - Dec 5-611
StarCraft 2
General
GSTL Returns in 2026! Balance hotfix patch 5.0.16b (July 16) SC4ALL: II Talent Announcement! Protoss AoE skill expression Weekly Cups (Aug 3-9): Protoss get shut out
Tourneys
PIG STY FESTIVAL 8.0! (13 - 23 August) Sparkling Tuna Cup - Weekly Open Tournament 2026 GSTL Announcement Sea Duckling Open (Global, Bronze-Diamond) 2026 KungFu Cup Announcement
Strategy
[G] Having the right mentality to improve
Custom Maps
Nexus Wars 2021 GUIDE [M] (2) Industrial Park
External Content
Mutation # 538 Media Blackout The PondCast: SC2 News & Results Mutation # 537 Hostile Territory Mutation # 536 Railroad Switch
Brood War
General
Best Games Kespa era BCA KCU TANGERANG Telp:08218200233 Your past clans BW General Discussion ASL22 General Discussion
Tourneys
CSLAN 4 is Coming! Small VOD Thread 2.0 Escore Tournament - Season 3 BSL LAN Party - Kraków 29-30 August - OPEN SIGNUPS
Strategy
Odyssey Mineral Stack Saturation Fighting Spirit mining rates Any training maps people recommend? Simple Questions, Simple Answers
Other Games
General Games
Nintendo Switch Thread Anyone here play Quakeworld back in the day? Stormgate/Frost Giant Megathread EVE Corporation General RTS Discussion Thread
Dota 2
Official 'what is Dota anymore' discussion
League of Legends
[TL LoL EUW IHs] Teemo shall perish TSM pausing esports and CLG Dead
Heroes of the Storm
Heroes of the Storm 2.0
Hearthstone
Deck construction bug
TL Mafia
TL Mafia Power Rank TL Mafia Community Thread NeO.D_StephenKing vs This Guy From 1 Million Dance
Community
General
Russo-Ukrainian War Thread US Politics Mega-thread European Politico-economics QA Mega-thread Artificial Intelligence Thread The Letting Off Steam Thread
Fan Clubs
MarineLorD Fan Club The ShoWTimE Fan Club The herO Fan Club!
Media & Entertainment
Movie Discussion! Anime Discussion Thread Series you have seen recently... [Req][Books] Good Fantasy/SciFi books
Sports
MLB/Baseball 2023 Football (Soccer) Thread TeamLiquid Health and Fitness Initiative For 2023 NBA General Discussion Formula 1 Discussion
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread Simple Questions Simple Answers FPS when play League Of Legend on laptop
TL Community
The Automated Ban List Northern Ireland Global Starcraft
Blogs
LOCKPICKING NOOB
LUCKY_NOOB
Chinese Gen Z: Between Dream…
TrAiDoS
Cathedral Of CS And NY pizza a…
FuDDx
Please support my new stand…
Peanutsc
Hello guys!
LIN1s
Customize Sidebar...

Website Feedback

Closed Threads



Active: 8094 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
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
IPSL
16:00
CSLAN Day 1
Liquipedia
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
Nina 145
StarCraft: Brood War
Pusan 182
Bale 42
Dota 2
The International58444
singsing2592
Fuzer 314
NeuroSwarm153
League of Legends
JimRising 639
Counter-Strike
summit1g8717
Other Games
WinterStarcraft555
m0e_tv534
Organizations
Other Games
BasetradeTV270
[ Show 13 non-featured ]
StarCraft 2
• practicex 36
• intothetv
• AfreecaTV YouTube
• Kozan
• IndyKCrew
• Migwel
StarCraft: Brood War
• Azhi_Dahaki48
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• C_a_k_e 2258
• lizZardDota265
League of Legends
• Rush1650
Upcoming Events
Sparkling Tuna Cup
3h 43m
PiG Sty Festival
5h 43m
Maru vs Shameless
Reynor vs TriGGeR
IPSL
9h 43m
OSC
17h 43m
Afreeca Starleague
1d 3h
Rush vs Hm
Bisu vs Shuttle
WardiTV Weekly
1d 4h
The Patches Monday
1d 9h
Afreeca Starleague
2 days
Sharp vs Shinee
Action vs Shine
PiGosaur Cup
2 days
Replay Cast
3 days
[ Show More ]
Afreeca Starleague
3 days
BeSt vs Paralyze
Jaedong vs Speed
Kung Fu Cup
3 days
The PondCast
4 days
KCM Race Survival
4 days
Replay Cast
4 days
PiG Sty Festival
5 days
CranKy Ducklings
6 days
PiG Sty Festival
6 days
Liquipedia Results

Completed

Escore Tournament S3: W7
CranK Gathers Season 4: BW vs SC2 Team League
Eternal Conflict S2 Finale

Ongoing

KCM Race Survival 2026 Season 3
K-JUNGMAN
Acropolis #5
CSLAN 4
RSL Revival: Season 6
PiG Sty Festival 8.0
META DYMY #4
Esports World Cup 2026
Esports World Cup 2026: LCQ
BLAST Bounty Summer 2026
BLAST Bounty Summer Qual
Stake Ranked Episode 3
XSE Pro League 2026
IEM Cologne Major 2026

Upcoming

ASL Season 22
CSL Season 22: Qualifier 1
Escore Tournament S3: W8
CSL Season 22: Qualifier 2
CSL 2026 AUTUMN (S22)
Acropolis #5 - TRS
Blizzard Classic Cup 2026
HSC XXX
SC4ALL II: StarCraft II
Kung Fu Cup 2026 Grand Finals
RSL Offline Finals
Big Dog Cup 2026 Div 1
Stake Ranked Episode 5
PGL Masters Bucharest 2026
Thunderpick World Champ. '26
ESL Pro League Season 24
Stake Ranked Episode 4
1win Private Club #1
Logitech G Connect 2026
SL StarSeries Fall 2026
FISSURE Playground #5
BLAST Open Fall 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.