From 3552869913b0b087168f3b729289ea80c7a5b633 Mon Sep 17 00:00:00 2001 From: h3nc4 Date: Mon, 18 Dec 2023 12:48:33 -0300 Subject: [PATCH] =?UTF-8?q?Renova=C3=A7=C3=A3o=20do=20projeto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 +- LICENSE | 37 ++++--- README.md | 40 +++---- code/velha.c | 230 ---------------------------------------- scripts/build.sh | 2 + scripts/tic-tac-toe.ico | Bin 0 -> 269342 bytes scripts/win.cmd | 3 + src/AI.c | 79 ++++++++++++++ src/avalia_tabuleiro.c | 50 +++++++++ src/jogador.c | 98 +++++++++++++++++ src/velha.c | 83 +++++++++++++++ src/velha.h | 67 ++++++++++++ 12 files changed, 421 insertions(+), 272 deletions(-) delete mode 100644 code/velha.c create mode 100755 scripts/build.sh create mode 100644 scripts/tic-tac-toe.ico create mode 100755 scripts/win.cmd create mode 100644 src/AI.c create mode 100644 src/avalia_tabuleiro.c create mode 100644 src/jogador.c create mode 100644 src/velha.c create mode 100644 src/velha.h diff --git a/.gitignore b/.gitignore index b5a313b..3e29dca 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -velha.exe +*.json +jogo-da-velha.exe +velha diff --git a/LICENSE b/LICENSE index 4395f50..2ffae55 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,24 @@ -MIT License +BSD 2-Clause License -Copyright (c) 2022 Henrique Almeida +Copyright (c) 2022-2023, Henrique Almeida -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index 8dd0524..09d65e2 100644 --- a/README.md +++ b/README.md @@ -2,46 +2,38 @@ This is a Tic-Tac-Toe game implementation with an artificial intelligence player written in C using the mini-max algorithm. The game allows a player to play against the AI, where the player always starts first and plays as X. -## Requirements - -To run this game, you will need to have a C compiler installed on your computer. - ## How to Play -1. Clone the repo: - - ```bash - git clone https://github.com/henrish0/jogo-da-velha.git - ``` - -2. Navigate to the code: +### Clone the repo - ```bash - cd jogo-da-velha/code - ``` +```bash +git clone https://github.com/henrish0/jogo-da-velha.git +``` -3. Compile the code: +### Build the project - ```bash - gcc velha.c -o velha - ``` +```bash +cd jogo-da-velha/ +./scripts/build.sh +``` -4. Run the game: +Run the game - ```bash - velha - ``` +```bash +./velha +``` -Or you can also see releases for the exe file +You can also see **[releases](https://github.com/henrish0/jogo-da-velha/releases)** for the compiled Windows version. ## Game Rules - The game is played on a 3x3 grid. -- The player always starts first and plays as X. +- The player starts first and plays as X. - The AI plays as O. - Players take turns placing their mark on an empty cell in the grid. - The first player to get three of their marks in a row (horizontally, vertically, or diagonally) wins the game. - If all cells are filled and no player has won, the game is a tie. +- The starting player alternates between games, so the AI plays next. ## How the AI Works diff --git a/code/velha.c b/code/velha.c deleted file mode 100644 index c3fe674..0000000 --- a/code/velha.c +++ /dev/null @@ -1,230 +0,0 @@ -/** - * MIT License - * - * Copyright(c) 2022 Henrique Almeida - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include - -// verifica se há possibilidades de vitória para a função minimax -#define possibilidades() (tabuleiro[0] == tabuleiro[1] && tabuleiro[1] == tabuleiro[2] && tabuleiro[0] != 0 ? tabuleiro[0] \ - : tabuleiro[3] == tabuleiro[4] && tabuleiro[4] == tabuleiro[5] && tabuleiro[3] != 0 ? tabuleiro[3] \ - : tabuleiro[6] == tabuleiro[7] && tabuleiro[7] == tabuleiro[8] && tabuleiro[6] != 0 ? tabuleiro[6] \ - : tabuleiro[0] == tabuleiro[3] && tabuleiro[3] == tabuleiro[6] && tabuleiro[0] != 0 ? tabuleiro[0] \ - : tabuleiro[1] == tabuleiro[4] && tabuleiro[4] == tabuleiro[7] && tabuleiro[1] != 0 ? tabuleiro[1] \ - : tabuleiro[2] == tabuleiro[5] && tabuleiro[5] == tabuleiro[8] && tabuleiro[2] != 0 ? tabuleiro[2] \ - : tabuleiro[0] == tabuleiro[4] && tabuleiro[4] == tabuleiro[8] && tabuleiro[0] != 0 ? tabuleiro[0] \ - : tabuleiro[2] == tabuleiro[4] && tabuleiro[4] == tabuleiro[6] && tabuleiro[2] != 0 ? tabuleiro[2] \ - : 0) - -static int tabuleiro[9]; // tabuleiro do jogo - -/** - * \brief Função que imprime o tabuleiro - */ -static void print_tabuleiro(void) -{ - system("cls"); - for (int i = 0; i < 9; i++) - { - switch (i) - { - case 0: - case 3: - case 6: - printf("\n --- --- --- \n "); - break; - default: - printf("|"); - } - switch (tabuleiro[i]) - { - case -1: - printf(" X "); - break; - case 1: - printf(" O "); - break; - default: - printf(" "); - } - } - printf("\n --- --- --- \n\n"); -} - -/** - * \brief Verifica se o jogo acabou - * \return Retorna o jogador vencedor, 0 se não houver um e 9 se houver empate - */ -static int avalia_tabuleiro(void) -{ - for (int i = 0; i < 3; i++) - { - if (tabuleiro[i] == tabuleiro[i + 3] && tabuleiro[i + 3] == tabuleiro[i + 6]) // verifica se há uma linha vencedora - return tabuleiro[i]; // se houver, retorna o jogador vencedor - if (tabuleiro[i * 3] == tabuleiro[i * 3 + 1] && tabuleiro[i * 3 + 1] == tabuleiro[i * 3 + 2]) // verifica se há uma coluna vencedora - return tabuleiro[i * 3]; // se houver, retorna o jogador vencedor - } - if (tabuleiro[0] == tabuleiro[4] && tabuleiro[4] == tabuleiro[8]) // verifica se há uma diagonal vencedora - return tabuleiro[0]; - if (tabuleiro[2] == tabuleiro[4] && tabuleiro[4] == tabuleiro[6]) // verifica se há uma diagonal vencedora - return tabuleiro[2]; - for (int i = 0; i < 9; i++) // verifica se há um empate - if (tabuleiro[i] == 0) // se há uma posição vazia, não há empate - return 0; - return 9; // se não houver vencedor e não houver posição vazia, há empate -} - -/** - * \brief Algoritmo minimax - * \return Retorna o jogador vencedor - * \param jogador Valor que representa o jogador - */ -static int minimax(int jogador) -{ - int vencedor = possibilidades(), // verifica se há um vencedor - jogada = -1, decisao, melhor_decisao = -2; // melhor_decisao = -2 para que o primeiro valor seja maior que ele - if (vencedor != 0) // se houver um vencedor, retorna o jogador atual - return vencedor * jogador; - for (int i = 0; i < 9; i++) // percorre o tabuleiro inteiro - if (tabuleiro[i] == 0) // se a posição estiver vazia - { - tabuleiro[i] = jogador; // preenche a posição com o jogador atual - decisao = -minimax(-jogador); // chama a função minimax com o jogador oposto ao atual - if (decisao > melhor_decisao) // se o resultado for maior que a saída - { - melhor_decisao = decisao; // a saída se torna o resultado - jogada = i; // a melhor jogada se torna a posição atual - } - tabuleiro[i] = 0; // limpa a posição atual - } - if (jogada == -1) // se não houver nenhuma jogada possível - return 0; - return melhor_decisao; -} - -/** - * \brief Função que realiza o turno da AI - * \return Retorna o valor da função avalia_tabuleiro - */ -static int jogada_AI(void) -{ - int jogada = -1, melhor_decisao = -2, decisao; - for (int i = 0; i < 9; i++) // percorre o tabuleiro - if (tabuleiro[i] == 0) // 0 = vazio - { - tabuleiro[i] = 1; // 1 = AI - decisao = -minimax(-1); // -1 = jogador - tabuleiro[i] = 0; // 0 = vazio - if (decisao > melhor_decisao) // se a jogada for melhor que as anteriores - { - melhor_decisao = decisao; // a saída se torna o resultado - jogada = i; // a melhor jogada se torna a posição atual - } - } - tabuleiro[jogada] = 1; - return avalia_tabuleiro(); -} - -/** - * \brief Função que realiza o turno do jogador - * \return Retorna o valor da função avalia_tabuleiro - */ -static int jogada_pessoa(void) -{ - printf(" Seu turno. Qual a sua opcao? "); - while (1) - { - int jogada = fgetc(stdin) - 48; // pega o primeiro caractere da entrada converte para inteiro - fflush(stdin); - if (jogada >= 1 && jogada <= 9 && tabuleiro[jogada - 1] == 0) // 0 = vazio - { - tabuleiro[jogada - 1] = -1; // -1 = jogador - break; // sai do loop - } - printf(" Tentativa invalida. Qual a sua opcao? "); - } - return avalia_tabuleiro(); -} - -/** - * \brief Função que realiza o jogo - * \return Retorna o jogador vencedor - */ -static int jogo(int jogador) -{ - int vencedor = 0; - while (!vencedor) // 9 = empate, 1 = AI, -1 = jogador, 0 = jogo em andamento - if (jogador) - { - print_tabuleiro(); - vencedor = jogada_pessoa(); - jogador--; - } - else - { - jogador++; - vencedor = jogada_AI(); - } - return vencedor; -} - -static void novoJogo(void) -{ - - printf(" Deseja jogar novamente? (s/n) "); - char resposta; - while (1) - { - resposta = fgetc(stdin); - fflush(stdin); - if (resposta == 's' || resposta == 'n') - break; - printf(" Resposta invalida. Deseja jogar novamente? (s/n) "); - } - if (resposta == 'n') - { - system("pause"); - exit(0); - } -} - -int main() -{ - - while (1) // loop para jogar multiplas partidas - { - for (int i = 0; i < 9; i++) - tabuleiro[i] = 0; // limpa o tabuleiro - - int vencedor = jogo(1); // 0 = vazio, 1 = AI, -1 = jogador - - print_tabuleiro(); // imprime o tabuleiro final - printf(vencedor == 9 ? "\n Empate! Nos vemos da proxima vez.\n\n" // - : vencedor == 1 ? "\n Eu ganhei!\n\n" // - : "\n Impressionante, voce me derrotou\n\n" // - ); - - novoJogo(); // permite uma nova partida - } - return 0; -} diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..420fc4a --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,2 @@ +gcc src/* -o ./velha +chmod +x velha diff --git a/scripts/tic-tac-toe.ico b/scripts/tic-tac-toe.ico new file mode 100644 index 0000000000000000000000000000000000000000..e81fa64c252a3bbaedfd4303a2c9302188529579 GIT binary patch literal 269342 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 rTClG=P4A=h(7LP?c literal 0 HcmV?d00001 diff --git a/scripts/win.cmd b/scripts/win.cmd new file mode 100755 index 0000000..dfd9758 --- /dev/null +++ b/scripts/win.cmd @@ -0,0 +1,3 @@ +echo 0 ICON "tic-tac-toe.ico" | windres -O coff -o i.o +gcc ..\src\* i.o -o ../jogo-da-velha.exe +del i.o diff --git a/src/AI.c b/src/AI.c new file mode 100644 index 0000000..80fd52a --- /dev/null +++ b/src/AI.c @@ -0,0 +1,79 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2022-2023, Henrique Almeida + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "velha.h" + +/** + * \brief Algoritmo minimax, calcula a melhor jogada possível + * \return Retorna o jogador vencedor + * \param jogador Valor que representa o jogador + */ +int minimax(int jogador) +{ + int vencedor = vitoria(), // verifica se há um vencedor + jogada = -1, decisao, melhor_decisao = -2; // melhor_decisao = -2 para que o primeiro valor seja maior que ele + if (vencedor) // se houver um vencedor, retorna o jogador atual + return vencedor * jogador; + for (int i = 0; i < 9; i++) // percorre o tabuleiro + if (!tabuleiro[i]) // se a posição estiver vazia + { + tabuleiro[i] = jogador; // preenche a posição com o jogador atual + decisao = -minimax(-jogador); // chama a função minimax com o jogador oposto ao atual + if (decisao > melhor_decisao) // se o resultado for maior que a saída + { + melhor_decisao = decisao; // a saída se torna o resultado + jogada = i; // a melhor jogada se torna a posição atual + } + tabuleiro[i] = 0; // limpa a posição atual + } + if (jogada == -1) // se não houver nenhuma jogada possível + return 0; + return melhor_decisao; +} + +/** + * \brief Realiza o turno da AI + * \return Retorna o valor da função avalia_tabuleiro + */ +int jogada_AI(void) +{ + int jogada = -1, melhor_decisao = -2, decisao; + for (int i = 0; i < 9; i++) // percorre o tabuleiro + if (!tabuleiro[i]) // se a posição estiver vazia + { + tabuleiro[i] = 1; // 1 = AI + decisao = -minimax(-1); // -1 = jogador + tabuleiro[i] = 0; // 0 = vazio + if (decisao > melhor_decisao) // se a jogada for melhor que as anteriores + { + melhor_decisao = decisao; // a saída se torna o resultado + jogada = i; // a melhor jogada se torna a posição atual + } + } + tabuleiro[jogada] = 1; + return avalia_tabuleiro(); +} diff --git a/src/avalia_tabuleiro.c b/src/avalia_tabuleiro.c new file mode 100644 index 0000000..c490481 --- /dev/null +++ b/src/avalia_tabuleiro.c @@ -0,0 +1,50 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2022-2023, Henrique Almeida + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "velha.h" + +/** + * \brief Verifica se há empate + * \return Retorna verdadeiro se houver empate e falso caso ainda haja jogadas + */ +int empate(void) +{ + for (int i = 0; i < 9; i++) + if (!tabuleiro[i]) // se houver uma posição vazia + return 0; // não há empate + return 1; // se não houver posições vazias, há empate +} + +/** + * \brief Verifica se o jogo acabou + * \return Retorna o jogador vencedor, 0 se não houver um e 9 se houver empate + */ +int avalia_tabuleiro(void) +{ + int v = vitoria(); + return v ? v : empate() ? 9 : 0; +} diff --git a/src/jogador.c b/src/jogador.c new file mode 100644 index 0000000..495f5d0 --- /dev/null +++ b/src/jogador.c @@ -0,0 +1,98 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2022-2023, Henrique Almeida + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "velha.h" + +/** + * \brief Imprime o tabuleiro na tela + */ +void print_tabuleiro(void) +{ + system(CLEAR); + for (int i = 0; i < 9; i++) + { + switch (i) + { + case 0: + case 3: + case 6: + printf("\n --- --- --- \n "); + break; + default: + printf("|"); + } + switch (tabuleiro[i]) + { + case -1: + printf(" X "); + break; + case 1: + printf(" O "); + break; + default: + printf(" "); + } + } + printf("\n --- --- --- \n\n"); +} + +void limpar_buffer_entrada() +{ + int c; + while ((c = getchar()) != '\n' && c != EOF) {} + fflush(stdin); +} + +/** + * \brief Realiza o turno do jogador + * \return Retorna o valor da função avalia_tabuleiro + */ +int jogada_pessoa(void) +{ + print_tabuleiro(); + printf(" Seu turno. Qual a sua opcao? "); + int jogada; + while (1) + { + if (scanf("%d", &jogada) != 1) + { + limpar_buffer_entrada(); + printf("Tentativa invalida. Qual a sua opcao? "); + continue; + } + limpar_buffer_entrada(); + printf("debug: %d\n", jogada); + printf("debug: %d\n", !tabuleiro[jogada - 1]); + if (jogada >= 1 && jogada <= 9 && !tabuleiro[jogada - 1]) // verifica se a jogada é válida + { + tabuleiro[jogada - 1] = -1; // -1 = jogador + break; // sai do loop + } + printf(" Tentativa invalida. Qual a sua opcao? "); + } + return avalia_tabuleiro(); +} diff --git a/src/velha.c b/src/velha.c new file mode 100644 index 0000000..08d013d --- /dev/null +++ b/src/velha.c @@ -0,0 +1,83 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2022-2023, Henrique Almeida + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "velha.h" + +int *tabuleiro; + +/** + * \brief Pergunta se o usuário deseja jogar novamente + */ +void novo_jogo(void) +{ + printf(" Deseja jogar novamente? (s/n) "); + char resposta; + while (1) + { + resposta = fgetc(stdin); + fflush(stdin); + if (resposta == 's' || resposta == 'n') + break; + printf(" Resposta invalida. Deseja jogar novamente? (s/n) "); + } + if (resposta == 'n') + { + free(tabuleiro); + exit(0); + } +} + +/** + * \brief Verifica se existe um vencedor + * \param jogador Define se o jogador começa ou não + * \return Retorna o jogador vencedor + */ +int jogo(int jogador) +{ + int vencedor = 0; + while (!vencedor) // 9 = empate, 1 = AI, -1 = jogador, 0 = jogo em andamento + vencedor = (jogador = !jogador) ? jogada_pessoa() : jogada_AI(); + return vencedor; +} + +int main(void) +{ + tabuleiro = malloc(sizeof(int) * 9); + char inicio = 0; + while (1) + { + for (int i = 0; i < 9; i++) + tabuleiro[i] = 0; // limpa o tabuleiro + int vencedor = jogo(inicio++ % 2); // 0 = jogador começa, 1 = AI começa + print_tabuleiro(); + printf(vencedor == 9 ? "\n Empate! Nos vemos da proxima vez.\n\n" // + : vencedor == 1 ? "\n Eu ganhei!\n\n" // + : "\n Impressionante, voce me derrotou\n\n" // + ); + novo_jogo(); + } +} diff --git a/src/velha.h b/src/velha.h new file mode 100644 index 0000000..679582b --- /dev/null +++ b/src/velha.h @@ -0,0 +1,67 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2022-2023, Henrique Almeida + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// includes padrão +#include +#include + +// limpa a tela +#ifdef _WIN32 +#define CLEAR "cls" +#else +#define CLEAR "clear" +#endif + +// tabuleiro do jogo +extern int *tabuleiro; + +#define t tabuleiro + +/** + * \brief Verifica se há possibilidades de vitória para a função minimax + * \return Retorna o jogador vencedor + */ +#define vitoria() t[0] == t[1] && t[1] == t[2] && t[0] != 0 ? t[0] \ + : t[3] == t[4] && t[4] == t[5] && t[3] != 0 ? t[3] \ + : t[6] == t[7] && t[7] == t[8] && t[6] != 0 ? t[6] \ + : t[0] == t[3] && t[3] == t[6] && t[0] != 0 ? t[0] \ + : t[1] == t[4] && t[4] == t[7] && t[1] != 0 ? t[1] \ + : t[2] == t[5] && t[5] == t[8] && t[2] != 0 ? t[2] \ + : t[0] == t[4] && t[4] == t[8] && t[0] != 0 ? t[0] \ + : t[2] == t[4] && t[4] == t[6] && t[2] != 0 ? t[2] \ + : 0 + +// funções + +int avalia_tabuleiro(void); +int jogada_AI(void); +int jogada_pessoa(void); +int jogo(int jogador); +int main(void); +int minimax(int jogador); +void novo_jogo(void); +void print_tabuleiro(void);