Desenvolver Jogo da Velha em Java contra Computador com três níveis de dificuldade

Bom dia. Alguém poderia me ajudar em relação ao código? Preciso implementar as jogadas do computador, no momento, só consigo efetuar a jogadas do usuário (marcação X), minha ideia era que a cada jogada do usuário, a próxima seria do Computador, por exemplo: preencher espaços que não foram preenchidos, etc.(precisa ter 3 níveis de dificuldade, de jogadas), e assim, sucessivamente. Segue o código abaixo:

import java.util.Scanner;

public class Jogo {
	//Vai desenhar o tabuleiro
    static char [][] tab = {{'_', '|','_','|','_'} , {'_', '|','_','|','_'} , {' ', '|',' ','|',' '}};
	
	public static void main(String[] args) {
		
		//Chama método JogadorHumano e passa parâmetro tab Jogo para iniciar jogo 
		JogadorHumano(tab);
		JogadorHumano(tab);
	}
	
	//Método para verificar marcação da jogada, posição, int posicaoMarcada para verificar se já foi marcada
	//char [][] tabuleirojogo vai verificar tabuleiro
	//Método boolean para retornar true ou false
	public static boolean VerificaEspacoPreenchido(int posicaoMarcada, char [][] tabuleiroJogo) {
		
		//Estrututa Switch para verificar posição, qual posição foi maracada, posso mudar essa estrutura para if/else
		switch(posicaoMarcada){
			case 1: 
			//Verifica se a posição 1 está preenchida
			if(tabuleiroJogo[0][0] == '_') {
				//Bolean será true, retonando que não está preenchido
				return true;
			}
			//Se tiver preenchida retorna false
			else {
				return false;
			}
			case 2: 
				if(tabuleiroJogo[0][2] == '_') {
					
					return true;
				}
				
				else {
					return false;
				}
				
			case 3: 
				if(tabuleiroJogo[0][4] == '_') {
					
					return true;
				}
				
				else {
					return false;
				}
			case 4: 
				if(tabuleiroJogo[1][0] == '_') {
					
					return true;
				}
				
				else {
					return false;
				}
			case 5: 
				if(tabuleiroJogo[1][2] == '_') {
					
					return true;
				}
				
				else {
					return false;
				}
			case 6: 
				if(tabuleiroJogo[1][4] == '_') {
					
					return true;
				}
				
				else {
					return false;
				}
			case 7: 
				if(tabuleiroJogo[2][0] == ' ') {//''Espaço vazio
					
					return true;
				}
				
				else {
					return false;
				}
			case 8: 
				if(tabuleiroJogo[2][2] == ' ') {
					
					return true;
				}
				
				else {
					return false;
				}
			case 9: 
				if(tabuleiroJogo[2][4] == ' ') {
					
					return true;
				}
				
				else {
					return false;
				}
				default:
					return false;
		}
	}
	
	
	//Essa pode ser a classe que vai imprimi o tabuleiro
	//Deifine método array passando com  parâmetro nome do mesmo
	public static void ImprimiTabuleiro(char[][] tabuleiroJogo) { //Vai exibir tabuleiro
		
		for (char[] linha : tabuleiroJogo) {
			for(char c : linha) {
				System.out.print(c);
			}
			System.out.println();
		}
	}//Separar essa parte do código em outra classe
	
	
	//Método para fazer as jogadas do computador após cada jogada do Jogador Humano, deve inserir em uma posição que não está preenchida
	public static void JogadorComputador(char [][] tabuleiroJogo) {
		
		
	}
	
