Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.

Archivo del blog

lunes, 8 de julio de 2024

Juegos IV.2. Tres en Raya (GUI).

Esta versión del código crea una interfaz gráfica para el juego de tres en raya con las siguientes características:

1- Usa una imagen para representar el tablero.
2- Los jugadores hacen clic directamente en las casillas para realizar sus jugadas.
3- Las X's y O's se dibujan en el tablero con diferentes colores.
4- Detecta automáticamente cuando hay un ganador o un empate.
5- Muestra mensajes de victoria o empate y reinicia el juego.


Código Java (TresEnRayaGUI.java):

package tresenrayagui;

import javax.swing.*;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;

public class TresEnRayaGUI extends JFrame {

    private static final int CELL_SIZE = 100;
    private static final int BOARD_SIZE = 3;
    private static final int WINDOW_WIDTH = CELL_SIZE * BOARD_SIZE + 40;
    private static final int WINDOW_HEIGHT = CELL_SIZE * BOARD_SIZE + 160;

    private final char[][] tablero = new char[BOARD_SIZE][BOARD_SIZE];
    private char jugadorActual = 'X';
    private final JPanel boardPanel;
    private final JLabel turnoLabel;
    private final JLabel puntajeLabel;
    private int puntosX = 0, puntosO = 0;

    public TresEnRayaGUI() {
        setTitle("Tres en Raya");
        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setLocationRelativeTo(null);

        // Panel de información mejorado
        JPanel infoPanel = new JPanel(new GridLayout(2, 1, 0, 5));
        infoPanel.setBackground(new Color(230, 230, 250));
        infoPanel.setBorder(new CompoundBorder(
                new LineBorder(new Color(100, 100, 100), 2),
                new EmptyBorder(10, 10, 10, 10)
        ));

        Font mathFont = new Font("Cambria Math", Font.BOLD, 18);
        if (mathFont.getFamily().equals("Dialog")) {
            mathFont = new Font("Arial", Font.BOLD, 18);
        }

        turnoLabel = new JLabel("Turno del jugador: X", SwingConstants.CENTER);
        turnoLabel.setFont(mathFont);
        puntajeLabel = new JLabel("X: 0 | O: 0", SwingConstants.CENTER);
        puntajeLabel.setFont(mathFont);

        infoPanel.add(turnoLabel);
        infoPanel.add(puntajeLabel);
        add(infoPanel, BorderLayout.NORTH);

        inicializarTablero();

        boardPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                dibujarTablero(g);
            }
        };
        boardPanel.setPreferredSize(new Dimension(CELL_SIZE * BOARD_SIZE, CELL_SIZE * BOARD_SIZE));
        boardPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int col = e.getX() / CELL_SIZE;
                int row = e.getY() / CELL_SIZE;
                realizarJugada(row, col);
            }
        });

        JPanel centerPanel = new JPanel(new GridBagLayout());
        centerPanel.setBackground(new Color(230, 230, 250));
        centerPanel.add(boardPanel);

        add(centerPanel, BorderLayout.CENTER);
    }

    private void inicializarTablero() {
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                tablero[i][j] = ' ';
            }
        }
    }

    private void dibujarTablero(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // Dibujar fondo degradado
        GradientPaint gp = new GradientPaint(0, 0, new Color(200, 220, 240), CELL_SIZE * BOARD_SIZE, CELL_SIZE * BOARD_SIZE, new Color(220, 240, 255));
        g2d.setPaint(gp);
        g2d.fillRect(0, 0, CELL_SIZE * BOARD_SIZE, CELL_SIZE * BOARD_SIZE);

        // Dibujar líneas del tablero
        g2d.setColor(new Color(100, 100, 100));
        g2d.setStroke(new BasicStroke(2));
        for (int i = 1; i < BOARD_SIZE; i++) {
            g2d.drawLine(i * CELL_SIZE, 0, i * CELL_SIZE, BOARD_SIZE * CELL_SIZE);
            g2d.drawLine(0, i * CELL_SIZE, BOARD_SIZE * CELL_SIZE, i * CELL_SIZE);
        }

        // Dibujar X y O
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (tablero[i][j] == 'X') {
                    dibujarX(g2d, j * CELL_SIZE, i * CELL_SIZE);
                } else if (tablero[i][j] == 'O') {
                    dibujarO(g2d, j * CELL_SIZE, i * CELL_SIZE);
                }
            }
        }
    }

    private void dibujarX(Graphics2D g2d, int x, int y) {
        g2d.setColor(new Color(220, 20, 60));
        g2d.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2d.draw(new Line2D.Double(x + 20, y + 20, x + CELL_SIZE - 20, y + CELL_SIZE - 20));
        g2d.draw(new Line2D.Double(x + CELL_SIZE - 20, y + 20, x + 20, y + CELL_SIZE - 20));
    }

    private void dibujarO(Graphics2D g2d, int x, int y) {
        g2d.setColor(new Color(30, 144, 255));
        g2d.setStroke(new BasicStroke(4));
        g2d.draw(new Ellipse2D.Double(x + 20, y + 20, CELL_SIZE - 40, CELL_SIZE - 40));
    }

    private void realizarJugada(int row, int col) {
        if (tablero[row][col] == ' ') {
            tablero[row][col] = jugadorActual;
            boardPanel.repaint();
            if (verificarGanador(row, col)) {
                if (jugadorActual == 'X') {
                    puntosX++;
                } else {
                    puntosO++;
                }
                JOptionPane.showMessageDialog(this, "¡El jugador " + jugadorActual + " ha ganado!");
                reiniciarJuego();
            } else if (tableroLleno()) {
                JOptionPane.showMessageDialog(this, "¡Empate!");
                reiniciarJuego();
            } else {
                jugadorActual = (jugadorActual == 'X') ? 'O' : 'X';
                actualizarInfoLabel();
            }
        }
    }

    private boolean verificarGanador(int row, int col) {
        return (tablero[row][0] == jugadorActual && tablero[row][1] == jugadorActual && tablero[row][2] == jugadorActual)
                || (tablero[0][col] == jugadorActual && tablero[1][col] == jugadorActual && tablero[2][col] == jugadorActual)
                || (row == col && tablero[0][0] == jugadorActual && tablero[1][1] == jugadorActual && tablero[2][2] == jugadorActual)
                || (row + col == 2 && tablero[0][2] == jugadorActual && tablero[1][1] == jugadorActual && tablero[2][0] == jugadorActual);
    }

    private boolean tableroLleno() {
        for (int i = 0; i < BOARD_SIZE; i++) {
            for (int j = 0; j < BOARD_SIZE; j++) {
                if (tablero[i][j] == ' ') {
                    return false;
                }
            }
        }
        return true;
    }

    private void reiniciarJuego() {
        inicializarTablero();
        jugadorActual = 'X';
        actualizarInfoLabel();
        boardPanel.repaint();
    }

    private void actualizarInfoLabel() {
        turnoLabel.setText("Turno del jugador: " + jugadorActual);
        puntajeLabel.setText("X: " + puntosX + " | O: " + puntosO);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TresEnRayaGUI().setVisible(true));
    }
}


