"Tag" ee Java - sida loo horumariyo ciyaar dhamaystiran

"Tag" ee Java - sida loo horumariyo ciyaar dhamaystiran

"Shan iyo toban" ama "Shan iyo toban" waa tusaale aad u wanaagsan ciyaar macquul ah oo fudud oo caan ka ah aduunka oo dhan. Si aad u xalliso halxiraalaha, waxaad u baahan tahay inaad habayso afar geesoodka oo leh nambaro isku xiga, mid yar ilaa kan ugu weyn. Ma fududa, laakiin waa mid xiiso leh.

Casharka maanta waxaan ku tusi doonaa sida loo horumariyo shan iyo toban Java 8 leh Eclipse. Si loo horumariyo UI waxaan isticmaali doonaa Swing API.

Waxaan xusuusineynaa: dhammaan akhristayaasha "Habr" - qiimo dhimis ah 10 rubles marka la qorayo koorso kasta oo Skillbox ah iyadoo la adeegsanayo koodhka xayeysiinta "Habr".

Skillbox waxay ku talinaysaa: Koorso online ah oo waxbarasho "Horumarinta Xirfadda Java".

Naqshadaynta ciyaarta

Marxaladdan waxaad u baahan tahay inaad qeexdo sifooyinka:

  • Cabbirka - cabbirka garoonka ciyaarta;
  • nbTiles - tirada tags ee goobta. nbTiles = cabbirka * cabbirka - 1;
  • Tiles waa sumad ka kooban hal-geesood oo kala duwan. Mid kasta oo ka mid ah sumadaha ayaa heli doona qiime gaar ah inta u dhaxaysa [0, nbTiles]. Eber waxa ay tilmaamaysaa afar geesoodka oo madhan;
  • blankPos - booska square madhan.

Ciyaarta macquulka ah

Waxaan u baahanahay inaan qeexno habka dib u dajinta loo isticmaalo in lagu bilaabo booska cusub ee ciyaarta. Sidan ayaanu u dejinaynaa qiimaha shay kasta oo ka mid ah array tags. Hagaag, ka dib waxaan dhignaa blankPos booska ugu dambeeya ee diyaarinta.

Waxaan sidoo kale u baahanahay habka isku shaandheynta si aan isku shaandheynno isku dhafka calaamadaha. Kuma darin summada madhan habka isku-shaandhaynta si aanu isla boos uga tagno.

Maaddaama kala badh ka mid ah meelaha suurtagalka ah ee bilawga ah ee halxiraalaha ay leeyihiin xal, waxaad u baahan tahay inaad hubiso natiijada isku shaandhaynta si aad u hubiso in qaabka hadda jira uu yahay mid la xallin karo. Si tan loo sameeyo, waxaan qeexeynaa habka isSolable.

Haddii calaamad gaar ah ay ka horreyso sumad leh qiime sare, waxaa loo arkaa rogaal celin. Marka meesha madhan ay taallo, tirada rogaal celisyadu waa inay ahaataa xitaa si halxiraalaha loo xalliyo. Markaa waxaanu tirinaynaa tirada rogaal celiska oo aanu run ku noqonaa haddii tiradu siman tahay.

Markaa waa muhiim in la qeexo habka is-Solved si loo hubiyo in Game Of Shan iyo Tobnaad gacanta lagu xalliyo. Marka hore waxaan eegaynaa meesha ay madhan tahay. Haddii booska hore, ka dibna toosinta hadda waa cusub, aan hore loo go'aamin. Ka dib waxaan ku celcelineynaa tiles-ka sida ay u kala horreeyaan, iyo haddii qiimaha sumadda uu ka duwan yahay tusaha u dhigma +1, waxaan ku celineynaa been. Haddii kale, dhamaadka habka waa waqtigii lagu noqon lahaa runta sababtoo ah halxiraalaha mar hore ayaa la xalliyay.

Habka kale ee u baahan in la qeexo waa newGame. Waxaa loo baahan yahay in la abuuro tusaale cusub oo ciyaarta ah. Si tan loo sameeyo, waxaan dib u dejineynaa garoonka ciyaarta, ka dibna isku shaandheyn oo sii wad ilaa booska ciyaarta la xalin karo.

