diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7dbf5d9..4e71c9a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -37,6 +37,7 @@ dependencies { implementation(libs.material) implementation(libs.activity) implementation(libs.constraintlayout) + implementation(libs.gridlayout) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) diff --git a/app/src/main/java/legion/muyue/best2048/Game.java b/app/src/main/java/legion/muyue/best2048/Game.java index dca2a48..ec41638 100644 --- a/app/src/main/java/legion/muyue/best2048/Game.java +++ b/app/src/main/java/legion/muyue/best2048/Game.java @@ -1,8 +1,9 @@ package legion.muyue.best2048; -import android.util.Log; import java.util.ArrayList; import java.util.Random; +import android.util.Log; + public class Game { @@ -15,6 +16,19 @@ public class Game { random = new Random(); } + public int getGameBoard(int x, int y) { + return gameBoard[x][y]; + } + + public int getScore() { + return score; + } + + public int getHighScore() { + return 0; // TODO: Implémentez la logique du meilleur score plus tard + } + + // La méthode printArray est toujours présente dans l'extrait de Game.java pour l'étape 8 public void printArray() { for (int[] row : gameBoard) { String rowString = String.format("%6d%6d%6d%6d%n", row[0], row[1], row[2], row[3]); @@ -132,36 +146,35 @@ public class Game { } public void pushLeft() { - Log.d("Game", "Pushing Left"); // Pour le débogage - boolean[] alreadyCombined = new boolean[4]; // Tableau par ligne cette fois + Log.d("Game", "Pushing Left"); + boolean[] alreadyCombined = new boolean[4]; - for (int x = 0; x < 4; x++) { // Itère sur les *lignes* d'abord - alreadyCombined = new boolean[4]; // Réinitialise pour chaque ligne - for (int y = 1; y < 4; y++) { // Itère sur les *colonnes*, en commençant par la deuxième + for (int x = 0; x < 4; x++) { + alreadyCombined = new boolean[4]; + for (int y = 1; y < 4; y++) { if (gameBoard[x][y] != 0) { int value = gameBoard[x][y]; - int currentY = y; // Suit la colonne + int currentY = y; - // Déplace vers la gauche while (currentY > 0 && gameBoard[x][currentY - 1] == 0) { currentY--; } - if (currentY == 0) { // Arrivé tout à gauche + if (currentY == 0) { gameBoard[x][0] = value; if(currentY != y) gameBoard[x][y] = 0; - } else if (gameBoard[x][currentY - 1] != value) { // Case à gauche différente + } else if (gameBoard[x][currentY - 1] != value) { gameBoard[x][currentY] = value; if(currentY != y) gameBoard[x][y] = 0; - } else if (!alreadyCombined[currentY - 1]) { // Case à gauche identique et non fusionnée - gameBoard[x][currentY - 1] *= 2; // Fusionne + } else if (!alreadyCombined[currentY - 1]) { + gameBoard[x][currentY - 1] *= 2; score += gameBoard[x][currentY - 1]; gameBoard[x][y] = 0; - alreadyCombined[currentY - 1] = true; // Marque comme fusionné - } else { // Case à gauche identique mais déjà fusionnée - gameBoard[x][currentY] = value; // Place à côté + alreadyCombined[currentY - 1] = true; + } else { + gameBoard[x][currentY] = value; if(currentY != y) gameBoard[x][y] = 0; } @@ -171,36 +184,35 @@ public class Game { } public void pushRight() { - Log.d("Game", "Pushing Right"); // Pour le débogage - boolean[] alreadyCombined = new boolean[4]; // Tableau par ligne + Log.d("Game", "Pushing Right"); + boolean[] alreadyCombined = new boolean[4]; - for (int x = 0; x < 4; x++) { // Itère sur les *lignes* - alreadyCombined = new boolean[4]; // Réinitialise pour chaque ligne. - for (int y = 2; y >= 0; y--) { // Itère sur les *colonnes*, de droite à gauche (avant-dernière vers première) + for (int x = 0; x < 4; x++) { + alreadyCombined = new boolean[4]; + for (int y = 2; y >= 0; y--) { if (gameBoard[x][y] != 0) { int value = gameBoard[x][y]; - int currentY = y; // Suit la colonne + int currentY = y; - // Déplace vers la droite while (currentY < 3 && gameBoard[x][currentY + 1] == 0) { currentY++; } - if (currentY == 3) { // Arrivé tout à droite + if (currentY == 3) { gameBoard[x][3] = value; if (currentY != y) gameBoard[x][y] = 0; - } else if (gameBoard[x][currentY + 1] != value) { // Case à droite différente + } else if (gameBoard[x][currentY + 1] != value) { gameBoard[x][currentY] = value; if(currentY != y) gameBoard[x][y] = 0; - } else if (!alreadyCombined[currentY + 1]) { // Case à droite identique et non fusionnée - gameBoard[x][currentY + 1] *= 2; // Fusionne + } else if (!alreadyCombined[currentY + 1]) { + gameBoard[x][currentY + 1] *= 2; score += gameBoard[x][currentY + 1]; gameBoard[x][y] = 0; - alreadyCombined[currentY + 1] = true; // Marque comme fusionné - } else { // Case à droite identique mais déjà fusionnée - gameBoard[x][currentY] = value; // Place à côté + alreadyCombined[currentY + 1] = true; + } else { + gameBoard[x][currentY] = value; if (currentY != y) gameBoard[x][y] = 0; } diff --git a/app/src/main/java/legion/muyue/best2048/MainActivity.java b/app/src/main/java/legion/muyue/best2048/MainActivity.java index 2572400..7a45c49 100644 --- a/app/src/main/java/legion/muyue/best2048/MainActivity.java +++ b/app/src/main/java/legion/muyue/best2048/MainActivity.java @@ -1,41 +1,154 @@ package legion.muyue.best2048; import android.os.Bundle; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; +import androidx.gridlayout.widget.GridLayout; public class MainActivity extends AppCompatActivity { + private GridLayout gameBoardLayout; + private TextView scoreTextView; + private TextView highScoreTextView; + private Game game; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); - Game game = new Game(); + gameBoardLayout = findViewById(R.id.gameBoard); + scoreTextView = findViewById(R.id.scoreLabel); + highScoreTextView = findViewById(R.id.highScoreLabel); - // Initialisation et tests des quatre directions - game.addNewNumbers(); - game.addNewNumbers(); - game.addNewNumbers(); - game.printArray(); // Grille initiale + game = new Game(); - game.pushUp(); - game.printArray(); // Après pushUp + initGameBoardLayout(); game.addNewNumbers(); - game.printArray(); // Avant pushDown - - game.pushDown(); - game.printArray(); // Après pushDown - game.addNewNumbers(); - game.printArray(); // Avant pushLeft - - game.pushLeft(); - game.printArray(); // Après pushLeft - game.addNewNumbers(); - game.printArray(); // Avant pushRight + updateUI(); - game.pushRight(); - game.printArray(); // Après pushRight + // Ajout des listeners de swipe + setupSwipeListener(); + } + private void initGameBoardLayout() { + gameBoardLayout.removeAllViews(); + gameBoardLayout.setColumnCount(4); + gameBoardLayout.setRowCount(4); + } + + private void updateUI() { + gameBoardLayout.removeAllViews(); // Efface les tuiles précédentes + + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 4; y++) { + TextView tileTextView = new TextView(this); + int value = game.getGameBoard(x, y); + + // Choisir le bon drawable en fonction de la valeur + int drawableId; + + switch (value) { + case 2: + drawableId = R.drawable.tile2; + break; + case 4: + drawableId = R.drawable.tile4; + break; + case 8: + drawableId = R.drawable.tile8; + break; + case 16: + drawableId = R.drawable.tile16; + break; + case 32: + drawableId = R.drawable.tile32; + break; + case 64: + drawableId = R.drawable.tile64; + break; + case 128: + drawableId = R.drawable.tile128; + break; + case 256: + drawableId = R.drawable.tile256; + break; + case 512: + drawableId = R.drawable.tile512; + break; + case 1024: + drawableId = R.drawable.tile1024; + break; + case 2048: + drawableId = R.drawable.tile2048; + break; + default: + drawableId = R.drawable.tile_empty; + break; + } + + tileTextView.setBackground(ContextCompat.getDrawable(this, drawableId)); + + // Afficher le texte uniquement si la valeur est > 0 + if (value > 0) { + tileTextView.setText(String.valueOf(value)); + // Adapte la taille du texte en fonction de la valeur. + tileTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, value < 128 ? 24 : (value < 1024 ? 20 : 16)); + + tileTextView.setTextColor(ContextCompat.getColor(this, R.color.text_tile_low)); + } + tileTextView.setGravity(Gravity.CENTER); + + GridLayout.LayoutParams params = new GridLayout.LayoutParams(); + params.width = 0; + params.height = 0; + params.rowSpec = GridLayout.spec(x, 1f); + params.columnSpec = GridLayout.spec(y, 1f); + params.setMargins(10, 10, 10, 10); // Marges codées en dur selon l'extrait + tileTextView.setLayoutParams(params); + + gameBoardLayout.addView(tileTextView); + } + } + + scoreTextView.setText("Score:\n" + game.getScore()); // Concaténation simple selon l'extrait + highScoreTextView.setText("High Score:\n" + game.getHighScore()); // Concaténation simple selon l'extrait + } + + private void setupSwipeListener() { + gameBoardLayout.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) { + @Override + public void onSwipeTop() { + game.pushUp(); + game.addNewNumbers(); + updateUI(); + } + + @Override + public void onSwipeBottom() { + game.pushDown(); + game.addNewNumbers(); + updateUI(); + } + + @Override + public void onSwipeLeft() { + game.pushLeft(); + game.addNewNumbers(); + updateUI(); + } + + @Override + public void onSwipeRight() { + game.pushRight(); + game.addNewNumbers(); + updateUI(); + } + }); } } \ No newline at end of file diff --git a/app/src/main/java/legion/muyue/best2048/OnSwipeTouchListener.java b/app/src/main/java/legion/muyue/best2048/OnSwipeTouchListener.java new file mode 100644 index 0000000..22f8171 --- /dev/null +++ b/app/src/main/java/legion/muyue/best2048/OnSwipeTouchListener.java @@ -0,0 +1,72 @@ +package legion.muyue.best2048; + +import android.content.Context; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +public class OnSwipeTouchListener implements View.OnTouchListener { + + private final GestureDetector gestureDetector; + + public OnSwipeTouchListener(Context ctx) { + gestureDetector = new GestureDetector(ctx, new GestureListener()); + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + return gestureDetector.onTouchEvent(event); + } + + private final class GestureListener extends GestureDetector.SimpleOnGestureListener { + + private static final int SWIPE_THRESHOLD = 100; + private static final int SWIPE_VELOCITY_THRESHOLD = 100; + + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + boolean result = false; + try { + float diffY = e2.getY() - e1.getY(); + float diffX = e2.getX() - e1.getX(); + if (Math.abs(diffX) > Math.abs(diffY)) { + if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { + if (diffX > 0) { + onSwipeRight(); + } else { + onSwipeLeft(); + } + result = true; + } + } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { + if (diffY > 0) { + onSwipeBottom(); + } else { + onSwipeTop(); + } + result = true; + } + } catch (Exception exception) { + exception.printStackTrace(); + } + return result; + } + } + + public void onSwipeRight() { + } + + public void onSwipeLeft() { + } + + public void onSwipeTop() { + } + + public void onSwipeBottom() { + } +} \ No newline at end of file