argcv

codes and stuff

Archive for the ‘jogos’ Category

Jogo da velha 2.0 – No Country For Old Men

with one comment

Quando terminei de escrever aquele joguinho da velha, um fato ficou me perturbando: a CPU perdia com muita facilidade.

Daí eu resolvi ensinar a ela uns truques, e criei quatro níveis para o jogo: Noob, Médio, Gladiador e Zeus. Sendo que o último, dizem as más línguas, é impossível de se vencer.

Também adaptei a função mostra_tabuleiro() para apresentar tabuleiros que condizem mais com um de verdade. O “1” do player foi substituído pelo “X” e o “2” da CPU foi substituído pelo “O”.

Percebam também que eu adicionei a função __fpurge() em algumas ocasiões. Isso porque sem ela alguns bugs estavam sendo provocados em situações em que havia interação com o usuário.

Se você usa Windows (tsc tsc) deverá trocar o __fpurge() por fflush().

O código-fonte segue abaixo. E também está no pastebin.

/* ***********************************
   * Autor: Renato R. Leme
   * Data: 14/04/2012 (atualizado em 17/04/2012)
   * e-mail: rntreisleme@gmail.com
   * site: https://argcv.wordpress.com
   ***********************************
   Qualquer dúvida ou sugestão, pode entrar em contato comigo pelo meu e-mail
   ou pelo meu blog.
*/

#include <stdio.h>
#include <stdlib.h>

#define LINHAS  3
#define COLUNAS 3
#define CASAS   9

void init_tabuleiro(void);
void mostra_tabuleiro(void);
void jogada_player(void);
void jogada_cpu(int rodada);
int update_tabuleiro(int x, int y); // retorna 0 se a operação for bem sucedida
int testa_vencedor(void); // 2 - vitória cpu, 1 - vitória player, 0 - nada aconteceu
int velha(void); // conta o número de casas vazias no tabuleiro

enum vez { PLAYER, CPU } jogador;
enum niveis { NOOB, MEDIO, GLADIADOR, ZEUS } nivel;

int tabuleiro[LINHAS][COLUNAS];

void main() {
    int dificuldade, escolha, status;
    static int rodada;
    rodada = 0;
    jogador = PLAYER; // seta o primeiro jogador para player
    init_tabuleiro(); // inicia o tabuleiro com 0s

    while(1) {
        __fpurge(stdin); // limpa o buffer do teclado
        printf("\nEscolha o nível em que deseja jogar \n(1 - Noob, 2 - Médio, 3 - Gladiador, 4 - Zeus): ");
        scanf("%d", &dificuldade);
        if (dificuldade == 1) { nivel = NOOB; break; }
        else if (dificuldade == 2) { nivel = MEDIO; break; }
        else if (dificuldade == 3) { nivel = GLADIADOR; break; }
        else if (dificuldade == 4) { nivel = ZEUS; break; }
        else printf("\nEscolha invalida!");
    }

    while(1) {
        ++rodada;
        if (jogador == PLAYER) {
            if (!velha()) break;
            mostra_tabuleiro();
            jogada_player();
            status = testa_vencedor();
            if (status) break;
        }
        if (jogador == CPU) {
            if (!velha()) break;
            jogada_cpu(rodada);
            status = testa_vencedor();
            if (status) break;
        }
    }

    mostra_tabuleiro();

    if (status == 1) printf("\nParabéns, você venceu!\n");
    else if (status == 2) printf("\nVocê perdeu! :(\n");
    else printf("\nDeu velha!\n");

    while(1) {
        __fpurge(stdin);
        printf("\nJogar novamente? (1 = sim / 2 = não) : ");
        scanf("%d", &escolha);
        if (escolha == 1) main();
        else if (escolha == 2) exit(0);
        else printf("\nEscolha invalida!");
    }
}

void init_tabuleiro() {
    register int i;
    int *p;
    p = (int *) tabuleiro;

    for (i = 0; i < CASAS; i++ ) *(p+i) = 0;
}

int velha() {
    register int i;
    int *p, zeros = 0;
    p = (int *) tabuleiro;

    for (i = 0; i < CASAS; i++ ) if (*(p+i) == 0) zeros++;

    if (!zeros) return 0;
    else return 1;
}

void mostra_tabuleiro() {
    register int i, j;
    char m_tabuleiro[LINHAS][COLUNAS];

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            if (tabuleiro[i][j] == 0) m_tabuleiro[i][j] = ' ';
            if (tabuleiro[i][j] == 1) m_tabuleiro[i][j] = 'X';
            if (tabuleiro[i][j] == 2) m_tabuleiro[i][j] = 'O';
        }
    }

    printf("\n");

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            if (i < 2) printf("|_%c_|", m_tabuleiro[i][j]);
            else printf("| %c |", m_tabuleiro[i][j]);
        }
        printf("\n");
    }
}