Resultado:



jueves, 4 de julio de 2024

Juegos IV. Tres en Raya.


Código Java (TresEnRaya.java):

package tresenraya;

import java.util.Scanner;

public class TresEnRaya {

    private static final char[] JUGADORES = {'X', 'O'};
    private static final String LINEA_SUPERIOR = "  ╔═══╦═══╦═══╗";
    private static final String LINEA_MEDIA = "  ╠═══╬═══╬═══╣";
    private static final String LINEA_INFERIOR = "  ╚═══╩═══╩═══╝";

    private static final char[][] tablero = new char[3][3];
    private static final Scanner scanner = new Scanner(System.in);
    private static int jugadorActual = 0;

    public static void main(String[] args) {
        try (scanner) {
            while (true) {
                if (jugar()) {
                    break;
                }
            }
        }
    }

    private static boolean jugar() {
        inicializarTablero();
        while (true) {
            dibujarTablero();
            if (!realizarJugada()) {
                return false;
            }
            if (verificarGanador()) {
                dibujarTablero();
                System.out.println("¡El jugador " + JUGADORES[jugadorActual] + " ha ganado!");
                return true;
            }
            if (tableroLleno()) {
                dibujarTablero();
                System.out.println("¡Empate!");
                return true;
            }
            jugadorActual = 1 - jugadorActual;
        }
    }

