Aula Ricardo

This commit is contained in:
2025-11-26 23:15:53 -03:00
commit 9d78ac4cc6
24 changed files with 1915 additions and 0 deletions

View File

@@ -0,0 +1,255 @@
package com.blackjack;
import com.blackjack.model.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.*;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class BlackjackApp extends Application {
// --- Estado do Jogo ---
private Baralho baralho;
private Mao maoJogador;
private Mao maoDealer;
private boolean jogoEmAndamento;
// --- Elementos de UI ---
private HBox containerCartasDealer;
private HBox containerCartasJogador;
private Label lblPontosDealer;
private Label lblPontosJogador;
private Label lblMensagem;
private Button btnPedir;
private Button btnParar;
private Button btnNovoJogo;
@Override
public void start(Stage stage) {
// Inicialização dos Modelos
baralho = new Baralho();
maoJogador = new Mao();
maoDealer = new Mao();
// --- Construção da Interface ---
// 1. Cabeçalho
Label titulo = new Label("BLACKJACK 21");
titulo.getStyleClass().add("titulo-principal");
// 2. Área do Dealer
lblPontosDealer = new Label("Dealer: 0");
lblPontosDealer.getStyleClass().add("titulo-area");
containerCartasDealer = new HBox(10);
containerCartasDealer.setAlignment(Pos.CENTER);
VBox areaDealer = new VBox(10, lblPontosDealer, containerCartasDealer);
areaDealer.getStyleClass().add("area-jogo");
// 3. Status do Jogo
lblMensagem = new Label("Bem-vindo!");
lblMensagem.getStyleClass().add("status-msg");
// 4. Área do Jogador
lblPontosJogador = new Label("Você: 0");
lblPontosJogador.getStyleClass().add("titulo-area");
containerCartasJogador = new HBox(10);
containerCartasJogador.setAlignment(Pos.CENTER);
VBox areaJogador = new VBox(10, lblPontosJogador, containerCartasJogador);
areaJogador.getStyleClass().add("area-jogo");
// 5. Controles
HBox controles = new HBox(20);
controles.setAlignment(Pos.CENTER);
controles.setPadding(new Insets(20));
btnPedir = new Button("PEDIR CARTA");
btnParar = new Button("PARAR (STAND)");
btnNovoJogo = new Button("NOVO JOGO");
// Ações dos Botões
btnPedir.setOnAction(e -> acaoPedirCarta());
btnParar.setOnAction(e -> acaoParar());
btnNovoJogo.setOnAction(e -> iniciarJogo());
controles.getChildren().addAll(btnPedir, btnParar, btnNovoJogo);
// --- Layout Principal ---
VBox root = new VBox(20);
root.setAlignment(Pos.TOP_CENTER);
root.setPadding(new Insets(20));
root.getChildren().addAll(titulo, areaDealer, lblMensagem, areaJogador, controles);
// Configuração da Cena
Scene scene = new Scene(root, 900, 700);
// Importante: Carregando o CSS
String css = getClass().getResource("/styles.css").toExternalForm();
scene.getStylesheets().add(css);
stage.setTitle("Blackjack Desktop - JavaFX");
stage.setScene(scene);
stage.show();
// Começar o primeiro jogo
iniciarJogo();
}
// --- Lógica do Jogo (Game Loop) ---
private void iniciarJogo() {
jogoEmAndamento = true;
baralho.reiniciar();
maoJogador.limpar();
maoDealer.limpar();
lblMensagem.setText("Sua vez. Pedir ou Parar?");
atualizarBotoes(true);
// Distribuição inicial
maoJogador.adicionar(baralho.comprar());
maoDealer.adicionar(baralho.comprar());
maoJogador.adicionar(baralho.comprar());
maoDealer.adicionar(baralho.comprar());
// Verifica Blackjack instantâneo
if (maoJogador.calcularPontuacao() == 21) {
finalizarJogo("Blackjack! Você venceu!");
}
atualizarMesa(false); // false = esconde a primeira carta do dealer
}
private void acaoPedirCarta() {
if (!jogoEmAndamento) return;
maoJogador.adicionar(baralho.comprar());
atualizarMesa(false);
if (maoJogador.calcularPontuacao() > 21) {
finalizarJogo("Você estourou! Dealer vence.");
}
}
private void acaoParar() {
if (!jogoEmAndamento) return;
// Vez do Dealer
while (maoDealer.calcularPontuacao() < 17) {
maoDealer.adicionar(baralho.comprar());
}
determinarVencedor();
}
private void determinarVencedor() {
int ptsJogador = maoJogador.calcularPontuacao();
int ptsDealer = maoDealer.calcularPontuacao();
// Atualiza mostrando a carta oculta
atualizarMesa(true);
if (ptsDealer > 21) {
finalizarJogo("Dealer estourou! Você venceu!");
} else if (ptsJogador > ptsDealer) {
finalizarJogo("Você venceu!");
} else if (ptsDealer > ptsJogador) {
finalizarJogo("Dealer venceu.");
} else {
finalizarJogo("Empate!");
}
}
private void finalizarJogo(String msg) {
jogoEmAndamento = false;
lblMensagem.setText(msg);
atualizarBotoes(false);
atualizarMesa(true); // Revela tudo no final
}
private void atualizarBotoes(boolean jogando) {
btnPedir.setDisable(!jogando);
btnParar.setDisable(!jogando);
btnNovoJogo.setDisable(jogando);
}
// --- Renderização Visual (O "DOM" do JavaFX) ---
private void atualizarMesa(boolean mostrarTudoDealer) {
// 1. Renderizar Jogador
containerCartasJogador.getChildren().clear();
for (Carta c : maoJogador.getCartas()) {
containerCartasJogador.getChildren().add(criarCartaVisual(c));
}
lblPontosJogador.setText("Você: " + maoJogador.calcularPontuacao());
// 2. Renderizar Dealer
containerCartasDealer.getChildren().clear();
var cartasD = maoDealer.getCartas();
for (int i = 0; i < cartasD.size(); i++) {
if (i == 0 && !mostrarTudoDealer) {
containerCartasDealer.getChildren().add(criarCartaVerso());
} else {
containerCartasDealer.getChildren().add(criarCartaVisual(cartasD.get(i)));
}
}
// Placar Dealer (esconde pontuação total se carta estiver oculta)
if (mostrarTudoDealer) {
lblPontosDealer.setText("Dealer: " + maoDealer.calcularPontuacao());
} else {
// Mostra pontuação apenas das cartas visíveis (a partir da segunda)
// Simplificação: mostra "?" ou recalcula sem a primeira
lblPontosDealer.setText("Dealer: ?");
}
}
// Cria o componente visual da carta (StackPane)
private StackPane criarCartaVisual(Carta carta) {
StackPane cardPane = new StackPane();
cardPane.getStyleClass().add("carta");
// Rank Topo Esquerdo
Label lblRankTop = new Label(carta.rank().display);
lblRankTop.getStyleClass().addAll("carta-texto", carta.nipe().corCss);
StackPane.setAlignment(lblRankTop, Pos.TOP_LEFT);
StackPane.setMargin(lblRankTop, new Insets(5));
// Naipe Centro
Label lblNaipe = new Label(carta.nipe().simbolo);
lblNaipe.getStyleClass().addAll("carta-naipe-grande", carta.nipe().corCss);
StackPane.setAlignment(lblNaipe, Pos.CENTER);
// Rank Base Direito (invertido opcionalmente, aqui normal)
Label lblRankBot = new Label(carta.rank().display);
lblRankBot.getStyleClass().addAll("carta-texto", carta.nipe().corCss);
StackPane.setAlignment(lblRankBot, Pos.BOTTOM_RIGHT);
StackPane.setMargin(lblRankBot, new Insets(5));
cardPane.getChildren().addAll(lblRankTop, lblNaipe, lblRankBot);
return cardPane;
}
private StackPane criarCartaVerso() {
StackPane cardPane = new StackPane();
cardPane.getStyleClass().addAll("carta", "carta-oculta");
Label inter = new Label("?");
inter.setStyle("-fx-text-fill: white; -fx-font-size: 30px;");
cardPane.getChildren().add(inter);
return cardPane;
}
public static void main(String[] args) {
launch();
}
}