int update_tabuleiro(int x, int y) {
    if (jogador == PLAYER) {
            tabuleiro[x][y] = 1;
            jogador = CPU;
            return 0;
        }
    if (jogador == CPU) {
        if (tabuleiro[x][y] != 0) return 1;
        else {
            tabuleiro[x][y] = 2;
            jogador = PLAYER;
            return 0;
        }
    }
}

void jogada_player() {
    int x, y;
    __fpurge(stdin);
    printf("\nDigite a linha e a coluna em que deseja jogar: ");
    scanf("%d %d", &x, &y);

    x--, y--;

    if (tabuleiro[x][y] != 0 || x < 0 || x > 2 || y < 0 || y > 2) {
        printf("\nJogada inválida.\n");
        jogada_player();
    }
    else update_tabuleiro(x, y);
}

void jogada_cpu(int rodada) {
    register int i;
    int x, y;
    static int diagonais; // será alterada caso o player comece a jogar pelas diagonais
    int ad; // ataque e defesa. Quando 'ad' vale 2, a cpu testa a possibilidade de ataque.
            // se valer 1, ela testa por defesa.

    diagonais = (rodada == 1) ? 0 : diagonais; // será zerada toda vez que o jogo reinicia

    // série de testes que verificará se há possibilidade de o jogador ou
    // a CPU vencer o jogo em alguma linha, alguma coluna ou alguma diagonal.
    // serão executados de acordo com o nivel do jogo.

    if (nivel == MEDIO || nivel == GLADIADOR || nivel == ZEUS) {
        for (ad = 2; ad >= 1; ad--) {
            for (i = 0; i < 3; i++) { // para todas as linhas e colunas
                if (tabuleiro[i][1] == ad && tabuleiro[i][2] == ad) if (!update_tabuleiro(i, 0)) return;
                if (tabuleiro[i][0] == ad && tabuleiro[i][2] == ad) if (!update_tabuleiro(i, 1)) return;
                if (tabuleiro[i][0] == ad && tabuleiro[i][1] == ad) if (!update_tabuleiro(i, 2)) return;
                if (tabuleiro[1][i] == ad && tabuleiro[2][i] == ad) if (!update_tabuleiro(0, i)) return;
                if (tabuleiro[0][i] == ad && tabuleiro[2][i] == ad) if (!update_tabuleiro(1, i)) return;
                if (tabuleiro[0][i] == ad && tabuleiro[1][i] == ad) if (!update_tabuleiro(2, i)) return;
            }

            // para as diagonais
            if (tabuleiro[0][0] == ad && tabuleiro[2][2] == ad) if (!update_tabuleiro(1, 1)) return;
            if (tabuleiro[0][2] == ad && tabuleiro[2][0] == ad) if (!update_tabuleiro(1, 1)) return;
            if (tabuleiro[0][2] == ad && tabuleiro[1][1] == ad) if (!update_tabuleiro(2, 0)) return;
            if (tabuleiro[2][2] == ad && tabuleiro[1][1] == ad) if (!update_tabuleiro(0, 0)) return;
            if (tabuleiro[2][0] == ad && tabuleiro[1][1] == ad) if (!update_tabuleiro(0, 2)) return;
            if (tabuleiro[0][0] == ad && tabuleiro[1][1] == ad) if (!update_tabuleiro(2, 2)) return;
        }

        if (nivel == GLADIADOR || nivel == ZEUS) { // testes que evitam jogadas do player
            if (rodada == 1 && tabuleiro[1][1] == 1) if (!update_tabuleiro(2, 0)) return;
            if ((!diagonais && rodada == 2) && tabuleiro[0][2] == 1) if (!update_tabuleiro(0, 0)) return;

            if (tabuleiro[0][1] == 1  || tabuleiro[1][0] == 1 || tabuleiro[1][2] == 1 || tabuleiro[2][1] == 1) {
                if (rodada == 1 && !update_tabuleiro(1, 1)) return;
                if (rodada == 2) {
                    if (tabuleiro[1][2] == 1 || tabuleiro[1][0] == 1) {
                        if (tabuleiro[2][0] == 1 && !update_tabuleiro(2, 2)) return;
                        if (tabuleiro[0][0] == 1 && !update_tabuleiro(0, 2)) return;
                        if (tabuleiro[0][1] == 1 && !update_tabuleiro(0, 0)) return;
                        if (tabuleiro[2][1] == 1 && !update_tabuleiro(2, 0)) return;
                    }
                    if (tabuleiro[0][1] == 1 || tabuleiro[2][1] == 1) {
                        if ((tabuleiro[2][0] == 1 || tabuleiro[0][0] == 1) && !update_tabuleiro(1, 2)) return;
                        if ((tabuleiro[2][2] == 1 || tabuleiro[0][2] == 1) && !update_tabuleiro(1, 0)) return;
                    }
                }
            }
        }

        if (nivel == ZEUS) { // ultimo nivel de testes para evitar jogadas
            if (tabuleiro[0][0] == 1 || tabuleiro[0][2] == 1 || tabuleiro[2][0] == 1 || tabuleiro[2][2] == 1) {
                diagonais++;
                if (!update_tabuleiro(1, 1)) return;
                if (rodada == 2) if (!update_tabuleiro(1, 0)) return;
            }
        }
    }

    // caso nenhum dos testes acima sejam satisfeitos, a cpu joga aleatoriamente

    srand(time(NULL));

    while(1) {
        x = rand() % 3;
        y = rand() % 3;
        if (!update_tabuleiro(x,y)) return;
    }

}

int testa_vencedor() {
    register int i;
    int a = (jogador == CPU) ? 1 : 2; // 'a' varia de acordo com quem o chama (player ou cpu)

    for (i = 0; i < 3; i++) if (tabuleiro[i][0] == a && tabuleiro[i][1] == a && tabuleiro[i][2] == a) return a;
    for (i = 0; i < 3; i++) if (tabuleiro[0][i] == a && tabuleiro[1][i] == a && tabuleiro[2][i] == a) return a;
    if (tabuleiro[2][0] == a && tabuleiro[1][1] == a && tabuleiro[0][2] == a) return a; 
    if (tabuleiro[0][0] == a && tabuleiro[1][1] == a && tabuleiro[2][2] == a) return a;

    return 0; // se não houver retorno até aqui, é sinal de que ninguém venceu. Portanto, a função retorna 0
}

Written by rntreis

abril 18, 2012 at 8:00 am

Publicado em C, jogos, programação

Jogo da velha em C

with one comment

(Confira também a versão melhorada deste código).

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.

/* ***********************************
   * Autor: Renato R. Leme
   * Data: 14/04/2012 (atualizado em 16/04/2012)
   * e-mail: rntreisleme@gmail.com
   * site: https://argcv.wordpress.com
   ***********************************
    Qualquer dúvida ou sugestão, pode entrar em contato comigo pelo meu e-mail
    ou pelo meu blog.
*/

#include <stdio.h>
#include <stdlib.h>

#define LINHAS  3
#define COLUNAS 3
#define CASAS   9

void init_tabuleiro(void);
void mostra_tabuleiro(void);
void jogada_player(void);
void jogada_cpu(void);
int update_tabuleiro(int x, int y); // retorna 0 se a operação for bem sucedida
int testa_vencedor(void); // 2 - vitória cpu, 1 - vitória player, 0 - nada aconteceu
int velha(void); // conta o número de casas vazias no tabuleiro

enum vez { PLAYER, CPU } jogador;

int tabuleiro[LINHAS][COLUNAS];

void main() {
    int escolha, status;
    jogador = PLAYER; // seta o primeiro jogador para player
    init_tabuleiro(); // inicia o tabuleiro com 0s

    while(1) {
        if (jogador == PLAYER) {
            if (!velha()) break;
            mostra_tabuleiro();
            jogada_player();
            status = testa_vencedor();
            if (status) break;
        }
        if (jogador == CPU) {
            if (!velha()) break;
            jogada_cpu();
            status = testa_vencedor();
            if (status) break;
        }
    }

    mostra_tabuleiro();

    if (status == 1) printf("\nParabéns, você venceu!\n");
    else if (status == 2) printf("\nVocê perdeu! :(\n");
    else printf("\nDeu velha!\n");

    while(1) {
        printf("\nJogar novamente? (1 = sim / 2 = não) : ");
        scanf("%d", &escolha);
        if (escolha == 1) main();
        else if (escolha == 2) exit(0);
        else printf("\nEscolha invalida!");
    }
}

void init_tabuleiro() {
    register int i;
    int *p;
    p = (int *) tabuleiro;

    for (i = 0; i < CASAS; i++ ) *(p+i) = 0;
}

