Jogo da Velha em C
Eu tinha feito há algum tempo atrás o mesmo jogo em Java, mas não tinha gostado muito do meu código-fonte. Era ineficiente e longo demais. Daí que resolvi refazê-lo, agora em C. Demorei cerca de três horas para terminar.
A inteligência da CPU é bem simples. Ela primeiro testa se existe a possibilidade de ganhar o jogo no ato, e, se houver, ela joga para ganhar. Se não tiver como vencer, ela tenta se defender, testando se existe alguma forma de o jogador ganhar na próxima jogada dele. Se existir, ela se defende.
Pra jogar em uma posição vazia (representada por 0) é só digitar a linha e a coluna, que variam de 1 a 3, separadas por um espaço.
1/* ***********************************
2 * Autor: Lucas Stefano
3 * Data: 20/12/2023
4 ***********************************
5*/
6
7#include <stdio.h>
8#include <stdlib.h>
9
10#define LINHAS 3
11#define COLUNAS 3
12#define CASAS 9
13
14void init_tabuleiro(void);
15void mostra_tabuleiro(void);
16void jogada_player(void);
17void jogada_cpu(void);
18int update_tabuleiro(int x, int y); // retorna 0 se a operação for bem sucedida
19int testa_vencedor(void); // 2 - vitória cpu, 1 - vitória player, 0 - nada aconteceu
20int velha(void); // conta o número de casas vazias no tabuleiro
21
22enum vez { PLAYER, CPU } jogador;
23
24int tabuleiro[LINHAS][COLUNAS];
25
26void main() {
27 int escolha, status;
28 jogador = PLAYER; // seta o primeiro jogador para player
29 init_tabuleiro(); // inicia o tabuleiro com 0s
30
31 while(1) {
32 if (jogador == PLAYER) {
33 if (!velha()) break;
34 mostra_tabuleiro();
35 jogada_player();
36 status = testa_vencedor();
37 if (status) break;
38 }
39 if (jogador == CPU) {
40 if (!velha()) break;
41 jogada_cpu();
42 status = testa_vencedor();
43 if (status) break;
44 }
45 }
46
47 mostra_tabuleiro();
48
49 if (status == 1) printf("\nParabéns, você venceu!\n");
50 else if (status == 2) printf("\nVocê perdeu! :(\n");
51 else printf("\nDeu velha!\n");
52
53 while(1) {
54 printf("\nJogar novamente? (1 = sim / 2 = não) : ");
55 scanf("%d", &escolha);
56 if (escolha == 1) main();
57 else if (escolha == 2) exit(0);
58 else printf("\nEscolha invalida!");
59 }
60}
61
62void init_tabuleiro() {
63 register int i;
64 int *p;
65 p = (int *) tabuleiro;
66
67 for (i = 0; i < CASAS; i++ ) *(p+i) = 0;
68}
69
70int velha() {
71 register int i;
72 int *p, zeros = 0;
73 p = (int *) tabuleiro;
74
75 for (i = 0; i < CASAS; i++ ) if (*(p+i) == 0) zeros++;
76
77 if (!zeros) return 0;
78 else return 1;
79}
80
81void mostra_tabuleiro() {
82 register int i, j;
83 printf("\n");
84
85 for (i = 0; i < 3; i++) {
86 for (j = 0; j < 3; j++) {
87 printf("%d", tabuleiro[i][j]);
88 }
89 printf("\n");
90 }
91}
92
93int update_tabuleiro(int x, int y) {
94 if (jogador == PLAYER) {
95 tabuleiro[x][y] = 1;
96 jogador = CPU;
97 return 0;
98 }
99 if (jogador == CPU) {
100 if (tabuleiro[x][y] != 0) return 1;
101 else {
102 tabuleiro[x][y] = 2;
103 jogador = PLAYER;
104 return 0;
105 }
106 }
107}
108
109void jogada_player() {
110 int x, y;
111 printf("\nDigite a linha e a coluna em que deseja jogar: ");
112 scanf("%d %d", &x, &y);
113
114 x--, y--;
115
116 if (tabuleiro[x][y] != 0 || x < 0 || x > 2 || y < 0 || y > 2) {
117 printf("\nJogada inválida.\n");
118 jogada_player();
119 }
120 else update_tabuleiro(x, y);
121}
122
123void jogada_cpu() {
124 register int i, j, x, y;
125 int ad; // ataque e defesa. Quando 'ad' vale 2, a cpu testa a possibilidade de ataque.
126 // se valer 1, ela testa por defesa.
127
128 // série de testes que verificará se há possibilidade de o jogador ou a CPU vencer
129 // o jogo em alguma linha, alguma coluna ou alguma diagonal.
130
131 for (ad = 2; ad >= 1; ad--) {
132 for (i = 0; i < 3; i++) { // para todas as linhas e colunas
133 if (tabuleiro[i][1] == ad && tabuleiro[i][2] == ad)
134 if (!update_tabuleiro(i, 0)) return;
135 if (tabuleiro[i][0] == ad && tabuleiro[i][2] == ad)
136 if (!update_tabuleiro(i, 1)) return;
137 if (tabuleiro[i][0] == ad && tabuleiro[i][1] == ad)
138 if (!update_tabuleiro(i, 2)) return;
139 if (tabuleiro[1][i] == ad && tabuleiro[2][i] == ad)
140 if (!update_tabuleiro(0, i)) return;
141 if (tabuleiro[0][i] == ad && tabuleiro[2][i] == ad)
142 if (!update_tabuleiro(1, i)) return;
143 if (tabuleiro[0][i] == ad && tabuleiro[1][i] == ad)
144 if (!update_tabuleiro(2, i)) return;
145 }
146
147 // para as diagonais
148 if (tabuleiro[0][0] == ad && tabuleiro[2][2] == ad)
149 if (!update_tabuleiro(1, 1)) return;
150 if (tabuleiro[0][2] == ad && tabuleiro[2][0] == ad)
151 if (!update_tabuleiro(1, 1)) return;
152 if (tabuleiro[0][2] == ad && tabuleiro[1][1] == ad)
153 if (!update_tabuleiro(2, 0)) return;
154 if (tabuleiro[2][2] == ad && tabuleiro[1][1] == ad)
155 if (!update_tabuleiro(0, 0)) return;
156 if (tabuleiro[2][0] == ad && tabuleiro[1][1] == ad)
157 if (!update_tabuleiro(0, 2)) return;
158 if (tabuleiro[0][0] == ad && tabuleiro[1][1] == ad)
159 if (!update_tabuleiro(2, 2)) return;
160 }
161
162 // caso nenhum dos testes acima sejam satisfeitos, a cpu joga aleatoriamente
163
164 srand(time(NULL));
165
166 while(1) {
167 x = rand() % 3;
168 y = rand() % 3;
169 if (!update_tabuleiro(x,y)) return;
170 }
171}
172
173int testa_vencedor() {
174 register int i;
175 int a = (jogador == CPU) ? 1 : 2; // 'a' varia de acordo com quem o chama
176
177 for (i = 0; i < 3; i++)
178 if (tabuleiro[i][0] == a && tabuleiro[i][1] == a && tabuleiro[i][2] == a) return a;
179 for (i = 0; i < 3; i++)
180 if (tabuleiro[0][i] == a && tabuleiro[1][i] == a && tabuleiro[2][i] == a) return a;
181
182 if (tabuleiro[2][0] == a && tabuleiro[1][1] == a && tabuleiro[0][2] == a) return a;
183 if (tabuleiro[0][0] == a && tabuleiro[1][1] == a && tabuleiro[2][2] == a) return a;
184
185 return 0;
186}