    private static void inicializarTablero() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                tablero[i][j] = ' ';
            }
        }
    }

    private static void dibujarTablero() {
        System.out.println(LINEA_SUPERIOR);
        for (int i = 2; i >= 0; i--) {
            System.out.print((i + 1) + "-║");
            for (int j = 0; j < 3; j++) {
                System.out.print(" " + tablero[i][j] + " ║");
            }
            System.out.println();
            if (i > 0) {
                System.out.println(LINEA_MEDIA);
            }
        }
        System.out.println(LINEA_INFERIOR);
        System.out.println("    A   B   C");
    }

    private static boolean realizarJugada() {
        System.out.println("Jugador " + JUGADORES[jugadorActual] + ", ingresa coordenada: ");
        try {
            String entrada = scanner.nextLine().toUpperCase().trim();
            if (entrada.length() != 2) {
                throw new IllegalArgumentException();
            }

            int columna = entrada.charAt(0) - 'A';
            int fila = Character.getNumericValue(entrada.charAt(1)) - 1;

            if (fila < 0 || fila > 2 || columna < 0 || columna > 2 || tablero[fila][columna] != ' ') {
                System.out.println("Jugada inválida. Intenta de nuevo.");
                return true;
            }
            tablero[fila][columna] = JUGADORES[jugadorActual];
            return true;
        } catch (IllegalArgumentException e) {
            System.out.println("Entrada inválida. ¿Deseas salir? (s/n)");
            return !scanner.nextLine().trim().equalsIgnoreCase("s");
        }
    }

    private static boolean verificarGanador() {
        for (int i = 0; i < 3; i++) {
            if (tablero[i][0] != ' ' && tablero[i][0] == tablero[i][1] && tablero[i][1] == tablero[i][2]) {
                return true;
            }
            if (tablero[0][i] != ' ' && tablero[0][i] == tablero[1][i] && tablero[1][i] == tablero[2][i]) {
                return true;
            }
        }
        return (tablero[0][0] != ' ' && tablero[0][0] == tablero[1][1] && tablero[1][1] == tablero[2][2])
                || (tablero[0][2] != ' ' && tablero[0][2] == tablero[1][1] && tablero[1][1] == tablero[2][0]);
    }

    private static boolean tableroLleno() {
        for (char[] fila : tablero) {
            for (char celda : fila) {
                if (celda == ' ') {
                    return false;
                }
            }
        }
        return true;
    }
}


Resultado:

run:
  ╔═══╦═══╦═══╗
3-║   ║   ║   ║
  ╠═══╬═══╬═══╣
2-║   ║   ║   ║
  ╠═══╬═══╬═══╣
1-║   ║   ║   ║
  ╚═══╩═══╩═══╝
    A   B   C
Jugador X, ingresa coordenada:
b1
  ╔═══╦═══╦═══╗
3-║   ║   ║   ║
  ╠═══╬═══╬═══╣
2-║   ║   ║   ║
  ╠═══╬═══╬═══╣
1-║   ║ X ║   ║
  ╚═══╩═══╩═══╝
    A   B   C
Jugador O, ingresa coordenada:
b2
  ╔═══╦═══╦═══╗
3-║   ║   ║   ║
  ╠═══╬═══╬═══╣
2-║   ║ O ║   ║
  ╠═══╬═══╬═══╣
1-║   ║ X ║   ║
  ╚═══╩═══╩═══╝
    A   B   C
Jugador X, ingresa coordenada:
c3
  ╔═══╦═══╦═══╗
3-║   ║   ║ X ║
  ╠═══╬═══╬═══╣
2-║   ║ O ║   ║
  ╠═══╬═══╬═══╣
1-║   ║ X ║   ║
  ╚═══╩═══╩═══╝
    A   B   C
Jugador O, ingresa coordenada:
 

martes, 2 de julio de 2024

Generación de laberintos I.2. Algoritmo de Aldous-Broder.

El Algoritmo de Aldous-Broder es otro método para generar un laberinto aleatorio. Funcionamiento para la generación es el siguiente:

    1. Comenzar en un vértice aleatorio del grafo.
    2. Elegir un vecino aleatorio del vértice actual.
    3. Si el vecino no ha sido visitado, añadir la arista entre el vértice actual y el vecino al árbol de expansión.
    4. Moverse al vecino elegido (sea visitado o no).
    5. Repetir los pasos 2-4 hasta que todos los vértices hayan sido visitados.

Este algoritmo es simple pero ineficiente, especialmente para grafos grandes, ya que puede tomar mucho tiempo para visitar todos los vértices.

 

Código (AldousBroderMaze.java):

package aldousbrodermaze;

import java.util.*;

public class AldousBroderMaze {

    private static final int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    private final int width;
    private final int height;
    private final boolean[][] maze;

    public AldousBroderMaze(int width, int height) {
        this.width = width;
        this.height = height;
        this.maze = new boolean[height * 2 + 1][width * 2 + 1];
    }

    public void generateMaze() {
        Random rand = new Random();
        int x = rand.nextInt(width) * 2 + 1;
        int y = rand.nextInt(height) * 2 + 1;
        int unvisited = width * height - 1;

        maze[y][x] = true;

        while (unvisited > 0) {
            int[] direction = DIRECTIONS[rand.nextInt(DIRECTIONS.length)];
            int newX = x + direction[0] * 2;
            int newY = y + direction[1] * 2;

            if (newX > 0 && newX < maze[0].length && newY > 0 && newY < maze.length) {
                if (!maze[newY][newX]) {
                    maze[newY][newX] = true;
                    maze[y + direction[1]][x + direction[0]] = true;
                    unvisited--;
                }
                x = newX;
                y = newY;
            }
        }
    }

    public void printMaze() {
        for (boolean[] row : maze) {
            for (boolean cell : row) {
                System.out.print(cell ? "  " : "██");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        AldousBroderMaze maze = new AldousBroderMaze(10, 10);
        maze.generateMaze();
        maze.printMaze();
    }
}


Resultado:

run:
██████████████████████████████████████████
██              ██  ██      ██          ██
██  ██████████████  ██████  ██  ██████████
██              ██      ██  ██      ██  ██
██  ██  ██████████████  ██  ██  ██████  ██
██  ██      ██          ██  ██          ██
██  ██████████████  ██████  ██  ██████  ██
██              ██  ██          ██  ██  ██
██  ██████████  ██  ██████  ██  ██  ██████
██  ██  ██              ██  ██      ██  ██
██  ██  ██████████████████  ██████  ██  ██
██          ██  ██      ██  ██          ██
██████████  ██  ██████  ██  ██  ██  ██████
██          ██  ██  ██      ██  ██      ██
██████████  ██  ██  ██████████  ██████████
██              ██      ██  ██      ██  ██
██████████████  ██  ██████  ██  ██████  ██
██                      ██  ██  ██      ██
██████████  ██  ██████  ██  ██  ██████  ██
██          ██  ██                      ██
██████████████████████████████████████████
BUILD SUCCESSFUL (total time: 0 seconds)


Con la tecnología de Blogger.