View File

@@ -0,0 +1,7 @@
package com.blackjack;
public class Launcher {
public static void main(String[] args) {
BlackjackApp.main(args);
}
}

View File

@@ -0,0 +1,22 @@
package com.blackjack.model;
import java.util.Collections;
import java.util.Stack;
public class Baralho {
private final Stack<Carta> cartas = new Stack<>();
public void reiniciar() {
cartas.clear();
for (Nipe n : Nipe.values()) {
for (Rank r : Rank.values()) {
cartas.push(new Carta(n, r));
}
}
Collections.shuffle(cartas); // O shuffle do Java é mais otimizado que o manual
}
public Carta comprar() {
return cartas.isEmpty() ? null : cartas.pop();
}
}

View File

@@ -0,0 +1,8 @@
package com.blackjack.model;
public record Carta(Nipe nipe, Rank rank) {
@Override
public String toString() {
return rank.display + nipe.simbolo;
}
}

View File

@@ -0,0 +1,37 @@
package com.blackjack.model;
import java.util.ArrayList;
import java.util.List;
public class Mao {
private final List<Carta> cartas = new ArrayList<>();
public void adicionar(Carta c) {
cartas.add(c);
}
public void limpar() {
cartas.clear();
}
public List<Carta> getCartas() {
return cartas;
}
public int calcularPontuacao() {
int pontos = 0;
int ases = 0;
for (Carta c : cartas) {
pontos += c.rank().valorBase;
if (c.rank() == Rank.AS) ases++;
}
// Lógica do Ás: se estourar 21, conta como 1 (subtrai 10)
while (pontos > 21 && ases > 0) {
pontos -= 10;
ases--;
}
return pontos;
}
}

View File

@@ -0,0 +1,16 @@
package com.blackjack.model;
public enum Nipe {
COPAS("", "red"),
OUROS("", "red"),
PAUS("", "black"),
ESPADAS("", "black");
public final String simbolo;
public final String corCss;
Nipe(String simbolo, String corCss) {
this.simbolo = simbolo;
this.corCss = corCss;
}
}

View File

@@ -0,0 +1,16 @@
package com.blackjack.model;
public enum Rank {
DOIS("2", 2), TRES("3", 3), QUATRO("4", 4), CINCO("5", 5),
SEIS("6", 6), SETE("7", 7), OITO("8", 8), NOVE("9", 9),
DEZ("10", 10), VALETE("J", 10), DAMA("Q", 10), REI("K", 10),
AS("A", 11);
public final String display;
public final int valorBase;
Rank(String display, int valorBase) {
this.display = display;
this.valorBase = valorBase;
}
}

View File

@@ -0,0 +1,93 @@
.root {
-fx-background-color: #0a5c0a; /* Verde clássico */
-fx-font-family: 'Arial';
}
/* Títulos */
.titulo-principal {
-fx-text-fill: white;
-fx-font-size: 32px;
-fx-font-weight: bold;
-fx-padding: 20;
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.5), 5, 0, 0, 1);
}
.titulo-area {
-fx-text-fill: #ffc107; /* Dourado */
-fx-font-size: 18px;
-fx-font-weight: bold;
}
/* Container das Mãos (Areas) */
.area-jogo {
-fx-background-color: rgba(0, 0, 0, 0.2);
-fx-border-color: #ffc107;
-fx-border-width: 2;
-fx-border-radius: 10;
-fx-background-radius: 10;
-fx-padding: 20;
-fx-spacing: 15;
-fx-alignment: center;
-fx-min-width: 600;
}
/* A Carta Visual */
.carta {
-fx-background-color: white;
-fx-background-radius: 8;
-fx-border-color: #333;
-fx-border-radius: 8;
-fx-border-width: 1;
-fx-pref-width: 80;
-fx-pref-height: 120;
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 8, 0, 2, 2);
}
.carta-texto {
-fx-font-size: 18px;
-fx-font-weight: bold;
}
.carta-naipe-grande {
-fx-font-size: 36px;
}
.red { -fx-text-fill: #d90000; }
.black { -fx-text-fill: black; }
/* Carta Oculta (Verso) */
.carta-oculta {
-fx-background-color: linear-gradient(to bottom right, #444, #666);
-fx-background-radius: 8;
-fx-border-color: white;
-fx-border-width: 2;
-fx-border-style: solid;
}
/* Mensagem de Status */
.status-msg {
-fx-text-fill: white;
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-padding: 10;
}
/* Botões */
.button {
-fx-background-color: #ffc107;
-fx-text-fill: #333;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-background-radius: 5;
-fx-cursor: hand;
-fx-padding: 10 20;
}
.button:hover {
-fx-background-color: #ffd54f;
}
.button:disabled {
-fx-background-color: #999;
-fx-opacity: 0.7;
}