JavaRush /Blogue Java /Random-PT /Jogo Java para iniciantes
timurnav
Nível 21

Jogo Java para iniciantes

Publicado no grupo Random-PT
Olá amigos e futuros colegas! Jogo Java para iniciantes - 1Recentemente fiz um teste para participar de um projeto real, passei, mas aconteceu que por motivos pessoais não pude participar do próprio RP. Depois de problemas tão interessantes como o teste de RP, os problemas habituais do curso tornaram-se um passatempo menos atraente, especialmente porque eu já tinha resolvido a maioria deles. Portanto, para que meu talento não fosse desperdiçado para continuar aprendendo, decidi criar um web game multiplayer. Links para outros jogos:
  1. continuação deste artigo
  2. 2048
Tic Tac Toe parecia o jogo mais simples para mim, então decidi dividir a tarefa em uma série de subtarefas:
  1. Aplicativo de console para testar a lógica do jogo
  2. Multijogador
  3. Anexando um banco de dados de jogadores a um aplicativo de console
  4. Criação de design front-end, escrita de modelos de página, interface de jogo
  5. Juntando tudo
Existe a possibilidade de eu ser repreendido por tal sequência, e muito provavelmente todos os projetos sérios são construídos em uma sequência completamente diferente, responderei imediatamente, escreverei um post sobre isso “para iniciantes” para que todos (inclusive eu) posso aprender isso :) Bem. Vamos começar a escrever uma aplicação de console! Seguirei os mesmos passos dos grandes desafios de nível 20. O que há no jogo da velha?!
  1. campo
  2. dois jogadores que se revezam, um faz uma cruz e o segundo um zero. é simples.
Tornamos o campo um campo padrão 3x3. Como esse campo pode ser armazenado? a primeira opção é uma matriz bidimensional. Quais elementos esse array deve conter? A resposta é que precisamos pensar no que faremos com esses elementos, isso é exibir e comparar para encontrar o vencedor. Se os estivéssemos apenas exibindo-os na tela, então seria lógico mantê-los como uma string, então o próprio array e exibi-lo na tela em um loop ficaria mais ou menos assim:
String[][] strings = {{"O", "O", "_"},
                    {"_", "X", "O"},
                    {"X", "X", "X"},
for (String [] ss : strings){
    for (String s : ss) System.out.print(s + " ");
    System.out.println(); //для перевода строки
}
a tela exibiria:
O O _
_ X O
X X X
Mas além do display, temos também uma comparação de valores, e aqui as opções já são possíveis. Você pode comparar strings, pode criar uma classe de enumeração especial ( enum), mas eu preferiria comparar números e substituí-los por “X” e “O” somente quando exibidos na tela. Seja, por exemplo, 1 - "X", 2 - "O", 0 - "_". Então, como você verifica se há uma correspondência tripla X ou O em um campo?
O primeiro algoritmo está verificando todo o campo
int[][] canvas = {{00, 01, 02},
                 {10, 11, 12},
                 {20, 21, 22}}
Combinações vencedoras:
00-01-02, 10-11-12, 20-21-22, 00-10-20, 01-11-21, 02-12-22, 00-11-22, 20-11-02 — всего 8.
Verificando comparando números, mas acontece que você precisa verificar o campo INTEIRO, todas as 8 combinações, todas as vezes. Claro, isso não é muito, não se trata de uma busca por números de Armstrong na faixa de 0 a 1 bilhão, há pouco mais do que nenhum cálculo aqui, mas você ainda quer algo mais ideal do que verificar todo o campo. A segunda ideia que me veio foi verificar apenas a célula que estava marcada na jogada anterior, assim ainda poderemos determinar o vencedor, pois saberemos quem fez essa jogada. Assim, em vez de todas as 8 combinações, obtemos apenas 2, 3 ou 4 combinações, dependendo da célula, veja a imagem: Jogo Java para iniciantes - 2Agora precisamos descobrir como determinar qual combinação precisa ser iniciada? Foi aqui que percebi que usar um array bidimensional não é muito conveniente. Decidi considerar outras opções. A princípio tive a ideia de que o campo pode ser mantido em um número de nove dígitos, por exemplo, o mesmo campo que exibimos na tela pode ser escrito assim: 220012111, vou explicar nos dedos o que é é... O código é o mesmo, 1 - “X”, 2 - “O” , 0 – " ", o que significa 220012111 = "OO__XOXXX", ou se após cada terceiro dígito você inserir uma quebra de linha e adicionar espaços para clareza:
О О _
_ Х О
Х Х Х
aqui novamente, conveniente para armazenamento, foi inventado um dispositivo para exibição, mas inconveniente para comparação! A solução foi encontrada quando numerei as células de 1 a 9, então pensei, porque na programação a contagem regressiva começa em 0 e numerei como na foto. Jogo Java para iniciantes - 3Você não notou nenhuma peculiaridade? se você olhar a imagem acima, ficará claro que soluções com 2 combinações têm um número de série ímpar, 4 combinações têm o número de série 4, 3 combinações têm o resto. Então cheguei à conclusão de que é necessário manter o campo de jogo em uma matriz regular de números: simples iteração entre números, capacidade de comparação de acordo com o algoritmo escolhido, simples saída para a tela. Quanto ao próprio algoritmo de comparação. Vamos pela ordem: em todas as opções há uma verificação de linha e coluna, verificamos apenas elas. se a pesquisa não der resultado, verificamos o número da célula para par/ímpar, se for ímpar, então voltamos ao jogo, não adianta verificar mais, se for par, verificamos se esta célula está no diagonal esquerda, os números desta diagonal quando divididos por 4 têm resto 0. Se mentir, verificamos se há correspondências, se nenhuma correspondência for encontrada, então verificamos o número 4, se não, voltamos ao jogo, se sim, avançamos no código e retornamos o resultado da verificação da última diagonal. Provavelmente para uma pessoa despreparada isso é difícil de entender depois de ler o conjunto de letras acima, mas alguém pode dizer que tem muitas letras no próprio código, que pode ser mais simples, terei prazer em discutir isso. Já resolvemos o campo, agora precisamos lidar com dois usuários que se revezam e cada um deles tem seu sinal, X ou O. Na primeira etapa não temos nenhuma funcionalidade multiusuário, então o a maneira mais fácil seria usar os ícones um por um. X sempre faz o primeiro movimento, O sempre faz o segundo, depois X novamente e assim por diante. Ele implora para ser verificado ( true/false ), e se for verdadeiro – então o jogador atual é X, se for falso – então O e no início de cada movimento flag=!flag Resta receber de alguma forma um sinal dos jogadores sobre qual célula que eles escolherem. Aqui precisaremos de nossos inesquecíveis. BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); Os jogadores inserirão os números dos celulares no console e pressionar Enter fará um movimento. A célula correspondente ao número inserido mudará seu valor de 0 para 1 ou 2, dependendo do estado atual da caixa de seleção, discutido no parágrafo acima. É aqui que é importante validar a entrada para que ninguém possa alterar X para O quando a célula já estiver preenchida :) O que o jogador pode inserir no console?
  1. linha vazia
  2. letras, sinais de pontuação, colchetes... em uma palavra, não números
  3. números incorretos - negativos ou fora do tamanho do array, células ocupadas.