Halkan waxaa ah kood kood oo leh macquulka muhiimka ah ee tag:

private void newGame() {
  do {
    reset(); // reset in initial state
    shuffle(); // shuffle
  } while(!isSolvable()); // make it until grid be solvable
 
  gameOver = false;
}
 
private void reset() {
  for (int i = 0; i < tiles.length; i++) {
    tiles[i] = (i + 1) % tiles.length;
  }
 
  // we set blank cell at the last
  blankPos = tiles.length - 1;
}
 
private void shuffle() {
  // don't include the blank tile in the shuffle, leave in the solved position
  int n = nbTiles;
 
  while (n > 1) {
    int r = RANDOM.nextInt(n--);
    int tmp = tiles[r];
    tiles[r] = tiles[n];
    tiles[n] = tmp;
  }
}
 
// Only half permutations of the puzzle are solvable/
// Whenever a tile is preceded by a tile with higher value it counts
// as an inversion. In our case, with the blank tile in the solved position,
// the number of inversions must be even for the puzzle to be solvable
private boolean isSolvable() {
  int countInversions = 0;
 
  for (int i = 0; i < nbTiles; i++) {
    for (int j = 0; j < i; j++) {
      if (tiles[j] > tiles[i])
        countInversions++;
    }
  }
 
  return countInversions % 2 == 0;
}
 
private boolean isSolved() {
  if (tiles[tiles.length - 1] != 0) // if blank tile is not in the solved position ==> not solved
    return false;
 
  for (int i = nbTiles - 1; i >= 0; i--) {
    if (tiles[i] != i + 1)
      return false;
  }
 
  return true;
}

Ugu dambeyntii, waxaad u baahan tahay inaad barnaamijka dhaqdhaqaaqa ee tags ee array. Koodhkan waxa loogu yeedhi doonaa hadhow iyada oo dib loo soo wacay si looga jawaabo dhaqdhaqaaqa cursor. Ciyaartayadu waxay taageeri doontaa dhaqdhaqaaqyo badan oo tile ah isku mar. Sidaa darteed, ka dib markii aan u beddelnay booska la riixay ee shaashadda ee tag, waxaan helnaa booska tagitaanka madhan oo aan raadino jihada dhaqdhaqaaqa si aan u taageerno dhowr dhaqdhaqaaqyadeeda isku mar.

Waa kan tusaale kood:

// get position of the click
int ex = e.getX() - margin;
int ey = e.getY() - margin;
 
// click in the grid ?
if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
  return;
 
// get position in the grid
int c1 = ex / tileSize;
int r1 = ey / tileSize;
 
// get position of the blank cell
int c2 = blankPos % size;
int r2 = blankPos / size;
 
// we convert in the 1D coord
int clickPos = r1 * size + c1;
 
int dir = 0;
 
// we search direction for multiple tile moves at once
if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
  dir = (r1 - r2) > 0 ? size : -size;
else if (r1 == r2 && Math.abs(c1 - c2) > 0)
  dir = (c1 - c2) > 0 ? 1 : -1;
 