	//Métod para as jogadas do jogador humano, pega o que foi digitado no teclado e substitui no tabuleiro
	public static void JogadorHumano(char [][] tabuleiroJogo) {
		//System.out.print("*** Jogo da Velha ***");
		System.out.println();
		ImprimiTabuleiro(tab);
		System.out.println("Jogador Humano, digite um opção de 1 a 9 para inserir no tabuleiro:");
		//Pega o que foi digitado no teclado
		Scanner teclado = new Scanner(System.in);
		//Variável para ler posição
		int posicao = teclado.nextInt();
		JogadorComputador(tab);
		//Guarda resultado do retorno do método na variável verif do tipo booleana
		boolean verif = VerificaEspacoPreenchido(posicao, tabuleiroJogo);
		//Enquanto for diferente de true fica nesse loop dizendo que é jogado que está sendo efetuada é inválida
		//Só sai desse loop até efetuar uma jogada valida
		while(verif != true) {
			System.out.println("A jogado efetuada é inválida!");
			System.out.println("Digite uma nova opção:");
			//Lê nova jogada efetuada
			posicao = teclado.nextInt();
			//Verifica a jogada
			verif = VerificaEspacoPreenchido(posicao, tabuleiroJogo);
		}
		//Chama método e passa os parâmetros posicao, que é digitado pelo usuário, Jogador Humano, e o tabuleiroJogo
		//Atualiza posição tabuleiro de acordo com que o usuário escolhe
		AtualizaTabuleiro(posicao, "Jogador Humano", tabuleiroJogo);
	}
	
	
	//pos: posição, jogador: representa jogador, tabuleiroJogo é o tabuleiro, pois precisamos alterar elementos
	public static void AtualizaTabuleiro(int pos, String jogador, char[][] tabuleiroJogo) {
		//Método para mudar as posições vazias do tabuleiro(com underline) pelas marcações, jogador humano X
		//jogador computador O
		char marcacao = ' ';//Vazia, preenchida de acordo com marcação: X ou O
		//Verifica jogador é Humano e efetua a marcação X
		if( jogador == "Jogador Humano") {
			marcacao = 'X';//Marca X Jogador Humano
		}
		// Verificar jogador é o Computador e efetua a marcação O
		else if(jogador == "Jogador Computador") {
			marcacao = 'O';//Marca O Jogador Computador
		}
		
		//Posso fazer está estrutura que verifica posições indices utilizando if/else
		switch (pos) {
		//Se a posição for igual a 1
		case 1:
			tabuleiroJogo[0][0] = marcacao;
			break;
			
		case 2:
			tabuleiroJogo[0][2] = marcacao;
			break;
			
		case 3:
			tabuleiroJogo[0][4] = marcacao;
			break;
			
		case 4:
			tabuleiroJogo[1][0] = marcacao;
			break;
			
		case 5:
			tabuleiroJogo[1][2] = marcacao;
			break;
			
		case 6:
			tabuleiroJogo[1][4] = marcacao;
			break;
			
		case 7:
			tabuleiroJogo[2][0] = marcacao;
			break;
			
		case 8:
			tabuleiroJogo[2][2] = marcacao;
			break;
			
		case 9:
			tabuleiroJogo[2][4] = marcacao;
			break;
			
		default:
			break;
		}
		ImprimiTabuleiro(tab);
	}
	
}

Exemplo para implementar computador:

public static void JogadorComputadorNivel1(char [][] tabuleiroJogo) {
  int posicao = (int)(Math.random() * 9) + 1;
  boolean verif = VerificaEspacoPreenchido(posicao, tabuleiroJogo);
  while(verif != true) {
    posicao = (int)(Math.random() * 9) + 1;
    verif = VerificaEspacoPreenchido(posicao, tabuleiroJogo);
  }
}

No JogadorHumano, eu removeria a linha “JogadorComputador(tab);” e colocaria no main:

public static void main(String[] args) {
  // depois aterar para verificar fim do jogo
  for (int i = 0; i < 9; i++) {
    // se i for impar, vez do computador
    if (i % 2 == 1) {
      JogadorComputadorNivel1(tab);
    } else {
      JogadorHumano(tab);
    }
  }
}

Bom dia, @DlEGO, então consegui preencher os espaços vazio, de forma sequencial, depois de cada jogada do usuário, em outro nivel, coloquei para preencher diagonal primeiro, etc. Mas vou tentar dessa forma que você mostrou também. Você poderia me orientar nessa outra dúvida?

Como eu faço pra chamar um método, e repetir ele quantas vezes quiser juntamente com outro, um após o outro, por exemplo.:Sem precisar fazer essas repetições métodos no código abaixo, chama um de cada vez, mas sem ser desse jeito que está:

if(nivel == 1){
JogadorHumano(tab);

JogadorComputadorA(tab);

JogadorHumano(tab);

JogadorComputadorA(tab);

    JogadorHumano(tab);
   
    JogadorComputadorA(tab);
   
    JogadorHumano(tab);
   
    JogadorComputadorA(tab);
   
    JogadorHumano(tab);
    }
while (jogoNaoAcabou) {
    umJogadorJoga();
    if (jogoNaoAcabou) {
        outroJogadorJoga();
    }
}

Boa noite, @DlEGO pode me auxiliar nessa parte? Agora preciso implementar algo para verificar quem venceu, jogador ou computador, ou se empatou. Tentei fazer algo assim, mas não deu:

public static void VerificaVencedor(char[][] tabuleiroJogo){
  int computador = -1;
  int jogador = 1;
  if(tabuleiroJogo[0][0] == 1 && tabuleiroJogo[0][2] == 1 && tabuleiroJogo[0][4] == 1){
    System.out.println("Jogador Venceu");
  }
}
}

Vc fez a marcação em “X/O” e não “1/-1”.