int velha() {
    register int i;
    int *p, zeros = 0;
    p = (int *) tabuleiro;

    for (i = 0; i < CASAS; i++ ) if (*(p+i) == 0) zeros++;

    if (!zeros) return 0;
    else return 1;
}

void mostra_tabuleiro() {
    register int i, j;
    printf("\n");

    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            printf("%d", tabuleiro[i][j]);
        }
        printf("\n");
    }
}

int update_tabuleiro(int x, int y) {
    if (jogador == PLAYER) {
            tabuleiro[x][y] = 1;
            jogador = CPU;
            return 0;
        }
    if (jogador == CPU) {
        if (tabuleiro[x][y] != 0) return 1;
        else {
            tabuleiro[x][y] = 2;
            jogador = PLAYER;
            return 0;
        }
    }
}

void jogada_player() {
    int x, y;
    printf("\nDigite a linha e a coluna em que deseja jogar: ");
    scanf("%d %d", &x, &y);

    x--, y--;

    if (tabuleiro[x][y] != 0 || x < 0 || x > 2 || y < 0 || y > 2) {
        printf("\nJogada inválida.\n");
        jogada_player();
    }
    else update_tabuleiro(x, y);
}

void jogada_cpu() {
    register int i, j, x, y;
    int ad; // ataque e defesa. Quando 'ad' vale 2, a cpu testa a possibilidade de ataque.
            // se valer 1, ela testa por defesa.

    // série de testes que verificará se há possibilidade de o jogador ou a CPU vencer
    // o jogo em alguma linha, alguma coluna ou alguma diagonal.

    for (ad = 2; ad >= 1; ad--) {
        for (i = 0; i < 3; i++) { // para todas as linhas e colunas
            if (tabuleiro[i][1] == ad && tabuleiro[i][2] == ad) 
                if (!update_tabuleiro(i, 0)) return;
            if (tabuleiro[i][0] == ad && tabuleiro[i][2] == ad) 
                if (!update_tabuleiro(i, 1)) return;
            if (tabuleiro[i][0] == ad && tabuleiro[i][1] == ad) 
                if (!update_tabuleiro(i, 2)) return;
            if (tabuleiro[1][i] == ad && tabuleiro[2][i] == ad) 
                if (!update_tabuleiro(0, i)) return;
            if (tabuleiro[0][i] == ad && tabuleiro[2][i] == ad) 
                if (!update_tabuleiro(1, i)) return;
            if (tabuleiro[0][i] == ad && tabuleiro[1][i] == ad) 
                if (!update_tabuleiro(2, i)) return;
        }

        // para as diagonais
        if (tabuleiro[0][0] == ad && tabuleiro[2][2] == ad) 
            if (!update_tabuleiro(1, 1)) return;
        if (tabuleiro[0][2] == ad && tabuleiro[2][0] == ad) 
            if (!update_tabuleiro(1, 1)) return;
        if (tabuleiro[0][2] == ad && tabuleiro[1][1] == ad) 
            if (!update_tabuleiro(2, 0)) return;
        if (tabuleiro[2][2] == ad && tabuleiro[1][1] == ad) 
            if (!update_tabuleiro(0, 0)) return;
        if (tabuleiro[2][0] == ad && tabuleiro[1][1] == ad) 
            if (!update_tabuleiro(0, 2)) return;
        if (tabuleiro[0][0] == ad && tabuleiro[1][1] == ad) 
            if (!update_tabuleiro(2, 2)) return;
    }

    // caso nenhum dos testes acima sejam satisfeitos, a cpu joga aleatoriamente

    srand(time(NULL));

    while(1) {
        x = rand() % 3;
        y = rand() % 3;
        if (!update_tabuleiro(x,y)) return;
    }
}

int testa_vencedor() {
    register int i;
    int a = (jogador == CPU) ? 1 : 2; // 'a' varia de acordo com quem o chama

    for (i = 0; i < 3; i++)
        if (tabuleiro[i][0] == a && tabuleiro[i][1] == a && tabuleiro[i][2] == a) return a;
    for (i = 0; i < 3; i++)
        if (tabuleiro[0][i] == a && tabuleiro[1][i] == a && tabuleiro[2][i] == a) return a;

    if (tabuleiro[2][0] == a && tabuleiro[1][1] == a && tabuleiro[0][2] == a) return a;
    if (tabuleiro[0][0] == a && tabuleiro[1][1] == a && tabuleiro[2][2] == a) return a;

    return 0;
}

Written by rntreis

abril 14, 2012 at 11:18 am

Publicado em C, jogos, programação