if (dir != 0) {
  // we move tiles in the direction
  do {
    int newBlankPos = blankPos + dir;
    tiles[blankPos] = tiles[newBlankPos];
    blankPos = newBlankPos;
  } while(blankPos != clickPos);
 
tiles[blankPos] = 0;

Waxaan horumarinay UI anagoo adeegsanayna Swing API

Waa waqtigii laga shaqeyn lahaa interface-ka. Marka hore waxaan qaadanaa fasalka Jpanel. Kadibna waxaan ku sawireynaa calaamado garoonka - si loo xisaabiyo cabbirrada mid kasta, waxaan isticmaali doonaa xogta lagu qeexay cabbirka dhiska ciyaarta:

gridSize = (dim  -  2 * margin);
tileSize = gridSize / size;

Margin sidoo kale waa halbeeg lagu dejiyay ciyaarta dhiska.

Hadda waxaan u baahanahay inaan qeexno habka drawGrid si aan u sawirno shabaqyada iyo dhibcaha shaashadda. Waxaan falanqeyneynaa soo diyaarinta tags-ka waxaanan u beddelnaa isku-duwayaasha isku-duwayaasha is-dhexgalka isticmaalaha. Kadibna ku sawir bar kasta lambarka u dhigma ee dhexda ku yaal:

private void drawGrid(Graphics2D g) {
  for (int i = 0; i < tiles.length; i++) {
    // we convert 1D coords to 2D coords given the size of the 2D Array
    int r = i / size;
    int c = i % size;
    // we convert in coords on the UI
    int x = margin + c * tileSize;
    int y = margin + r * tileSize;
 
    // check special case for blank tile
    if(tiles[i] == 0) {
      if (gameOver) {
        g.setColor(FOREGROUND_COLOR);
        drawCenteredString(g, "u2713", x, y);
      }
 
      continue;
    }
 
    // for other tiles
    g.setColor(getForeground());
    g.fillRoundRect(x, y, tileSize, tileSize, 25, 25);
    g.setColor(Color.BLACK);
    g.drawRoundRect(x, y, tileSize, tileSize, 25, 25);
    g.setColor(Color.WHITE);
 
    drawCenteredString(g, String.valueOf(tiles[i]), x , y);
  }
}

Ugu dambeyntii, aan ka gudubno habka rinjiComponent, kaas oo ka soo jeeda fasalka JPane. Waxaan isticmaalnaa habka drawGrid, oo ay ku xigto habka drawStartMessage si aan u muujino fariin nagu dhiirigelinaysa inaan gujino si aan u bilowno ciyaarta:

private void drawStartMessage(Graphics2D g) {
  if (gameOver) {
    g.setFont(getFont().deriveFont(Font.BOLD, 18));
    g.setColor(FOREGROUND_COLOR);
    String s = "Click to start new game";
    g.drawString(s, (getWidth() - g.getFontMetrics().stringWidth(s)) / 2,
        getHeight() - margin);
  }
}
 
private void drawCenteredString(Graphics2D g, String s, int x, int y) {
  // center string s for the given tile (x,y)
  FontMetrics fm = g.getFontMetrics();
  int asc = fm.getAscent();
  int desc = fm.getDescent();
  g.drawString(s,  x + (tileSize - fm.stringWidth(s)) / 2,
      y + (asc + (tileSize - (asc + desc)) / 2));
}
 
@Override
protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  Graphics2D g2D = (Graphics2D) g;
  g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  drawGrid(g2D);
  drawStartMessage(g2D);
}

Ka falcelinta isticmaalaha gudaha UI

Si ay ciyaartu u socodsiiso koorsadeeda, waxaa lagama maarmaan ah in lagu farsameeyo ficillada isticmaalaha gudaha UI. Si tan loo sameeyo, ku dar hirgelinta MouseListener ee Jpanel iyo koodhka meelaha dhaqaaqa, ee horeba kor loogu muujiyey:

addMouseListener(new MouseAdapter() {
  @Override
  public void mousePressed(MouseEvent e) {
    // used to let users to interact on the grid by clicking
    // it's time to implement interaction with users to move tiles to solve the game !
    if (gameOver) {
      newGame();
    } else {
      // get position of the click
      int ex = e.getX() - margin;
      int ey = e.getY() - margin;
 
      // click in the grid ?
      if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
        return;
 
      // get position in the grid
      int c1 = ex / tileSize;
      int r1 = ey / tileSize;
 
      // get position of the blank cell
      int c2 = blankPos % size;
      int r2 = blankPos / size;
 
      // we convert in the 1D coord
      int clickPos = r1 * size + c1;
 
      int dir = 0;
 
      // we search direction for multiple tile moves at once
      if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
        dir = (r1 - r2) > 0 ? size : -size;
      else if (r1 == r2 && Math.abs(c1 - c2) > 0)
        dir = (c1 - c2) > 0 ? 1 : -1;
 
      if (dir != 0) {
        // we move tiles in the direction
        do {
          int newBlankPos = blankPos + dir;
          tiles[blankPos] = tiles[newBlankPos];
          blankPos = newBlankPos;
        } while(blankPos != clickPos);
 
        tiles[blankPos] = 0;
      }
 
      // we check if game is solved
      gameOver = isSolved();
    }
 
    // we repaint panel
    repaint();
  }
});