// retorna true se venceu
public static boolean VerificaVencedor(char[][] tabuleiroJogo, char marcacao){

e chamaria assim

// verificar computador venceu
if (VerificaVencedor(tabuleiroJogo, 'O')) {

Bom dia, @DlEGO é verdade, tentei incluir esse 1/-1 sem necessidade. Mas consegui fazer dessa forma abaixo, mas como eu poderia diminuir essas linhas de códigos, esses if/else? Segue o código:

public static boolean VerificaVencedor(char[][] tabuleiroJogo){
    //Verifica X
    //Vertical
    if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[1][0] == 'X' && tabuleiroJogo [2][0] == 'X'){
        System.out.println("'X' Jogador Humano VENCEU");
        return true;
    }
     else if(tabuleiroJogo[1][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[1][4] == 'X'){
        System.out.println("'X' VENCEU");
        return true;
     }
     else if(tabuleiroJogo[2][0] == 'X' && tabuleiroJogo[2][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
        System.out.println("'X' Jogador Humano VENCEU");
        return true;
    }

     //Horizontal
     else if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[0][2] == 'X' && tabuleiroJogo[0][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    else if(tabuleiroJogo[1][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[1][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    } 
    else if(tabuleiroJogo[2][0] == 'X' && tabuleiroJogo[2][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    //Diagonal
    else if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[2][0] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    //Verifica O
    //Vertical
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[1][0] == 'O' && tabuleiroJogo[2][0] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][2] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][2] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'O' && tabuleiroJogo[1][4] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }

    //Horizontal
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[0][2] == 'O' && tabuleiroJogo[0][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[1][0] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[1][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[2][0] == 'O' && tabuleiroJogo[2][2] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }

    //Diagonal
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][0] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true; 
    }

    return false;
}
}

Se passar a marcação por parâmetro, é possível reduzir pela metade o número de ifs:

public static boolean VerificaVencedor(char[][] tabuleiroJogo, char marcacao){
    //Verifica marcacao
    //Vertical
    if(tabuleiroJogo[0][0] == marcacao && tabuleiroJogo[1][0] == marcacao && tabuleiroJogo [2][0] == marcacao){
        System.out.println("'" + marcacao + "' VENCEU");
        return true;
    }

outra forma é usando loops

// verifica todas as verticais
for (int coluna = 0, coluna < 6; coluna += 2) {
  if(tabuleiroJogo[0][coluna] == 'X' && tabuleiroJogo[1][coluna] == 'X' && tabuleiroJogo [2][coluna] == 'X'){
      System.out.println("'X' Jogador Humano VENCEU");
      return true;
  }
}

Boa tarde, @DlEGO Obrigado! Vou tentar dessas duas formas também. Outra coisa, já implementei quase tudo…e agora a questão do empate, como faço pra mostrar esse retorno na tela tentei de algumas formas aqui, mas não ficou muito bom. Segue as linhas de código do main e do método VerificaVencedor abaixo:

public static void main(String[] args) {
		
		System.out.println("Escolha o nível de dificuldade 1, 2 ou 3:");
		Scanner nDificuldade = new Scanner(System.in);
		int nivel = nDificuldade.nextInt();
		//int opcao = nivel;
		//while(nivel >= 4 || nivel == 0)
		while(nivel < 1 || nivel > 4){
		  System.out.println("Opção inválida, escolha a dificuldade 1, 2 ou 3:");
		  nivel = nDificuldade.nextInt();
}
		int jogoNaoAcabou = 1;
		while (jogoNaoAcabou <= 5) {
		
    JogadorHumano(tab);
    jogoNaoAcabou ++;
    
    if (nivel == 1) {
    
        JogadorComputadorA(tab);
    }
    else if (nivel == 2){
        JogadorComputadorB(tab);
    }
    
    if(VerificaVencedor(tab)){
      break;
    }
}


public static boolean VerificaVencedor(char[][] tabuleiroJogo){
    //Verifica X
    //Vertical
    if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[1][0] == 'X' && tabuleiroJogo [2][0] == 'X'){
        System.out.println("'X' Jogador Humano VENCEU");
        return true;
    }
     else if(tabuleiroJogo[1][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[1][4] == 'X'){
        System.out.println("'X' VENCEU");
        return true;
     }
     else if(tabuleiroJogo[2][0] == 'X' && tabuleiroJogo[2][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
        System.out.println("'X' Jogador Humano VENCEU");
        return true;
    }

     //Horizontal
     else if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[0][2] == 'X' && tabuleiroJogo[0][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    else if(tabuleiroJogo[1][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[1][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    } 
    else if(tabuleiroJogo[2][0] == 'X' && tabuleiroJogo[2][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    //Diagonal
    else if(tabuleiroJogo[0][0] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[2][4] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'X' && tabuleiroJogo[1][2] == 'X' && tabuleiroJogo[2][0] == 'X'){
    System.out.println("'X' Jogador Humano VENCEU");
    return true;
    }
    //Verifica O
    //Vertical
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[1][0] == 'O' && tabuleiroJogo[2][0] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][2] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][2] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'O' && tabuleiroJogo[1][4] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }

    //Horizontal
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[0][2] == 'O' && tabuleiroJogo[0][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[1][0] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[1][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[2][0] == 'O' && tabuleiroJogo[2][2] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }

    //Diagonal
    if(tabuleiroJogo[0][0] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][4] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true;
    }
    else if(tabuleiroJogo[0][4] == 'O' && tabuleiroJogo[1][2] == 'O' && tabuleiroJogo[2][0] == 'O'){
    System.out.println("'O' Computador VENCEU");
    return true; 
    }
    
    
    return false;
    
}
}