
"Meedogun" tabi "Meedogun" jẹ apẹẹrẹ ti o tayọ ti ere kannaa ti o rọrun ti o jẹ olokiki ni gbogbo agbaye. Lati yanju adojuru naa, o nilo lati ṣeto awọn onigun mẹrin pẹlu awọn nọmba ni ibere, lati kere julọ si tobi julọ. O ni ko rorun, sugbon o ni awon.
Ninu ikẹkọ oni a yoo fihan ọ bi o ṣe le ṣe idagbasoke Meedogun ni Java 8 pẹlu Oṣupa. Lati ṣe agbekalẹ UI a yoo lo API Swing.
A leti: fun gbogbo awọn oluka ti "Habr" - ẹdinwo ti 10 rubles nigbati o forukọsilẹ ni eyikeyi iṣẹ-ẹkọ Skillbox nipa lilo koodu ipolowo “Habr”.
Skillbox ṣe iṣeduro: Ẹkọ lori ayelujara ti ẹkọ .
Apẹrẹ ere
Ni ipele yii o nilo lati ṣalaye awọn ohun-ini:
- Iwọn - iwọn ti aaye ere;
- nbTiles - nọmba ti afi ninu awọn aaye. nbTiles = iwọn * iwọn - 1;
- Awọn alẹmọ jẹ tag ti o jẹ titobi onisẹpo kan ti odidi. Olukuluku awọn afi yoo gba iye alailẹgbẹ ni sakani [0, nbTiles]. Odo tọkasi ohun ṣofo square;
- blankPos - ipo ti square sofo.
game kannaa
A nilo lati ṣalaye ọna atunto ti a lo lati ṣe ipilẹṣẹ ipo ere tuntun kan. Ni ọna yii a ṣeto iye kan fun ipin kọọkan ti akojọpọ awọn afi. O dara, lẹhinna a gbe awọn blankPos si ipo ti o kẹhin ti orun naa.
A tun nilo ọna Daarapọmọra lati dapọ titobi awọn afi. A ko pẹlu aami ti o ṣofo ninu ilana sisọpọ lati le fi silẹ ni ipo kanna.
Niwọn bi idaji awọn ipo ibẹrẹ ti o ṣeeṣe ti adojuru ni ojutu kan, o nilo lati ṣayẹwo abajade daapọ ti abajade lati rii daju pe ifilelẹ lọwọlọwọ paapaa le yanju. Lati ṣe eyi, a ṣalaye ọna isSolvable.
Ti aami kan ba wa ni iṣaaju nipasẹ aami kan pẹlu iye ti o ga julọ, a kà ọ si iyipada. Nigbati aaye ti o ṣofo ba wa ni aaye, nọmba awọn iyipada gbọdọ jẹ paapaa fun adojuru lati yanju. Nitorinaa a ka nọmba awọn iyipada ati pada otitọ ti nọmba naa ba jẹ paapaa.
Lẹhinna o ṣe pataki lati ṣalaye ọna isSolved lati ṣayẹwo boya Ere Ti ọwọ mẹdogun ti yanju. Ni akọkọ a wo ibi ti aaye ti o ṣofo wa. Ti o ba wa ni ipo akọkọ, lẹhinna titete lọwọlọwọ jẹ tuntun, kii ṣe ipinnu tẹlẹ. A ki o si iterate nipasẹ awọn alẹmọ ni yiyipada ibere, ati ti o ba awọn iye ti awọn tag ti o yatọ si lati awọn ti o baamu atọka +1, a pada eke. Bibẹẹkọ, ni opin ọna naa o to akoko lati pada si otitọ nitori adojuru ti tẹlẹ ti yanju.
Ọna miiran ti o nilo lati ṣalaye jẹ ere tuntun. O nilo lati ṣẹda apẹẹrẹ tuntun ti ere naa. Lati ṣe eyi, a tunto aaye ere, lẹhinna daapọ rẹ ki o tẹsiwaju titi ipo iṣere yoo jẹ atunṣe.
Eyi ni koodu apẹẹrẹ kan pẹlu ọgbọn ọgbọn ti 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;
}
Nikẹhin, o nilo lati ṣe eto gbigbe ti awọn afi ni titobi. Koodu yii yoo pe nigbamii nipasẹ ipepada kan lati dahun si gbigbe kọsọ. Ere wa yoo ṣe atilẹyin awọn agbeka tile pupọ ni akoko kanna. Nitorinaa, lẹhin ti a ti yipada ipo ti o tẹ lori iboju sinu tag, a gba ipo ti tag ofo ati ki o wa itọsọna ti gbigbe lati ṣe atilẹyin ọpọlọpọ awọn agbeka rẹ ni akoko kanna.
Eyi ni apẹẹrẹ koodu kan:
// 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;
A ṣe idagbasoke UI nipa lilo API Swing
O to akoko lati ṣiṣẹ lori wiwo. Ni akọkọ a gba kilasi Jpanel. Lẹhinna a fa awọn afi lori aaye - lati ṣe iṣiro awọn iwọn ti ọkọọkan, a yoo lo data ti o pato ninu paramita olupilẹṣẹ ere:
gridSize = (dim - 2 * margin);
tileSize = gridSize / size;
Ala jẹ tun kan paramita ṣeto ni ere Constructor.
Bayi a nilo lati ṣalaye ọna drawGrid lati fa akoj ati awọn aaye loju iboju. A ṣe itupalẹ titobi awọn afi ati yi awọn ipoidojuko pada sinu awọn ipoidojuko wiwo olumulo. Lẹhinna fa aaye kọọkan pẹlu nọmba ti o baamu ni aarin:
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);
}
}
Nikẹhin, jẹ ki a bori ọna paintComponent, eyiti o gba lati kilasi JPane. Lẹhinna a lo ọna drawGrid, atẹle nipasẹ ọna drawStartMessage lati ṣafihan ifiranṣẹ kan ti o nfa wa lati tẹ lati bẹrẹ ere naa:
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);
}
Idahun si awọn iṣe olumulo ni UI
Ni ibere fun ere lati ṣiṣẹ ipa-ọna rẹ, o jẹ dandan lati ṣe ilana awọn iṣe olumulo ni UI. Lati ṣe eyi, ṣafikun imuse ti MouseListener lori Jpanel ati koodu fun awọn aaye gbigbe, ti han tẹlẹ loke:
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();
}
});
A gbe koodu naa sinu olupilẹṣẹ ti kilasi GameOfFifteen. Ni ipari pupọ, a pe ọna ere tuntun lati bẹrẹ ere tuntun kan.
Full game koodu
Igbesẹ ikẹhin ṣaaju ki o to rii ere ni iṣe ni lati fi gbogbo awọn eroja koodu papọ. Eyi ni ohun ti o ṣẹlẹ:
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);
});
}
}
Níkẹyìn, jẹ ki ká mu!
O to akoko lati ṣe ifilọlẹ ere naa ki o ṣe idanwo ni iṣe. Aaye yẹ ki o dabi eyi:

Jẹ ká gbiyanju lati yanju awọn adojuru. Ti ohun gbogbo ba lọ daradara, a gba eyi:

Gbogbo ẹ niyẹn. Ṣe o nireti diẹ sii? 🙂
Skillbox ṣe iṣeduro:
- Ilana ti o wulo .
- Ohun elo online dajudaju .
- Ọdun meji iṣẹ ikẹkọ .
orisun: www.habr.com