Waxaan dhignaa koodka dhisaha fasalka GameOfFifteen. Dhamaadka, waxaan ugu yeernaa habka cusub ee ciyaarta si aan u bilowno ciyaar cusub.

Koodhka ciyaarta oo buuxa

Talaabada ugu danbeysa ka hor inta aanad arkin ciyaarta ficilka ah waa in la isku geeyo dhammaan walxaha koodka. Waa kan waxa dhaca:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
 
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
 
// We are going to create a Game of 15 Puzzle with Java 8 and Swing
// If you have some questions, feel free to read comments ;)
public class GameOfFifteen extends JPanel { // our grid will be drawn in a dedicated Panel
 
  // Size of our Game of Fifteen instance
  private int size;
  // Number of tiles
  private int nbTiles;
  // Grid UI Dimension
  private int dimension;
  // Foreground Color
  private static final Color FOREGROUND_COLOR = new Color(239, 83, 80); // we use arbitrary color
  // Random object to shuffle tiles
  private static final Random RANDOM = new Random();
  // Storing the tiles in a 1D Array of integers
  private int[] tiles;
  // Size of tile on UI
  private int tileSize;
  // Position of the blank tile
  private int blankPos;
  // Margin for the grid on the frame
  private int margin;
  // Grid UI Size
  private int gridSize;
  private boolean gameOver; // true if game over, false otherwise
 
  public GameOfFifteen(int size, int dim, int mar) {
    this.size = size;
    dimension = dim;
    margin = mar;
    
    // init tiles
    nbTiles = size * size - 1; // -1 because we don't count blank tile
    tiles = new int[size * size];
    
    // calculate grid size and tile size
    gridSize = (dim - 2 * margin);
    tileSize = gridSize / size;
    
    setPreferredSize(new Dimension(dimension, dimension + margin));
    setBackground(Color.WHITE);
    setForeground(FOREGROUND_COLOR);
    setFont(new Font("SansSerif", Font.BOLD, 60));
    
    gameOver = true;
    
    addMouseListener(new MouseAdapter() {
      @Override
      public void mousePressed(MouseEvent e) {
        // used to let users to interact on the grid by clicking
        // it's time to implement interaction with users to move tiles to solve the game !
        if (gameOver) {
          newGame();
        } else {
          // get position of the click
          int ex = e.getX() - margin;
          int ey = e.getY() - margin;
          
          // click in the grid ?
          if (ex < 0 || ex > gridSize  || ey < 0  || ey > gridSize)
            return;
          
          // get position in the grid
          int c1 = ex / tileSize;
          int r1 = ey / tileSize;
          
          // get position of the blank cell
          int c2 = blankPos % size;
          int r2 = blankPos / size;
          
          // we convert in the 1D coord
          int clickPos = r1 * size + c1;
          
          int dir = 0;
          
          // we search direction for multiple tile moves at once
          if (c1 == c2  &&  Math.abs(r1 - r2) > 0)
            dir = (r1 - r2) > 0 ? size : -size;
          else if (r1 == r2 && Math.abs(c1 - c2) > 0)
            dir = (c1 - c2) > 0 ? 1 : -1;
            
          if (dir != 0) {
            // we move tiles in the direction
            do {
              int newBlankPos = blankPos + dir;
              tiles[blankPos] = tiles[newBlankPos];
              blankPos = newBlankPos;
            } while(blankPos != clickPos);
            
            tiles[blankPos] = 0;
          }
          
          // we check if game is solved
          gameOver = isSolved();
        }
        
        // we repaint panel
        repaint();
      }
    });
    
    newGame();
  }
 
  private void newGame() {
    do {
      reset(); // reset in intial state
      shuffle(); // shuffle
    } while(!isSolvable()); // make it until grid be solvable
    
    gameOver = false;
  }
 