O método padrão para obter um dígito de uma string é o método estático parseInt da classe Integer. Integer.parseInt("2");Ele lança uma exceção NumberFormatExceptionse não conseguir obter um dígito de uma determinada string. Podemos fornecer proteção dos dois primeiros pontos interceptando essa exceção. Para o terceiro ponto, eu criaria outro método que verifica o valor inserido, mas seria mais correto mover a solicitação de string para um método separado no qual a validação será realizada e retornará apenas um número. Para resumir, criamos um campo, fizemos um método que o exibe, fizemos um método que verifica “este jogador ganhou por uma hora?”, e validamos os números inseridos. Resta muito pouco a fazer, verificar se há empate - um método separado que percorre o array e procura 0 e exibe os resultados do jogo. Só isso, o código está pronto, o jogo acabou ficando pequeno, só uma classe, então copiadores durões podem, sem entender, apenas copiar tudo no projeto deles e rodar sozinho, eu mesmo era assim, mas agora procuro não fazer isso e não recomendo a ninguém :) Boa sorte a todos no aprendizado de JAVA! ps o resto dos pontos - multiplayer e banco de dados virão mais tarde, já comecei a estudar o material :)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class GameField {

    static int [] canvas = {0,0,0,
                            0,0,0,
                            0,0,0};

    //012, 345, 678, 036, 147, 258, 048, 246
    public static void main(String[] args){

        boolean b;
        boolean isCurrentX = false;
        do {
            isCurrentX = !isCurrentX;
            drawCanvas();
            System.out.println("mark " + (isCurrentX ? "X" : "O"));
            int n = getNumber();
            canvas[n] = isCurrentX ? 1 : 2;
            b = !isGameOver(n);
            if (isDraw()){
                System.out.println("Draw");
                return;
            }
        } while (b);
        drawCanvas();
        System.out.println();

        System.out.println("The winner is " + (isCurrentX ? "X" : "O") + "!");
    }

    static int getNumber(){
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true){
            try {
                int n = Integer.parseInt(reader.readLine());
                if (n >= 0 && n < canvas.length && canvas[n]==0){
                    return n;
                }
                System.out.println("Choose free cell and enter its number");
            } catch (NumberFormatException e) {
                System.out.println("Please enter the number");
            } catch (IOException e) {
            }
        }
    }

    static boolean isGameOver(int n){
        // 0 1 2
        // 3 4 5
        // 6 7 8
        //поиск совпадений по горизонтали
        int row = n-n%3; //номер строки - проверяем только её
        if (canvas[row]==canvas[row+1] &&
                canvas[row]==canvas[row+2]) return true;
        //поиск совпадений по вертикали
        int column = n%3; //номер столбца - проверяем только его
        if (canvas[column]==canvas[column+3])
            if (canvas[column]==canvas[column+6]) return true;
        //мы здесь, значит, первый поиск не положительного результата
        //если meaning n находится на одной из граней - возвращаем false
        if (n%2!=0) return false;
        //проверяем принадлежит ли к левой диагонали meaning
        if (n%4==0){
            //проверяем есть ли совпадения на левой диагонали
            if (canvas[0] == canvas[4] &&
                    canvas[0] == canvas[8]) return true;
            if (n!=4) return false;
        }
        return canvas[2] == canvas[4] &&
                canvas[2] == canvas[6];
    }

    static void drawCanvas(){
        System.out.println("     |     |     ");
        for (int i = 0; i < canvas.length; i++) {
            if (i!=0){
                if (i%3==0) {
                    System.out.println();
                    System.out.println("_____|_____|_____");
                    System.out.println("     |     |     ");
                }
                else
                    System.out.print("|");
            }

            if (canvas[i]==0) System.out.print("  " + i + "  ");
            if (canvas[i]==1) System.out.print("  X  ");
            if (canvas[i]==2) System.out.print("  O  ");
        }
        System.out.println();
        System.out.println("     |     |     ");
    }

    public static boolean isDraw() {
        for (int n : canvas) if (n==0) return false;
        return true;
    }
}
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION