📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados na Especialização em Android Nativo. Recomendado revisar antes de iniciar.

🃏 P02: Jogo da Memória com Cartas PNG & Grid

v1.0 — Android Nativo, Java, GridLayout, ImageButton, Temporizadores com Handler e Lógica de Pares

Série Prática Android Clássico — Projeto 2 de 21


🏛️ Visão Geral & Arquitetura Visual

O Jogo da Memória Android desafia o raciocínio e a agilidade do jogador em uma grade de cartas embaralhadas aleatoriamente. O projeto aprofunda a manipulação de layouts matriciais (GridLayout), a troca dinâmica de imagens em ImageButton com estados de carta (verso e frente), e a orquestração assíncrona de temporizadores de desviramento através da classe android.os.Handler.

Arquitetura do Jogo da Memória Android
Tela do Jogo da Memória

📁 Estrutura de Pastas Anti-Colisão

Todos os recursos gráficos, sons e código Java residem na subpasta canônica mobile-android-xml/:

catalogo_projetos/android_p02_memoria_png/
├── assets/
│   ├── arquitetura_memoria_png.svg
│   ├── screenshot.png
│   ├── screenshot_8cards.png
│   └── screenshot_classic.png
├── mobile-android-xml/
│   ├── app/
│   │   ├── src/
│   │   │   └── main/
│   │   │       ├── java/br/com/curso/jogomemoria/
│   │   │       │   └── MainActivity.java
│   │   │       ├── res/
│   │   │       │   ├── drawable/
│   │   │       │   └── layout/activity_main.xml
│   │   │       └── AndroidManifest.xml
│   │   └── build.gradle
│   ├── gradle/
│   ├── build.gradle
│   ├── gradlew
│   ├── settings.gradle
│   └── README.md
└── index.md

🧑‍💼 Engenharia de Software & Especificação Formal

1. Histórias de Usuário (User Stories)

ID Persona Narrativa da Funcionalidade Critério de Aceitação Principal Prioridade
US-01 Jogador Quero tocar em uma carta para que ela vire e mostre sua face ilustrada. Abertura imediata da carta com feedback tátil e sonoro. Alta
US-02 Jogador Quero que duas cartas iguais permaneçam abertas e contem como um par descoberto. Fixação das cartas no tabuleiro e incremento do contador de pares encontrados. Alta
US-03 Jogador Quero que duas cartas diferentes voltem a ficar viradas para baixo após 1 segundo. Ação automática via Handler sem permitir toques intermediários indevidos. Alta
US-04 Jogador Quero ver meu tempo de jogo e número de tentativas para tentar bater recordes. Exibição de cronômetro contínuo e contador de movimentos na barra de status. Média
US-05 Desenvolvedor Quero que a distribuição de cartas mude a cada reinício de partida. Embaralhamento pseudo-aleatório através de Collections.shuffle(). Baixa

2. Requisitos do Sistema

Requisitos Funcionais (RF)

Requisitos Não-Funcionais (RNF)


3. Diagrama de Casos de Uso

flowchart TD
    Player([fa:fa-user Jogador])

    subgraph AppMemoria ["🃏 Jogo da Memória (mobile-android-xml)"]
        UC01["Iniciar Partida / Embaralhar"]
        UC02["Virar Primeira Carta"]
        UC03["Virar Segunda Carta"]
        UC04["Avaliar Correspondência de Par"]
        UC05["Finalizar Partida e Exibir Estatísticas"]
    end

    Player --> UC01
    Player --> UC02
    UC02 --> UC03
    UC03 --> UC04
    UC04 -->|Par Correto| UC05

4. Matriz de Rastreabilidade (RTM)

ID Requisito História de Usuário Artefato de Código Teste de Aceitação
RF-01 US-01 mobile-android-xml/app/src/main/res/layout/activity_main.xml testGridLayoutDimensions()
RF-02 US-05 mobile-android-xml/app/.../MainActivity.java testDeckShuffleContains8Pairs()
RF-03 US-01, US-02 mobile-android-xml/app/.../MainActivity.java testCardFlipStateMachine()
RF-04 US-03 mobile-android-xml/app/.../MainActivity.java testHandlerDelay1000ms()
RF-05 US-04 mobile-android-xml/app/.../MainActivity.java testVictoryDialogTrigger()

🛠️ Implementação Guiada (MainActivity.java)

📄 mobile-android-xml/app/src/main/java/br/com/curso/memoria/MainActivity.java (arquivo real do projeto)

package br.com.curso.memoria;

import android.os.Bundle;
import android.os.Handler;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ImageButton primeiraCarta = null;
    private ImageButton segundaCarta = null;
    private boolean aguardando = false;
    private int paresEncontrados = 0;
    private TextView txtStatus;
    
    private final List<ImageButton> cards = new ArrayList<>();
    private final List<String> tags = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txtStatus = findViewById(R.id.txt_status);
        Button btnReiniciar = findViewById(R.id.btn_reiniciar);
        btnReiniciar.setOnClickListener(v -> reiniciarJogo());

        // Inicializa as referências das 8 cartas
        cards.add(findViewById(R.id.card1));
        cards.add(findViewById(R.id.card2));
        cards.add(findViewById(R.id.card3));
        cards.add(findViewById(R.id.card4));
        cards.add(findViewById(R.id.card5));
        cards.add(findViewById(R.id.card6));
        cards.add(findViewById(R.id.card7));
        cards.add(findViewById(R.id.card8));

        // Inicializa as tags (4 pares = 8 cartas)
        tags.add("poke_pikachu");
        tags.add("poke_charmander");
        tags.add("poke_squirtle");
        tags.add("poke_bulbasaur");
        tags.add("poke_pikachu");
        tags.add("poke_charmander");
        tags.add("poke_squirtle");
        tags.add("poke_bulbasaur");

        iniciarJogo();
    }

    private void iniciarJogo() {
        paresEncontrados = 0;
        txtStatus.setText("Encontre os pares!");
        
        Collections.shuffle(tags);

        for (int i = 0; i < cards.size(); i++) {
            ImageButton card = cards.get(i);
            card.setTag(tags.get(i));
            card.setEnabled(true);
            card.setImageResource(R.drawable.card_back);
            card.setOnClickListener(v -> aoClicarNaCarta(card));
        }
    }
// … (+63 linhas: veja o arquivo completo no projeto)

🚀 Como Executar no Laboratório

1. Navegue até a subpasta do projeto

cd catalogo_projetos/android_p02_memoria_png/mobile-android-xml

2. Compile e execute no emulador ou dispositivo físico

./gradlew assembleDebug
./gradlew test

🏁 Matriz de Checkpoints de Conclusão

Checkpoint Meta Técnica Critério de Aceite Status
CP-01 Distribuição da Matriz Grade GridLayout 4x4 preenchida com cartas proporcionais PASS ✅
CP-02 Embaralhamento Aleatório Posições distintas a cada nova partida via Collections.shuffle PASS ✅
CP-03 Controle Assíncrono com Handler Desviramento temporizado sem travamento da thread principal PASS ✅
CP-04 Prevenção de Toques Múltiplos Flag booleana inibindo cliques concorrentes PASS ✅
CP-05 Suíte de Testes Automatizados Testes de unidade aprovados com 100% de sucesso PASS ✅