  private void reset() {
    for (int i = 0; i < tiles.length; i++) {
      tiles[i] = (i + 1) % tiles.length;
    }
    
    // we set blank cell at the last
    blankPos = tiles.length - 1;
  }
 
  private void shuffle() {
    // don't include the blank tile in the shuffle, leave in the solved position
    int n = nbTiles;
    
    while (n > 1) {
      int r = RANDOM.nextInt(n--);
      int tmp = tiles[r];
      tiles[r] = tiles[n];
      tiles[n] = tmp;
    }
  }
 
  // Only half permutations of the puzzle are solvable.
  // Whenever a tile is preceded by a tile with higher value it counts
  // as an inversion. In our case, with the blank tile in the solved position,
  // the number of inversions must be even for the puzzle to be solvable
  private boolean isSolvable() {
    int countInversions = 0;
    
    for (int i = 0; i < nbTiles; i++) {
      for (int j = 0; j < i; j++) {
        if (tiles[j] > tiles[i])
          countInversions++;
      }
    }
    
    return countInversions % 2 == 0;
  }
 
  private boolean isSolved() {
    if (tiles[tiles.length - 1] != 0) // if blank tile is not in the solved position ==> not solved
      return false;
    
    for (int i = nbTiles - 1; i >= 0; i--) {
      if (tiles[i] != i + 1)
        return false;      
    }
    
    return true;
  }
 
  private void drawGrid(Graphics2D g) {
    for (int i = 0; i < tiles.length; i++) {
      // we convert 1D coords to 2D coords given the size of the 2D Array
      int r = i / size;
      int c = i % size;
      // we convert in coords on the UI
      int x = margin + c * tileSize;
      int y = margin + r * tileSize;
      
      // check special case for blank tile
      if(tiles[i] == 0) {
        if (gameOver) {
          g.setColor(FOREGROUND_COLOR);
          drawCenteredString(g, "u2713", x, y);
        }
        
        continue;
      }
      
      // for other tiles
      g.setColor(getForeground());
      g.fillRoundRect(x, y, tileSize, tileSize, 25, 25);
      g.setColor(Color.BLACK);
      g.drawRoundRect(x, y, tileSize, tileSize, 25, 25);
      g.setColor(Color.WHITE);
      
      drawCenteredString(g, String.valueOf(tiles[i]), x , y);
    }
  }
 
  private void drawStartMessage(Graphics2D g) {
    if (gameOver) {
      g.setFont(getFont().deriveFont(Font.BOLD, 18));
      g.setColor(FOREGROUND_COLOR);
      String s = "Click to start new game";
      g.drawString(s, (getWidth() - g.getFontMetrics().stringWidth(s)) / 2,
          getHeight() - margin);
    }
  }
 
  private void drawCenteredString(Graphics2D g, String s, int x, int y) {
    // center string s for the given tile (x,y)
    FontMetrics fm = g.getFontMetrics();
    int asc = fm.getAscent();
    int desc = fm.getDescent();
    g.drawString(s,  x + (tileSize - fm.stringWidth(s)) / 2,
        y + (asc + (tileSize - (asc + desc)) / 2));
  }
 
  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2D = (Graphics2D) g;
    g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    drawGrid(g2D);
    drawStartMessage(g2D);
  }
 
  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setTitle("Game of Fifteen");
      frame.setResizable(false);
      frame.add(new GameOfFifteen(4, 550, 30), BorderLayout.CENTER);
      frame.pack();
      // center on the screen
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }
 
 
}

Ugu dambeyntii, aan ciyaarno!

Waa waqtigii la bilaabi lahaa ciyaarta oo lagu tijaabin lahaa ficil ahaan. Garoonku waa inuu u ekaado sidan:

"Tag" ee Java - sida loo horumariyo ciyaar dhamaystiran

Aan isku dayno inaan xalino xujada. Haddii wax walba si fiican u dhaceen, waxaan helnaa tan:

"Tag" ee Java - sida loo horumariyo ciyaar dhamaystiran

Waa intaas. Wax intaa ka badan ma filaysay? 🙂

Skillbox waxay ku talinaysaa:

Source: www.habr.com

Add a comment