• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EST 06:44
CET 12:44
KST 20:44
  • 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
RSL Revival - 2025 Season Finals Preview8RSL Season 3 - Playoffs Preview0RSL Season 3 - RO16 Groups C & D Preview0RSL Season 3 - RO16 Groups A & B Preview2TL.net Map Contest #21: Winners12
Community News
ComeBackTV's documentary on Byun's Career !9Weekly Cups (Dec 8-14): MaxPax, Clem, Cure win4Weekly Cups (Dec 1-7): Clem doubles, Solar gets over the hump1Weekly Cups (Nov 24-30): MaxPax, Clem, herO win2BGE Stara Zagora 2026 announced15
StarCraft 2
General
Micro Lags When Playing SC2? ComeBackTV's documentary on Byun's Career ! When will we find out if there are more tournament Weekly Cups (Dec 8-14): MaxPax, Clem, Cure win RSL Revival - 2025 Season Finals Preview
Tourneys
Sparkling Tuna Cup - Weekly Open Tournament $100 Prize Pool - Winter Warp Gate Masters Showdow $5,000+ WardiTV 2025 Championship Winter Warp Gate Amateur Showdown #1 RSL Offline Finals Info - Dec 13 and 14!
Strategy
Custom Maps
Map Editor closed ?
External Content
Mutation # 504 Retribution Mutation # 503 Fowl Play Mutation # 502 Negative Reinforcement Mutation # 501 Price of Progress
Brood War
General
Klaucher discontinued / in-game color settings Anyone remember me from 2000s Bnet EAST server? BGH Auto Balance -> http://bghmmr.eu/ How Rain Became ProGamer in Just 3 Months FlaSh on: Biggest Problem With SnOw's Playstyle
Tourneys
[BSL21] LB QuarterFinals - Sunday 21:00 CET Small VOD Thread 2.0 [Megathread] Daily Proleagues [BSL21] WB SEMIFINALS - Saturday 21:00 CET
Strategy
Simple Questions, Simple Answers Game Theory for Starcraft Current Meta Fighting Spirit mining rates
Other Games
General Games
Stormgate/Frost Giant Megathread General RTS Discussion Thread Nintendo Switch Thread Mechabellum PC Games Sales Thread
Dota 2
Official 'what is Dota anymore' discussion
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
Mafia Game Mode Feedback/Ideas Survivor II: The Amazon Sengoku Mafia TL Mafia Community Thread
Community
General
The Games Industry And ATVI Russo-Ukrainian War Thread US Politics Mega-thread Things Aren’t Peaceful in Palestine YouTube Thread
Fan Clubs
White-Ra Fan Club
Media & Entertainment
Anime Discussion Thread [Manga] One Piece Movie Discussion!
Sports
2024 - 2026 Football Thread Formula 1 Discussion
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread
TL Community
TL+ Announced Where to ask questions and add stream?
Blogs
The (Hidden) Drug Problem in…
TrAiDoS
I decided to write a webnov…
DjKniteX
James Bond movies ranking - pa…
Topin
Thanks for the RSL
Hildegard
Customize Sidebar...

Website Feedback

Closed Threads



Active: 1915 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
Germany1774 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
3830 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 States1250 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 2025
11:00
Championship Sunday
Reynor vs SolarLIVE!
Clem vs MaxPax
Classic vs SHIN
WardiTV1095
ComeBackTV 900
TaKeTV 321
LiquipediaDiscussion
Sparkling Tuna Cup
10:00
Weekly #116
ByuN vs PercivalLIVE!
TBD vs Krystianer
CranKy Ducklings75
LiquipediaDiscussion
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
DivinesiaTV 16
Rex 11
StarCraft: Brood War
Sea 6851
Calm 4782
Rain 2409
GuemChi 1535
Horang2 1151
Shuttle 1129
Stork 444
Soma 402
firebathero 268
Last 242
[ Show more ]
Mini 223
Sharp 204
EffOrt 194
Light 179
Hyun 149
Rush 129
hero 111
soO 75
ggaemo 71
Yoon 65
Barracks 60
Killer 47
NaDa 42
Mong 35
Movie 29
910 27
zelot 24
Terrorterran 23
GoRush 17
SilentControl 7
Dota 2
Gorgc3765
singsing3113
XcaliburYe340
BananaSlamJamma133
League of Legends
JimRising 368
rGuardiaN76
Counter-Strike
zeus743
x6flipin668
edward107
Heroes of the Storm
Khaldor256
Other Games
B2W.Neo1171
Fuzer 356
RotterdaM162
Mew2King84
MindelVK14
Organizations
StarCraft: Brood War
CasterMuse 23
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 15 non-featured ]
StarCraft 2
• Berry_CruncH263
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• LaughNgamezSOOP
• Migwel
• sooper7s
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• WagamamaTV633
• lizZardDota284
League of Legends
• Jankos2299
• Stunt720
Upcoming Events
Ladder Legends
5h 17m
BSL 21
8h 17m
StRyKeR vs TBD
Bonyth vs TBD
Replay Cast
21h 17m
Wardi Open
1d
Monday Night Weeklies
1d 5h
WardiTV Invitational
3 days
Replay Cast
3 days
WardiTV Invitational
4 days
ByuN vs Solar
Clem vs Classic
Cure vs herO
Reynor vs MaxPax
Replay Cast
5 days
Sparkling Tuna Cup
6 days
Liquipedia Results

Completed

Acropolis #4 - TS3
RSL Offline Finals
Kuram Kup

Ongoing

C-Race Season 1
IPSL Winter 2025-26
KCM Race Survival 2025 Season 4
YSL S2
BSL Season 21
Slon Tour Season 2
CSL Season 19: Qualifier 1
WardiTV 2025
META Madness #9
eXTREMESLAND 2025
SL Budapest Major 2025
ESL Impact League Season 8
BLAST Rivals Fall 2025
IEM Chengdu 2025
PGL Masters Bucharest 2025
Thunderpick World Champ.
CS Asia Championships 2025
ESL Pro League S22

Upcoming

CSL Season 19: Qualifier 2
CSL 2025 WINTER (S19)
BSL 21 Non-Korean Championship
Acropolis #4
IPSL Spring 2026
Bellum Gens Elite Stara Zagora 2026
HSC XXVIII
Big Gabe Cup #3
OSC Championship Season 13
Nations Cup 2026
ESL Pro League Season 23
PGL Cluj-Napoca 2026
IEM Kraków 2026
BLAST Bounty Winter 2026
BLAST Bounty Winter Qual
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 © 2025 TLnet. All Rights Reserved.