Initial Commit

- upload to github
This commit is contained in:
2022-10-03 01:18:19 +02:00
parent 36d76c6eb3
commit 6543c21363
40 changed files with 2782 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target/

51
pom.xml Normal file
View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>berack96</groupId>
<artifactId>Minefield</artifactId>
<version>1.0.1</version>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>berack96.games.minefield.Game</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>

View File

@@ -0,0 +1,201 @@
package berack96.games.minefield;
import berack96.games.minefield.frame.MenuFrame;
import berack96.games.minefield.object.Decisor;
import berack96.games.minefield.object.Field;
import berack96.games.minefield.object.view.FieldView;
import berack96.games.minefield.runexception.OutOfBoundsException;
import jbook.util.Input;
/**
* Classe che utilizza {@link Field} e {@link Decisor} per creare una interazione con l'utente.<br>
* Il gioco puo' esser fatto partire per console o come finestra.<br>
* Senza argomenti il gioco partira' in finestra.<br>
* <br>
* Lista dei possibili argomenti da passare al programma:<br>
* -nogui indica che il gioco partira' su console.<br>
* -safe=(true/false)<br>
* -mode=(EASY/MEDIUM/HARD/CUSTOM)<br>
* -dim=(colonne),(righe)<br>
* -mines=(num)<br>
*
* Questi argomenti per ora funzionano solo con il gioco in console<br>
* ovvero solo se si usa anche -nogui
*
* @author Jack
*
*/
public class Game {
private static Field field;
private static boolean graphic = true;
private static Boolean safe = null;
private static Mode mode = null;
private static Integer columns = null;
private static Integer lines = null;
private static Integer mines = null;
public static void main(String[] arg) {
for(String s: arg) // looking for arguments
try {
if(s.matches("-nogui"))
graphic = false;
else if(s.matches("-safe=(.*)")) {
String temp[] = s.split("=");
safe = Boolean.getBoolean(temp[1]);
}
else if(s.matches("-mode=(.*)")) {
String temp2[] = s.split("=");
mode = Mode.valueOf(temp2[1]);
}
else if(s.matches("-dim=(.*)")) {
String temp3[] = s.split("=");
String t[] = temp3[1].split(",");
columns = Integer.valueOf(t[0]);
lines = Integer.valueOf(t[1]);
}
else if(s.matches("-mines=(.*)")) {
String temp5[] = s.split("=");
mines = Integer.valueOf(temp5[1]);
}
} catch(Exception e) {}
if(mode == null && (columns != null || lines != null || mines != null))
mode = Mode.CUSTOM;
if(graphic)
Game.startGraphic();
else
Game.startConsole();
}
private static void startConsole() {
String str;
// PARTENZA PROTETTA O MENO
if(safe == null) {
System.out.println("Vuoi la partenza protetta? (non troverai mine intorno alla prima cella scoperta)");
do {
System.out.print("[s/N] ");
str = Input.readString();
} while(!str.matches("(s|S|N|n)"));
safe = str.matches("(s|S)");
}
// DIFFICOLTA DEL GIOCO
if(mode == null) {
System.out.println("A che difficolta' vuoi giocare? ");
do {
System.out.println("1 - Facile.");
System.out.println("2 - Medio.");
System.out.println("3 - Difficile.");
System.out.println("4 - Personalizzata.");
str = Input.readString();
} while(!str.matches("(1|2|3|4)"));
if(str.matches("1"))
mode = Mode.EASY;
else if(str.matches("2"))
mode = Mode.MEDIUM;
else if(str.matches("3"))
mode = Mode.HARD;
else if(str.matches("4"))
mode = Mode.CUSTOM;
}
// DIFFICOLTA PERSONALIZATA
if(mode == Mode.CUSTOM) do {
if(columns == null)
columns = getNum("Inserisci quante colonne deve avere il campo: ", "Colonne = ", 1, Field.MAX_VAL);
if(lines == null)
lines = getNum("Inserisci quante righe deve avere il campo; ", "Righe = ", 1, Field.MAX_VAL);
if(mines == null)
mines = getNum("Inserisci le mine presenti nel campo: ", "Mine = ", 1, Field.MAX_VAL);
try {
field = Decisor.getNewField(safe, columns, lines, mines);
} catch(Exception e) {
System.out.println(e.getMessage());
mines = null;
}
} while(field == null);
else
field = Decisor.getNewField(safe, mode);
// code game
do {
System.out.println(FieldView.toString(field));
// coordinates used for interacting with user
int x = getNum(null, "X = ", 0, Integer.MAX_VALUE);
int y = getNum(null, "Y = ", 0, Integer.MAX_VALUE);;
System.out.println("Vuoi Scoprire la cella(S),\nSettarla come pericolosa(P),\nO rimuoverla dallo stato di pericolosa(R)?");
str = null;
do {
System.out.print("Inserisci scelta: ");
str = Input.readString();
} while(str.matches("(S|s|P|p|R|r)") == false);
try {
if(str.matches("(s|S)"))
field.cellUncover(x, y);
else if(str.matches("(P|p)"))
field.cellSetDangerous(x, y);
else
field.cellSetNotDangerous(x, y);
} catch (OutOfBoundsException e) {
System.out.println("Inserisci delle coordinate valide...");
}
} while(!Decisor.isALoose(field) && !Decisor.isAWin(field));
Decisor.uncoverAllMinesCells(field);
Decisor.uncoverAllDangerousCells(field);
System.out.println(FieldView.toString(field));
if(Decisor.isALoose(field))
System.out.println("Hai perso. SCARSO AHAHAHHA!");
else
System.out.println("Hai vinto.");
}
private static void startGraphic() {
MenuFrame menuFr = new MenuFrame();
menuFr.setVisible(true);
}
private static int getNum(String messaggio, String campo, int min, int max) {
if(messaggio != null)
System.out.println(messaggio);
int num = min - 1;
do {
try {
num = Input.readInt(campo);
if(num<min) {
System.out.println("Inserire un numero che sia almeno " + min);
num = -1;
}
if(num>max) {
System.out.println("Inserire un numero minore di " + max);
num = -1;
}
} catch(java.lang.NumberFormatException e) {
System.out.println("Inserire un numero.");
}
} while(num < min);
return num;
}
}

View File

@@ -0,0 +1,34 @@
package berack96.games.minefield;
import berack96.games.minefield.object.Decisor;
/**
* Serve a scegliere una delle modalita' di gioco senza inserire ogni singolo parametro.<br>
* Insomma serve a velocizzare la partenza del gioco.<br>
* Da usare con {@link Decisor}
*
* @author Jack
*
*/
public enum Mode {
/**
* Modalita' di gioco facile
*/
EASY,
/**
* Modalita' di gioco media
*/
MEDIUM,
/**
* Modalita' di gioco difficile
*/
HARD,
/**
* Modalita' di gioco personalizzata
*/
CUSTOM
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 B

View File

@@ -0,0 +1,84 @@
package berack96.games.minefield.frame;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import berack96.games.minefield.listener.EndFrameListener;
/**
* Classe che estende i {@link JPanel} in modo da creare una piccola finestra che appare alla fine del gioco.<br>
* <br>
* Essa contiene tre bottoni:<br>
* Menu che fa tornare ad un {@link MenuFrame},<br>
* Retry che fa riprovare la modalita' di gioco che era nel pannello {@link GameFrame},<br>
* Exit che serve a chiudere il gioco.
*
* @author Jack
*
*/
public class EndFrame extends JFrame{
private static final long serialVersionUID = 1L;
private JLabel labelMsg;
/**
* Costruttore: bisogna passargli la finestra di gioco corrente e una finestra menu.
*
* @param game Il gioco corrente che e' finito
* @param menu Il menu' che si vuole mostrare alla fine
*/
public EndFrame(GameFrame game, MenuFrame menu)
{
setTitle("MINEFIELD");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout(new GridLayout(2,1));
JPanel labelPanel = new JPanel();
labelMsg = new JLabel();
JPanel buttons = new JPanel();
JButton toMenu = new JButton("MENU");
JButton retry = new JButton("RETRY");
JButton quit = new JButton("EXIT");
EndFrameListener controller = new EndFrameListener(this, game, menu);
toMenu.addActionListener(controller);
retry.addActionListener(controller);
quit.addActionListener(controller);
labelPanel.add(labelMsg);
buttons.add(toMenu);
buttons.add(retry);
buttons.add(quit);
add(labelPanel);
add(buttons);
// centering window
Dimension size = new Dimension(240, 110);
int x = game.getLocation().x + game.getWidth()/2 - size.width/2;
int y = game.getLocation().y + game.getHeight()/2 - size.height/2;
setLocation(x, y);
setSize(size);
setVisible(true);
}
/**
* Setta il messaggio che si vuole mostrare nel pannello
*
* @param msg La stringa da mostrare
*/
public void setEndMsg(String msg)
{
labelMsg.setText("<html><center>"+msg+"</center></html>");
}
}

View File

@@ -0,0 +1,120 @@
package berack96.games.minefield.frame;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import berack96.games.minefield.listener.CellInFieldListener;
import berack96.games.minefield.object.Decisor;
import berack96.games.minefield.object.Field;
import berack96.games.minefield.object.FieldSafe;
import berack96.games.minefield.object.view.FieldView;
//TODO remove log lines
/**
* Classe che estende i {@link JPanel} in modo da creare una finestra del gioco.<br>
* Essa si serve di un {@link MenuFrame} per la finestra finale {@link EndFrame}<br>
* e anche di un {@link Field} gia' creato, in modo da creare una rappresentazione<br>
* grafica del gioco.
*
* @author Jack
*
*/
public class GameFrame extends JFrame {
private static final long serialVersionUID = 1L;
final private MenuFrame menu;
private Field field;
private JPanel gamePanel;
private JLabel label;
/**
* Costruttore: crea una finestra di gioco a partire dal parametro field.
*
* @param menu Il menu' che si vuole mostrare eventualmente alla fine del gioco
* @param field Il campo di gioco
*/
public GameFrame(MenuFrame menu, Field field)
{
this.field = field;
this.menu = menu;
setTitle("MINEFIELD");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
Container c = getContentPane();
c.setLayout(new FlowLayout());
label = new JLabel(String.valueOf(field.getNumMines()-field.getNumDagerousCell()));
label.setVisible(true);
gamePanel = new FieldView(field, new CellInFieldListener(this, field)).toJPanel();
gamePanel.setVisible(true);
add(label);
add(gamePanel);
// centering window
Dimension dim = gamePanel.getPreferredSize();
dim.height += 57; // doing this for the flowlayout & for the label
dim.width += 10; // same here
Dimension dimScreen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (dimScreen.width - dim.width)/2;
int y = (dimScreen.height - dim.height)/2;
setLocation(x, y);
setSize(dim);
setVisible(true);
}
public void updateView()
{
label.setText(String.valueOf(field.getNumMines()-field.getNumDagerousCell()));
}
/**
* Crea una nuova finestra {@link EndFrame} settata con endMsg.
*
* @param endMsg Il messaggio che si vuole mostrare
*/
public void launchEndFrame(String endMsg)
{
Decisor.uncoverAllMinesCells(field);
Decisor.uncoverAllDangerousCells(field);
EndFrame end = new EndFrame(this, menu);
end.setEndMsg(endMsg);
}
/**
* Resetta la griglia di gioco.<br>
* In questo modo si puo' giocare alla stessa difficolta' senza passare dal menu'.
*/
public void retryGame()
{
field = Decisor.getNewField(field.getClass() == FieldSafe.class, field.columns, field.lines, field.getNumMines());
gamePanel.setVisible(false);
remove(gamePanel); // remove all the component in the Frame
gamePanel = new FieldView(field, new CellInFieldListener(this, field)).toJPanel();
gamePanel.setVisible(true);
add(gamePanel);
updateView();
setVisible(true);
System.out.println("\n---New game started---"); // log line
}
}

View File

@@ -0,0 +1,366 @@
package berack96.games.minefield.frame;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import berack96.games.minefield.Mode;
import berack96.games.minefield.frame.strings.StringMode;
import berack96.games.minefield.frame.strings.StringSafe;
import berack96.games.minefield.listener.MenuFrameListener;
import berack96.games.minefield.object.Field;
/**
* Classe che estende i {@link JPanel} in modo da creare una finestra per il menu' del gioco.<br>
* Essa e' formata in modo da avere 4 zone: in ognuna di esse l'utente deve fare delle scelte.<br>
*
* @author Jack
*
*/
public class MenuFrame extends JFrame {
private static final long serialVersionUID = 1L;
private MenuFrameListener listener;
// TOP
final private JPanel panelTop;
final private JRadioButton easy;
final private JRadioButton medi;
final private JRadioButton hard;
final private JRadioButton cust;
final private JLabel modeMsg;
private Mode mode;
// MID TOP
final private JPanel panelMidTop;
final private JTextField textColumns;
final private JTextField textLines;
final private JTextField textMines;
final private JPanel customPanel;
// MID BOT
final private JPanel panelMidBot;
final private JRadioButton yes;
final private JRadioButton no;
final private JLabel safeMsg;
private boolean safe;
// BOT
final private JPanel panelBot;
final private JLabel error;
/**
* Costruttore: crea la finestra menu'
*/
public MenuFrame()
{
// set initial value for variable of JRadioButton
this.mode = Mode.EASY;
this.safe = true;
// add the listener
listener = new MenuFrameListener(this);
// basic things for the frame
setTitle("MINEFIELD");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setLayout( new GridLayout(4, 1));
Dimension dim = new Dimension(350, 400);
// TOP frame
panelTop = new JPanel();
JPanel panelTopLabel = new JPanel();
JPanel panelTopButtons = new JPanel();
JLabel labelTop = new JLabel("Scegli una difficolta'");
easy = new JRadioButton("EASY", true);
medi = new JRadioButton("MEDIUM", false);
hard = new JRadioButton("HARD", false);
cust = new JRadioButton("CUSTOM", false);
ButtonGroup groupTop = new ButtonGroup();
easy.addActionListener(this.listener);
medi.addActionListener(this.listener);
hard.addActionListener(this.listener);
cust.addActionListener(this.listener);
groupTop.add(easy);
groupTop.add(medi);
groupTop.add(hard);
groupTop.add(cust);
panelTopButtons.add(easy);
panelTopButtons.add(medi);
panelTopButtons.add(hard);
panelTopButtons.add(cust);
panelTopLabel.add(labelTop);
panelTop.setLayout(new BoxLayout(this.panelTop, BoxLayout.Y_AXIS));
panelTop.setBorder(BorderFactory.createLineBorder(Color.black));
panelTop.add(panelTopLabel);
panelTop.add(panelTopButtons);
add(panelTop);
// MID TOP frame
panelMidTop = new JPanel();
modeMsg = new JLabel(StringMode.easy);
customPanel = new JPanel();
JLabel labelLength = new JLabel("Colonne:");
JLabel labelHeight = new JLabel("Righe:");
JLabel labelMines = new JLabel("Numero di mine:");
textColumns = new JTextField();
textLines = new JTextField();
textMines = new JTextField();
customPanel.setLayout(new GridLayout(3, 3));
customPanel.add(labelLength);
customPanel.add(textColumns);
customPanel.add(labelHeight);
customPanel.add(textLines);
customPanel.add(labelMines);
customPanel.add(textMines);
panelMidTop.setLayout(new FlowLayout());
panelMidTop.setBorder(BorderFactory.createLineBorder(Color.black));
panelMidTop.add(modeMsg);
// not adding custom panel 'cause there is the private function when needed.
add(panelMidTop);
// MID BOT frame
panelMidBot = new JPanel();
JPanel panelMidBotButtons = new JPanel();
JPanel panelMidBotMsg = new JPanel();
JLabel labelMidBot = new JLabel("Vuoi la partenza safe?");
yes = new JRadioButton("YES", true);
no = new JRadioButton("NO", false);
safeMsg = new JLabel(StringSafe.yes);
ButtonGroup groupMid = new ButtonGroup();
yes.addActionListener(listener);
no.addActionListener(listener);
groupMid.add(yes);
groupMid.add(no);
panelMidBotButtons.add(yes);
panelMidBotButtons.add(no);
panelMidBotMsg.add(safeMsg);
panelMidBot.setLayout(new BoxLayout(panelMidBot, BoxLayout.Y_AXIS));
panelMidBot.setBorder(BorderFactory.createLineBorder(Color.black));
panelMidBot.add(labelMidBot);
panelMidBot.add(panelMidBotButtons);
panelMidBot.add(panelMidBotMsg);
add(panelMidBot);
// BOT frame
panelBot = new JPanel();
JPanel panelBotLabel = new JPanel();
JPanel panelBotButton = new JPanel();
error = new JLabel();
JButton next = new JButton("NEXT");
next.addActionListener(listener);
panelBotLabel.add(error);
panelBotButton.add(next);
panelBot.setLayout(new BorderLayout());
panelBot.setBorder(BorderFactory.createLineBorder(Color.black));
panelBot.add(panelBotLabel, BorderLayout.CENTER);
panelBot.add(panelBotButton, BorderLayout.EAST);
add(panelBot);
// last things to do for the frame
setSize(dim);
// centering window
Dimension dimScreen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (dimScreen.width - dim.width)/2;
int y = (dimScreen.height - dim.height)/2;
setLocation(x, y);
setVisible(true);
}
/**
* Funzione che serve al listener di questo frame {@link MenuFrameListener}<br>
* per aggiornare le frasi dei label e le varie variabili del menu'
*/
public void updateView()
{
if(easy.isSelected())
{
if(mode == Mode.CUSTOM)
removeCustomPanel();
mode = Mode.EASY;
modeMsg.setText(StringMode.easy);
}
else if(medi.isSelected())
{
if(mode == Mode.CUSTOM)
removeCustomPanel();
mode = Mode.MEDIUM;
modeMsg.setText(StringMode.medium);
}
else if(hard.isSelected())
{
if(mode == Mode.CUSTOM)
removeCustomPanel();
mode = Mode.HARD;
modeMsg.setText(StringMode.hard);
}
else
{
if(mode != Mode.CUSTOM)
addCustomPanel();
mode = Mode.CUSTOM;
modeMsg.setText(StringMode.custom);
}
if(yes.isSelected())
{
safe = true;
safeMsg.setText(StringSafe.yes);
}
else
{
safe = false;
safeMsg.setText(StringSafe.no);
}
}
/**
* Restituisce la stringa che si trova nel pannello delle colonne.
*
* @return La stringa inserita dall'utente
*/
public String getStringColumnsTextPanel()
{
return textColumns.getText();
}
/**
* Restituisce la stringa che si trova nel pannello delle linee.
*
* @return La stringa inserita dall'utente
*/
public String getStringLinesTextPanel()
{
return textLines.getText();
}
/**
* Restituisce la stringa che si trova nel pannello delle mine.
*
* @return La stringa inserita dall'utente
*/
public String getStringMinesTextPanel()
{
return textMines.getText();
}
/**
* Restituisce il valore attuale del parametro safe.
*
* @return true/false
*/
public boolean getSafeValue()
{
return safe;
}
/**
* Restituisce il valore attuale della modalita' di gioco.
*
* @return {@link Mode}
*/
public Mode getModeValue()
{
return mode;
}
/**
* Se inserita una stinga verra' mostrata di colore rosso nel pannello.
*
* @param error La stringa da mettere in evidenza
*/
public void setError(String error)
{
this.error.setText("<html><font color='red'>"+error+"</font></html>");
}
/**
* Se inserito un campo, verra' creata una finestra di gioco {@link GameFrame}<br>
* e questa finestra menu' verra' nascosta tramite {@link #setVisible(boolean)}.
*
* @param field Il campo del gioco che si vuole giocare
*/
public void startNewGameFrame(Field field)
{
setVisible(false);
GameFrame gameFrame = new GameFrame(this, field);
gameFrame.setVisible(true);
}
/**
* Resetta ogni variabile del pannello e ogni oggetto grafico.
*/
public void resetVariablePanel()
{
easy.setSelected(true);
medi.setSelected(false);
hard.setSelected(false);
cust.setSelected(false);
yes.setSelected(true);
no.setSelected(false);
updateView();
setError("");
}
/**
* Mostra il pannello per la personalizzazione della partita.
*/
private void addCustomPanel()
{
panelMidTop.add(customPanel);
customPanel.setVisible(true);
}
/**
* Nasconde il pannello per la personalizzazione della partita.
*/
private void removeCustomPanel()
{
customPanel.setVisible(false);
panelMidTop.remove(customPanel);
//panelMidTop.validate();
}
}

View File

@@ -0,0 +1,26 @@
package berack96.games.minefield.frame.strings;
public class StringError {
public static final String noValue = "Inserisci dei numeri nei campi indicati";
public static final String noPositiveValue = "Inserisci dei valori positivi<br>"
+ "per la grandezza del campo";
public static final String minesLessThanZero = "Inserisci dei valori positivi<br>"
+ "per le mine";
public static final String minesGreaterThanField = "Inserisci un valore minore per le mine<br>"
+ "siccome non possono essere maggiori<br>"
+ "della grandezza del campo";
public static final String minesGreaterThanFieldSafe = "Inserisci un valore minore per le mine<br>"
+ "siccome non possono essere maggiori<br>"
+ "della grandezza del campo-8<br>"
+ "(perche' la prima cella non<br>"
+ "puo avere mine intorno)";
public static final String valueTooHigh = "Inserisci un valore minore per le grandezze<br>"
+ "siccome entrambe devono avere un valore<br>"
+ "minore di 100";
}

View File

@@ -0,0 +1,19 @@
package berack96.games.minefield.frame.strings;
public class StringMode {
public static final String easy = "<html><center>MODALITA' FACILE:<br>"
+ "Il campo non e' molto grande (8x8)<br>"
+ "e le mine non sono molte (10)</center></html>";
public static final String medium = "<html><center>MODALITA' MEDIA:<br>"
+ "Il campo e' di medie dimensioni (16x16)<br>"
+ "e le mine sono numerose (40)</center></html>";
public static final String hard = "<html><center>MODALITA' DIFFICILE:<br>"
+ "Il campo e' molto grande (16x32)<br>"
+ "e le mine sono molto numerose (80)</center></html>";
public static final String custom = "<html><center>MODALITA' PERSONALIZZATA:</center></html>";
}

View File

@@ -0,0 +1,10 @@
package berack96.games.minefield.frame.strings;
public final class StringSafe {
public static final String yes = "<html><center>La prima cella che viene scoperta<br>"
+ "non avra' nessuna mina intorno.</center></html>";
public static final String no = "<html><center>La prima cella che viene scoperta<br>"
+ "potra' avere mine intorno, o esserla.</center></html>";
}

View File

@@ -0,0 +1,112 @@
package berack96.games.minefield.listener;
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
import berack96.games.minefield.frame.GameFrame;
import berack96.games.minefield.object.Decisor;
import berack96.games.minefield.object.Field;
//TODO remove log lines
/**
* Classe che serve a controllare un {@link Field} generato in un {@link GameFrame}.<br>
* Questa classe modifica la cella in base all'azione dell'utente tramite i movimenti<br>
* e i pulsanti generati dal mouse.
*
* @author Jack
*
*/
public class CellInFieldListener implements MouseListener {
private GameFrame frame;
private Field field;
public CellInFieldListener(GameFrame frame, Field field)
{
this.frame = frame;
this.field = field;
}
@Override
public void mouseClicked(MouseEvent arg0)
{
if(Decisor.isALoose(field) == false && Decisor.isAWin(field) == false)
{
JLabel label = (JLabel) arg0.getSource();
String[] str = label.getName().split("-");
int x = Integer.parseInt(str[0]);
int y = Integer.parseInt(str[1]);
System.out.println("User clicked on cell ("+label.getName()+")"); // log line
if(field.cellIsUncovered(x, y) == false)
{
if(arg0.getButton() == MouseEvent.BUTTON1)
field.cellUncover(x, y);
else if(arg0.getButton() == MouseEvent.BUTTON3)
{
if(field.cellIsDangerous(x, y) == false)
field.cellSetDangerous(x, y);
else
field.cellSetNotDangerous(x, y);
}
if(Decisor.isALoose(field))
{
frame.launchEndFrame("HAI PERSO");
System.out.println("---Game Lost---"); // log line
}
else if(Decisor.isAWin(field))
{
frame.launchEndFrame("HAI VINTO");
System.out.println("---Game Won---"); // log line
}
frame.updateView();
}
}
}
@Override
public void mouseEntered(MouseEvent arg0)
{
JLabel label = (JLabel) arg0.getSource();
String[] str = label.getName().split("-");
int x = Integer.parseInt(str[0]);
int y = Integer.parseInt(str[1]);
if(field.cellIsUncovered(x, y) == false && field.cellIsDangerous(x, y) == false)
label.setBackground(Color.GRAY);
}
@Override
public void mouseExited(MouseEvent arg0)
{
JLabel label = (JLabel) arg0.getSource();
String[] str = label.getName().split("-");
int x = Integer.parseInt(str[0]);
int y = Integer.parseInt(str[1]);
if(field.cellIsUncovered(x, y) == false && field.cellIsDangerous(x, y) == false)
label.setBackground(Color.LIGHT_GRAY);
}
@Override
public void mousePressed(MouseEvent arg0)
{
// do nothing
}
@Override
public void mouseReleased(MouseEvent arg0)
{
// do nothing
}
}

View File

@@ -0,0 +1,60 @@
package berack96.games.minefield.listener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import berack96.games.minefield.frame.EndFrame;
import berack96.games.minefield.frame.GameFrame;
import berack96.games.minefield.frame.MenuFrame;
/**
* Classe che contolla la finestra {@link EndFrame} e in base a che bottone<br>
* viene premuto viene effettuata una scelta.
*
* @author Jack
*
*/
public class EndFrameListener implements ActionListener {
private EndFrame end;
private GameFrame game;
private MenuFrame menu;
public EndFrameListener(EndFrame end, GameFrame game, MenuFrame menu)
{
this.end = end;
this.game = game;
this.menu = menu;
}
@Override
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton) e.getSource();
String s = button.getText();
if(s.matches("EXIT"))
{
System.exit(0);
}
else if(s.matches("RETRY"))
{
game.retryGame();
}
else if(s.matches("MENU"))
{
game.setVisible(false);
menu.resetVariablePanel();
menu.setVisible(true);
game.dispose();
}
end.setVisible(false);
end.dispose();
}
}

View File

@@ -0,0 +1,89 @@
package berack96.games.minefield.listener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import berack96.games.minefield.Mode;
import berack96.games.minefield.frame.MenuFrame;
import berack96.games.minefield.frame.strings.StringError;
import berack96.games.minefield.object.Decisor;
import berack96.games.minefield.object.Field;
import berack96.games.minefield.runexception.TooHighValueException;
/**
* Classe che contolla la finestra {@link MenuFrame} e in base a che bottone<br>
* viene premuto o a che pulsante Radio viene scelto, viene effettuata una scelta.
*
* @author Jack
*
*/
public class MenuFrameListener implements ActionListener {
private MenuFrame frame;
public MenuFrameListener(MenuFrame frame)
{
this.frame = frame;
}
@Override
public void actionPerformed(ActionEvent arg0)
{
frame.updateView();
if(frame.getModeValue() != Mode.CUSTOM)
frame.setError("");
int columns = 0,
lines = 0,
mines = 0;
try{
JButton button = (JButton) arg0.getSource();
if(button.getText().matches("NEXT"))
{
Field field;
if(frame.getModeValue() == Mode.CUSTOM)
{
columns = Integer.parseInt(this.frame.getStringColumnsTextPanel());
lines = Integer.parseInt(this.frame.getStringLinesTextPanel());
mines = Integer.parseInt(this.frame.getStringMinesTextPanel());
field = Decisor.getNewField(frame.getSafeValue(), columns, lines, mines);
}
else
field = Decisor.getNewField(frame.getSafeValue(), frame.getModeValue());
frame.startNewGameFrame(field);
}
}
catch(ClassCastException e) // not a JButton generated the action (in this case a JRadioButton have)
{
// DO NOTHING
}
catch(NumberFormatException e) // not a number is inserted in the text
{
frame.setError(StringError.noValue);
}
catch(IllegalArgumentException e) // the numbers inserted is not valid
{
if(columns<=0 || lines<=0)
frame.setError(StringError.noPositiveValue);
else if(mines<=0)
frame.setError(StringError.minesLessThanZero);
else if(frame.getSafeValue() && mines>=lines*columns-8)
frame.setError(StringError.minesGreaterThanFieldSafe);
else if(mines>= lines*columns)
frame.setError(StringError.minesGreaterThanField);
}
catch(TooHighValueException e)
{
frame.setError(StringError.valueTooHigh);
}
}
}

View File

@@ -0,0 +1,139 @@
package berack96.games.minefield.object;
import java.util.Observable;
/**
* Classe che serve a creare una cella per il campo.<br>
* Tramite le funzioni principali della cella si<br>
* possono sapere 4 cose:<br>
* - il numero di mine vicine {@link #nearMine}<br>
* - se la cella e' una mina {@link #isMine()}<br>
* - lo stato della cella {@link #getStatus()}<br>
*
* @author Jack
*
*/
public class Cell extends Observable {
/**
* Indica le mine che si trovano vicino a questa cella
*/
public int nearMine;
private boolean isMine;
private boolean uncovered;
private CellStatus status;
/**
* Costruttore: serve creare una nuova cella coperta con 0 mine intorno.
*/
public Cell() {
nearMine = 0;
isMine = false;
uncovered = false;
status = CellStatus.COVERED;
}
/**
* Serve a mettere la cella nello stato di "scoperta"<br>
* Una volta fatto la cella non potra' esser piu cambiata.<br>
* Essa potra' avere i seguenti valori:<br>
* - EXPLODED<br>
* - UNCOVERED<br>
* - GOTRIGHT<br>
* - GOTWRONG<br>
* <br>
* Per altro vedere {@link CellStatus}
*/
public void uncover() {
if(!this.uncovered) {
if(isMine) {
if(status == CellStatus.DANGEROUS)
status = CellStatus.GOTRIGHT;
else
status = CellStatus.EXPLODED;
}
else {
if(status == CellStatus.DANGEROUS)
status = CellStatus.GOTWRONG;
else
status = CellStatus.UNCOVERED;
}
uncovered = true;
setChanged();
notifyObservers();
clearChanged();
}
}
/**
* Serve ad avere lo stato della cella.<br>
* Vedi {@link CellStatus} per i possibili valori.
*
* @return CellStatus
*/
public CellStatus getStatus() {
return status;
}
/**
* Setta la cella come una mina solamente se<br>
* quest'ultima non e' stata scoperta.<br>
* Questa azione e' irreversibile.
*/
public void setMine() {
if(!uncovered)
isMine = true;
}
/**
* Setta la cella nello stato di {@link CellStatus}.DANGEROUS<br>
* Se La funzione {@link #uncover()} e' gia stata chiamata<br>
* la cella non verra' settata come pericolosa.
*/
public void setDangerous() {
if(status == CellStatus.COVERED) {
status = CellStatus.DANGEROUS;
setChanged();
notifyObservers();
clearChanged();
}
}
/**
* Toglie la cella dallo stato {@link CellStatus}.DANGEROUS<br>
* e la mette come COVERED.<br>
* Se la cella non e' in stato DANGEROUS, la funzione<br>
* non fa nulla.
*/
public void setNotDangerous() {
if(status == CellStatus.DANGEROUS) {
status = CellStatus.COVERED;
setChanged();
notifyObservers();
clearChanged();
}
}
/**
* Dice se la cella e' una mina o meno.
*
* @return true se lo e'
*/
public boolean isMine() {
return isMine;
}
/**
* Dice se la cella e' gia stata scoperta.<br>
* AKA se la funzione {@link #uncover()} e' gia stata chiamata.
*
* @return true se non e' piu {@link CellStatus#COVERED}
*/
public boolean isUncovered() {
return uncovered;
}
}

View File

@@ -0,0 +1,41 @@
package berack96.games.minefield.object;
/**
* Serve a comunicare lo stato della cella.<br>
* Essa puo' assumere questi stati in base al<br>
* fatto di essere o meno stata scoperrta.
*
* @author Jack
*
*/
public enum CellStatus {
/**
* Se la cella non e' ancora stata scoperta.
*/
COVERED,
/**
* Se la cella e' marchiata pericolosa.
*/
DANGEROUS,
/**
* Dopo aver scoperto la cella: se essa e' una mina.
*/
EXPLODED,
/**
* Dopo aver scoperto la cella, se essa non e' una mina
*/
UNCOVERED,
/**
* Dopo aver scoperto la cella: se essa, marchiata precedentemente come pericolosa, e' effettivamente una mina.
*/
GOTRIGHT,
/**
* Dopo aver scoperto la cella: se essa, marchiata precedentemente cvome pericolosa, non e' una mina.
*/
GOTWRONG
}

View File

@@ -0,0 +1,160 @@
package berack96.games.minefield.object;
import berack96.games.minefield.Mode;
/**
* Classe utile ad automatizzare alcuni meccanismi di gioco, come per esempio<br>
* {@link #getNewField(boolean, Mode)} che crea un nuovo campo data la modalita'.
*
* @author Jack
*
*/
public class Decisor {
/**
* Crea un nuovo campo di gioco data la modalita' {@link Mode}.
*
* @param safe Se si vuole che il campo sia {@link FieldSafe}
* @param mode La modalita' di gioco
* @return Un nuovo campo
*/
public static Field getNewField(boolean safe, Mode mode) {
if(mode == Mode.EASY)
return getNewFieldEasy(safe);
else if(mode == Mode.MEDIUM)
return getNewFieldMedium(safe);
else if(mode == Mode.HARD)
return getNewFieldHard(safe);
else
throw new java.lang.IllegalArgumentException("mode must be Easy, Medium or Hard");
}
/**
* Serve a creare un nuovo campo dati i parametri richiesti.
*
* @param safe Se si vuole che il campo sia {@link FieldSafe}
* @param columns Una grandezza del campo (larghezza)
* @param lines Una grandezza del campo (altezza)
* @param mines Quante mine ci sono nel campo
* @return Un nuovo campo
*/
public static Field getNewField(boolean safe, int columns, int lines, int mines) {
if(safe)
return new FieldSafe(columns, lines, mines);
return new FieldNoSafe(columns, lines, mines);
}
/**
* Serve a creare un campo in modalita' facile
*
* @param safe Se si vuole che il campo sia {@link FieldSafe}
* @return Un nuovo campo
*/
public static Field getNewFieldEasy(boolean safe) {
return getNewField(safe, 8, 8, 10);
}
/**
* Serve a creare un campo in modalita' media
*
* @param safe Se si vuole che il campo sia {@link FieldSafe}
* @return Un nuovo campo
*/
public static Field getNewFieldMedium(boolean safe) {
return getNewField(safe, 16, 16, 40);
}
/**
* Serve a creare un campo in modalita' difficile
*
* @param safe Se si vuole che il campo sia {@link FieldSafe}
* @return Un nuovo campo
*/
public static Field getNewFieldHard(boolean safe) {
return getNewField(safe, 32, 16, 80);
}
/**
* Indica se nel campo inserito si e' riusciti a vincere.
*
* @param field Il campo da controllare
* @return true se si ha vinto
*/
public static boolean isAWin(Field field) {
// Basic
if(!field.isGenerated)
return false;
// First Condition
if(field.getNumMines() == field.getNumCoveredCell())
return true;
// Second Condition
int minesGot = 0;
for(Cell cell : field)
if(cell.isMine() && cell.getStatus() == CellStatus.DANGEROUS)
minesGot++;
if(minesGot == field.getNumMines())
return true;
// Else
return false;
}
/**
* Indica se nel campo inserito si ha perso.
*
* @param field Il campo da controllare
* @return true se si ha perso
*/
public static boolean isALoose(Field field) {
for(Cell cell : field)
if(cell.isUncovered() && cell.isMine())
return true;
return false;
}
/**
* Scopre tutte le celle del campo.
*
* @param field Il campo da scoprire
*/
public static void uncoverAllCells(Field field) {
for(Cell cell : field)
cell.uncover();
}
/**
* Scopre tutte celle pericolose del campo.
*
* @param field Il campo da scoprire
*/
public static void uncoverAllDangerousCells(Field field) {
for(Cell cell : field)
if(cell.getStatus() == CellStatus.DANGEROUS)
cell.uncover();
}
/**
* Scopre tutte le mine del campo.
*
* @param field Il campo da scoprire
*/
public static void uncoverAllMinesCells(Field field) {
for(Cell cell : field)
if(cell.isMine())
cell.uncover();
}
/**
* Scopre tutte le celle che non sono mine del campo.
*
* @param field Il campo da scoprire
*/
public static void uncoverAllNotMinesCells(Field field) {
for(Cell cell : field)
if(!cell.isMine())
cell.uncover();
}
}

View File

@@ -0,0 +1,415 @@
package berack96.games.minefield.object;
import java.util.Iterator;
import berack96.games.minefield.runexception.OutOfBoundsException;
import berack96.games.minefield.runexception.TooHighValueException;
/**
* Classe astratta in cui manca la funzione che genera il campo.<br>
* Essa contiene un tot numero di celle della classe {@link Cell}<br>
*
* @author Jack
*
*/
public abstract class Field implements Iterable<Cell> {
/**
* Valore massimo del capo
*/
public static final int MAX_VAL = 100;
/**
* Una delle grandezze del campo
*/
public final int lines;
/**
* Una delle grandezze del campo
*/
public final int columns;
/**
* Valore che inizialmente e' settato a <b>false</b> e che<br>
* se messo a <b>true</b>, non fara' piu richiamare la funzione<br>
* {@link #generateField(int, int)} quando la funzione<br>
* {@link #cellUncover(int, int)} e' usata.
*/
protected boolean isGenerated;
private int numMines;
private Cell [][]matrix;
private int numCoveredCell;
private int numDangerousCell;
/**
* Costruttore che crea un campo senza mine o altro.<br>
* Genera solamente la base per futuri cambiamenti in esso.
*
* @param columns Una delle grandezze del campo (larghezza)
* @param lines Una delle grandezze del campo (altezza)
* @throws IllegalArgumentException nel caso in cui si inseriscano parametri sbagliati
* @throws TooHighValueException nel caso in cui i parametri siano maggiori di 100
*/
public Field(int columns, int lines) {
if(lines<0 || columns<0)
throw new java.lang.IllegalArgumentException("columns and lines must be greater than 0.");
if(lines>MAX_VAL || columns>MAX_VAL)
throw new TooHighValueException("columns and lines must be less than 100.");
this.isGenerated = false;
this.lines = lines;
this.columns = columns;
numMines = 0;
numDangerousCell = 0;
numCoveredCell = lines*columns;
matrix = new Cell[lines][columns];
for(int i=0; i<lines; i++)
for(int j=0; j<columns; j++)
this.matrix[i][j] = new Cell();
}
/**
* Scopre la cella dalle coordinate selezionate.<br>
* Se la cella e' in uno stato di {@link CellStatus}.DANGEROUS,<br>
* essa non verra' scoperta e la funzione terminara'.<br>
* Se il campo non e' ancora stato creato, viene automaticamente creato.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public void cellUncover(int x, int y) {
checkCoordinates(x, y);
if(!isGenerated)
generateField(x, y);
if(!cellIsUncovered(x, y) && matrix[x][y].getStatus() != CellStatus.DANGEROUS) {
matrix[x][y].uncover();
numCoveredCell--;
if(matrix[x][y].nearMine == 0 && !matrix[x][y].isMine())
cellUncoverNeighbors(x, y);
}
}
/**
* Scopre la cella dalle coordinate selezionate.<br>
* Se la cella e' in uno stato di {@link CellStatus}.DANGEROUS,<br>
* essa <b>VERRA'</b> comunque scoperta.<br>
* Se il campo non e' ancora stato creato, viene automaticamente creato.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public void cellUncoverIngnoringDangerousState(int x, int y) {
checkCoordinates(x, y);
if(!isGenerated)
generateField(x, y);
if(!cellIsUncovered(x, y)) {
matrix[x][y].uncover();
numCoveredCell--;
if(matrix[x][y].nearMine == 0 && matrix[x][y].isMine() == false)
cellUncoverNeighbors(x, y);
}
}
/**
* Setta una determinata cella come {@link CellStatus}.DANGEROUS<br>
* Se la cella e' gia stata scoperta non succedera' nulla.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public void cellSetDangerous(int x, int y) {
checkCoordinates(x, y);
if(numMines != numDangerousCell && matrix[x][y].getStatus() == CellStatus.COVERED) {
matrix[x][y].setDangerous();
numDangerousCell++;
}
}
/**
* Toglie alla cella lo status di {@link CellStatus}.DANGEROUS<br>
* Se la cella non e' in stato di DANGEROUS, la funzione non fa nulla.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public void cellSetNotDangerous(int x, int y) {
checkCoordinates(x, y);
if(matrix[x][y].getStatus() == CellStatus.DANGEROUS) {
matrix[x][y].setNotDangerous();
numDangerousCell--;
}
}
/**
* Dice se la cella e' stata scoperta o meno.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se e' stata scoperta
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public boolean cellIsUncovered(int x, int y) {
checkCoordinates(x, y);
return matrix[x][y].isUncovered();
}
/**
* Indica se la cella e' nello stato pericoloso.<br>
* Per info: {@link CellStatus}.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se lo e'
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public boolean cellIsDangerous(int x, int y) {
return matrix[x][y].getStatus() == CellStatus.DANGEROUS;
}
/**
* Indica se la cella e' esplosa.<br>
* Per info: {@link CellStatus}.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se lo e'
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public boolean cellIsExploded(int x, int y) {
return matrix[x][y].getStatus() == CellStatus.EXPLODED;
}
/**
* Indica se la cella e' stata marchiata come pericolosa,<br>
* e alla fine del gioco e' risultata essere una mina.<br>
* Per info: {@link CellStatus}.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se lo e'
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public boolean cellIsGotRight(int x, int y) {
return matrix[x][y].getStatus() == CellStatus.GOTRIGHT;
}
/**
* Indica se la cella e' una mina o meno.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se e' una mina
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public boolean cellIsMine(int x, int y) {
checkCoordinates(x, y);
return matrix[x][y].isMine();
}
/**
* Serve ad avere lo stato della cella.<br>
* Vedi {@link CellStatus} per i possibili valori.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return lo stato della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public CellStatus cellGetStatus(int x, int y) {
checkCoordinates(x, y);
return matrix[x][y].getStatus();
}
/**
* Indica il numero di mine vicine alla cella richiesta.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return il numero di mine vicine alla cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public int cellGetNumNearMines(int x, int y) {
checkCoordinates(x, y);
return matrix[x][y].nearMine;
}
/**
* @return il numero delle mine che il campo contiene
*/
public int getNumMines() {
return numMines;
}
/**
* @return il numero di celle ancora da scoprire
*/
public int getNumCoveredCell() {
return numCoveredCell;
}
/**
* @return il numero delle celle gia scoperto
*/
public int getNumUncoveredCell() {
return ( lines * columns ) - numCoveredCell;
}
/**
* @return il numero delle celle segnate pericolose
*/
public int getNumDagerousCell() {
return numDangerousCell;
}
/**
* Restituisce la cella desiderata. Restituendo la cella<br>
* questa funzione puo' esser considerata un modo per<br>
* rendere le cose piu' facili.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return la cella desiderata
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
public Cell getCell(int x, int y) {
checkCoordinates(x, y);
return matrix[x][y];
}
/**
* Funzione che inserisce nel campo gia creato mine e numeri.<br>
* La funzione <b>DEVE</b> aggiornare il campo {@link #isGenerated},<br>
* in modo che sia generato una sola volta il campo.<br>
* Per creare il campo si possono usare le funzioni<br>
* {@link #insertMine(int, int)} e {@link #updateNumNearMines(int, int)} gia fornite.<br>
* Nel caso non si usasse questa funzione nel costruttore,<br>
* essa viene richiamata nella funzione {@link #cellUncover(int, int)}.<br>
* Il campo isGenerated evita che venga ripetuta l'operazione piu' volte,<br>
* quindi e' necessario che venga aggiornata in questa funzione.<br>
* Le coordinate sono fornite per passare, per esempio,<br>
* il punto della cella da cui l'utente ha iniziato a giocare.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
*/
protected abstract void generateField(int x, int y);
/**
* Marchia la cella come mina se non lo e' gia<br>
* Aaggiorna inoltre quante mine ci sono nel campo<br>
* reperibili tramite {@link #getNumMines()}.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return true se la mina e' stata piazzata, false se la mina era gia presente
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
protected boolean insertMine(int x, int y) {
checkCoordinates(x, y);
if(!matrix[x][y].isMine()) {
matrix[x][y].setMine();
numMines++;
return true;
}
return false;
}
/**
* Aggiorna il numero di mine che si trovano vicino alla cella richiesta.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @return Il numero di mine che la cella ha intorno
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
protected int updateNumNearMines(int x, int y) {
checkCoordinates(x, y);
for(int i=x-1; i<=x+1; i++)
for(int j=y-1; j<=y+1; j++) try {
checkCoordinates(i, j);
if(matrix[i][j].isMine() && (i!=x || j!=y))
matrix[x][y].nearMine++;
} catch(OutOfBoundsException e) { /* do nothing and go on */ }
return matrix[x][y].nearMine;
}
/**
* Funzione che serve a controllare se le coordinate sono consone al campo.<br>
* Nel caso non lo siano, il programma lancera' una eccezione.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
* @throws OutOfBoundsException nel caso in cui si inseriscano coordinate sbagliate
*/
private void checkCoordinates(int x, int y) {
if(x<0 || y<0 || x>=lines || y>=columns)
throw new OutOfBoundsException("coordinates must be inside the field x(0-"+lines+"), y(0-"+columns+").\tX = "+x+" Y = "+y);
}
/**
* Scopre i vicini della cella che si passa.
*
* @param x Una coordinata della cella
* @param y Una coordinata della cella
*/
private void cellUncoverNeighbors(int x, int y) {
for(int i=x-1; i<=x+1; i++)
for(int j=y-1; j<=y+1; j++)
if(!(i==x && j==y)) try {
this.cellUncover(i, j);
} catch(OutOfBoundsException e) { /* do nothing and go on */ }
}
@Override
public Iterator<Cell> iterator() {
return new FieldIter(this);
}
private class FieldIter implements Iterator<Cell> {
private final Field field;
private int x = 0;
private int y = 0;
private FieldIter(Field field) {
this.field = field;
}
@Override
public boolean hasNext() {
return y + 1 < field.columns;
}
@Override
public Cell next() {
if(x + 1 == field.lines) {
x = 0;
y++;
}
else
x++;
return field.getCell(x, y);
}
}
}

View File

@@ -0,0 +1,61 @@
package berack96.games.minefield.object;
import berack96.games.minefield.runexception.TooHighValueException;
/**
* Classe che crea un campo di celle {@link Cell}.<br>
* Quando l'utente scopre la prima cella, essa puo essere anche una mina.
*
* @author Jack
*
*/
public class FieldNoSafe extends Field{
private final int numMines;
/**
* Costruisce il campo, contenente le mine e quante mine ogni cella ha intorno.
*
* @param columns Una delle grandezze del campo (lunghezza)
* @param lines Una delle grandezze del campo (altezza)
* @param numMines Quante mine deve contenere il campo
* @throws IllegalArgumentException nel caso in cui si inseriscano parametri sbagliati
* @throws TooHighValueException nel caso in cui i parametri siano maggiori di 100
*/
public FieldNoSafe(int columns, int lines, int numMines)
{
super(columns, lines);
if(numMines<=0)
throw new java.lang.IllegalArgumentException("the mines must be greater than 0.");
if(numMines>=columns*lines)
throw new java.lang.IllegalArgumentException("the mines must be less than the size of the whole field.");
this.numMines = numMines;
generateField(0, 0); // use of this function here because don't need safe start
}
/**
* Genera il campo senza considerare le due coordinate in entrata
*/
@Override
protected void generateField(int x, int y)
{
// i will not use the argument, don't need it
super.isGenerated = true;
while(getNumMines()<numMines) // insert mines
{
int randX = (int)(Math.random()*lines);
int randY = (int)(Math.random()*columns);
insertMine(randX, randY);
}
for(int i=0; i<lines; i++) // update neighbor
for(int j=0; j<columns; j++)
updateNumNearMines(i, j);
}
}

View File

@@ -0,0 +1,60 @@
package berack96.games.minefield.object;
import berack96.games.minefield.runexception.TooHighValueException;
/**
* Classe che crea un campo di celle {@link Cell}.<br>
* Quando l'utente scopre la prima cella, essa NON puo essere una mina,<br>
* e non puo avere mine intorno.
*
* @author Jack
*
*/
public class FieldSafe extends Field{
private final int numMines;
/**
* Crea il campo vouto. Esso si riempira' non appena verra'<br>
* scoperta la prima cella con al funzione {@link #cellUncover(int, int)}
* @param columns Una delle grandezze del campo.
*
* @param lines Una delle grandezze del campo
* @param numMines Quante mine deve contenere il campo
* @throws IllegalArgumentException nel caso in cui si inseriscano parametri sbagliati
* @throws TooHighValueException nel caso in cui i parametri siano maggiori di 100
*/
public FieldSafe(int columns, int lines, int numMines) {
super(columns, lines);
if(numMines<=0)
throw new java.lang.IllegalArgumentException("the mines must be greater than 0.");
if(numMines>=columns*lines-8)
throw new java.lang.IllegalArgumentException("the mines must be less than the size of the whole field -8 (for the safe start).");
this.numMines = numMines;
}
/**
* Genera il campo non creando mine vicino alla cella indicata dalle due coordinate
*/
@Override
protected void generateField(int x, int y) {
isGenerated = true;
while(this.getNumMines()<numMines) // insert mines
{
int randX = (int)(Math.random()*lines);
int randY = (int)(Math.random()*columns);
if((randX>=x-1 && randX<=x+1 && randY>=y-1 && randY<=y+1) == false)
this.insertMine(randX, randY);
}
for(int i=0; i<lines; i++)
for(int j=0; j<columns; j++)
this.updateNumNearMines(i, j); // update neighbor
}
}

View File

@@ -0,0 +1,41 @@
package berack96.games.minefield.object.view;
import javax.swing.ImageIcon;
/**
* Classe che contiene solamente le immagini da mostrare nel caso le si vogliano usare
*
* @author Jack
*
*/
public class CellIcons
{
public static final ImageIcon mine = createImageIcon("mine.png");
public static final ImageIcon flag = createImageIcon("flag.png");
public static final ImageIcon flagRight = createImageIcon("flagRight.png");
public static final ImageIcon flagWrong = createImageIcon("flagWrong.png");
public static final ImageIcon one = createImageIcon("1one.png");
public static final ImageIcon two = createImageIcon("2two.png");
public static final ImageIcon three = createImageIcon("3three.png");
public static final ImageIcon four = createImageIcon("4four.png");
public static final ImageIcon five = createImageIcon("5five.png");
public static final ImageIcon six = createImageIcon("6six.png");
public static final ImageIcon seven = createImageIcon("7seven.png");
public static final ImageIcon eight = createImageIcon("8eight.png");
private static final String path = "berack96/games/minefield/assets/icons/";
private static ImageIcon createImageIcon(String name)
{
java.net.URL imgURL = ClassLoader.getSystemResource(path+name);
if (imgURL != null)
return new ImageIcon(imgURL);
else
{
System.err.println("Couldn't find file: " + name);
return null;
}
}
}

View File

@@ -0,0 +1,213 @@
package berack96.games.minefield.object.view;
import java.awt.Color;
import java.awt.Dimension;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import berack96.games.minefield.object.Cell;
import berack96.games.minefield.object.CellStatus;
/**
* Classe che serve a restituire graficamente (stringa o jlabel) la cella che si desidera.
*
* @author Jack
*
*/
public class CellView implements Observer {
private final Cell cell;
private String string;
private JLabel label;
/**
* Costruttore: la cella passata, sara' ora osservvata dall'istanza creata
*
* @param cell La cella
*/
public CellView(Cell cell)
{
this.cell = cell;
cell.addObserver(this);
string = CellView.toString(cell);
label = CellView.toJLabel(cell);
}
/**
* Ritorna la rappresentazione della cella sottoforma di stringa:<br>
* [ ] - {@link CellStatus#UNCOVERED} 0 mine vicine<br>
* [n] - {@link CellStatus#UNCOVERED} con "n" mine vicine<br>
* [D] - {@link CellStatus#DANGEROUS}<br>
* [*] - {@link CellStatus#EXPLODED}<br>
* [V] - {@link CellStatus#GOTRIGHT}<br>
* [X] - {@link CellStatus#GOTWRONG}<br>
* [#] - {@link CellStatus#COVERED}<br>
*
* @return String
*/
public String toString()
{
return string;
}
/**
* Ritorna la rappresentazione della cella sottoforma di JLabel:<br>
* {@link CellStatus#UNCOVERED} bianco con eventuale numero<br>
* {@link CellStatus#DANGEROUS} con icona di una bandiera<br>
* {@link CellStatus#EXPLODED} con una icona di una mina<br>
* {@link CellStatus#GOTRIGHT} con una icona di una bandierina cerchiata di verde<br>
* {@link CellStatus#GOTWRONG} - con una icona di una bandierina crociata di rosso<br>
* {@link CellStatus#COVERED} - grigio chiaro<br>
*
* @return JLabel
*/
public JLabel toJLabel()
{
return label;
}
@Override
public void update(Observable arg0, Object arg1)
{
CellStatus status = cell.getStatus();
if(status == CellStatus.UNCOVERED)
{
label.setBackground(Color.WHITE);
label.setIcon(null);
if(cell.nearMine == 0)
string = "[ ]";
else
{
string = "["+cell.nearMine+"]";
switch(cell.nearMine)
{
case 1:
label.setIcon(CellIcons.one);
break;
case 2:
label.setIcon(CellIcons.two);
break;
case 3:
label.setIcon(CellIcons.three);
break;
case 4:
label.setIcon(CellIcons.four);
break;
case 5:
label.setIcon(CellIcons.five);
break;
case 6:
label.setIcon(CellIcons.six);
break;
case 7:
label.setIcon(CellIcons.seven);
break;
case 8:
label.setIcon(CellIcons.eight);
break;
}
}
}
else if(status == CellStatus.DANGEROUS)
{
string = "[D]";
label.setBackground(Color.LIGHT_GRAY);
label.setIcon(CellIcons.flag);
}
else if(status == CellStatus.EXPLODED)
{
string = "[*]";
label.setBackground(Color.LIGHT_GRAY);
label.setIcon(CellIcons.mine);
}
else if(status == CellStatus.GOTRIGHT)
{
string = "[V]";
label.setBackground(Color.LIGHT_GRAY);
label.setIcon(CellIcons.flagRight);
}
else if(status == CellStatus.GOTWRONG)
{
string = "[X]";
label.setBackground(Color.LIGHT_GRAY);
label.setIcon(CellIcons.flagWrong);
}
else
{
string = "[#]";
label.setBackground(Color.LIGHT_GRAY);
label.setIcon(null);
}
}
/**
* Metodo statico che serve, passata una cella, a trasformarla in stringa<br>
* secondo {@link #toString()}.
*
* @param cell La cella da vedere
* @return String
*/
public static String toString(Cell cell)
{
CellStatus status = cell.getStatus();
if(status == CellStatus.UNCOVERED)
{
if(cell.nearMine == 0)
return "[ ]";
else
return "["+cell.nearMine+"]";
}
else if(status == CellStatus.DANGEROUS)
return "[D]";
else if(status == CellStatus.EXPLODED)
return "[*]";
else if(status == CellStatus.GOTRIGHT)
return "[V]";
else
return "[#]";
}
/**
* Metodo statico che serve, passata una cella, a trasformarla in jpanel<br>
* secondo {@link #toJLabel()}.
*
* @param cell La cella da vedere
* @return JLabel
*/
public static JLabel toJLabel(Cell cell)
{
CellStatus status = cell.getStatus();
JLabel label = new JLabel();
label.setOpaque(true);
label.setBorder(BorderFactory.createLineBorder(Color.BLACK));
label.setPreferredSize(new Dimension(25, 25));
label.setSize(label.getPreferredSize());
label.setVisible(true);
if(status == CellStatus.UNCOVERED)
{
label.setBackground(Color.WHITE);
if(cell.nearMine != 0)
label.setText("["+cell.nearMine+"]");
}
else if(status == CellStatus.DANGEROUS)
label.setBackground(Color.BLACK);
else if(status == CellStatus.EXPLODED)
label.setBackground(Color.RED);
else if(status == CellStatus.GOTRIGHT)
label.setBackground(Color.GREEN);
else
label.setBackground(Color.LIGHT_GRAY);
return label;
}
}

View File

@@ -0,0 +1,119 @@
package berack96.games.minefield.object.view;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import berack96.games.minefield.listener.CellInFieldListener;
import berack96.games.minefield.object.Field;
/**
* Classe che mostra il campo da gioco in modo grafico (tramite stringhe o jpanel).
*
* @author Jack
*
*/
public class FieldView {
private final Field field;
private String string;
private JPanel panel;
/**
* Costruttore in cui si inserisce il campo e un eventuale listener<br>
* su ogni cella del campo
*
* @param field Il campo da vedere
* @param listener il controllore delle celle
*/
public FieldView(Field field, CellInFieldListener listener)
{
this.field = field;
string = toString(field);
panel = toJPanel(field, listener);
}
/**
* Restituisce il campo sottoforma di stringa.<br>
* Per valori celle vedi {@link CellView#toString()}.
*
* @return String
*/
public String toString()
{
string = toString(field);
return string;
}
/**
* Restituisce il campo sottoforma di jpanel.<br>
* Per valori celle vedi {@link CellView#toJLabel()}.
*
* @return JPanel
*/
public JPanel toJPanel()
{
return panel;
}
/**
* Metodo statico che serve, passato un campo, a trasformarlo in stringa<br>
* secondo {@link #toString()}.
*
* @param field il campo da vedere
* @return String
*/
public static String toString(Field field)
{
String string = new String();
for(int i=0; i<field.lines; i++)
{
for(int j=0; j<field.columns; j++)
string += CellView.toString(field.getCell(i, j));
string += "\n";
}
return string;
}
/**
* Metodo statico che serve, passato un campo, a trasformarlo in jpanel<br>
* secondo {@link #toJPanel()}.
*
* @param field il campo da vedere
* @param listener eventuale controller da applicare ad ogni cella
* @return JPanel
*/
public static JPanel toJPanel(Field field, CellInFieldListener listener)
{
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(field.lines, field.columns));
panel.setVisible(true);
for(int i=0; i<field.lines; i++)
for(int j=0; j<field.columns; j++)
{
JLabel cell = new CellView(field.getCell(i, j)).toJLabel();
cell.setName(i+"-"+j);
if(listener != null)
cell.addMouseListener(listener);
panel.add(cell);
}
Dimension dim = CellView.toJLabel(field.getCell(0, 0)).getPreferredSize();
panel.setPreferredSize(new Dimension(dim.height*field.columns, dim.width*field.lines));
panel.setSize(panel.getPreferredSize());
return panel;
}
}

View File

@@ -0,0 +1,23 @@
package berack96.games.minefield.runexception;
/**
* Lanciata perche' le coordinate indicano una area al di fuori del campo.
*
* @author Jack
*
*/
public class OutOfBoundsException extends RuntimeException {
private static final long serialVersionUID = 1L;
public OutOfBoundsException()
{
super();
}
public OutOfBoundsException(String arg0)
{
super(arg0);
}
}

View File

@@ -0,0 +1,23 @@
package berack96.games.minefield.runexception;
/**
* Lanciata perche' il valore inserito e' torppo alto
*
* @author Jack
*
*/
public class TooHighValueException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TooHighValueException()
{
super();
}
public TooHighValueException(String arg0)
{
super(arg0);
}
}

View File

@@ -0,0 +1,217 @@
package jbook.util;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Vector;
/**
Una semplice classe per leggere stringhe e numeri
dallo standard input.
*/
public class Input{
private static BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
/**
Legge una linea di input. Nell'improbabile caso di una
IOException, il programma termina.
@return restituisce la linea di input che l'utente ha battuto.
*/
public static String readString(){
String inputLine = "";
try{
inputLine = reader.readLine();
}
catch(IOException e){
System.out.println(e);
System.exit(1);
}
return inputLine;
}
public static String readString(String msg){
System.out.print(msg);
String inputLine = readString();
return inputLine;
}
/**
Legge una linea di input e la converte in un byte.
Eventuali spazi bianchi prima e dopo l'intero vengono ignorati.
@return l'intero dato in input dall'utente
*/
public static byte readByte(){
String inputString = readString();
inputString = inputString.trim();
byte n = Byte.parseByte(inputString);
return n;
}
public static byte readByte(String msg){
System.out.print(msg);
byte n = readByte();
return n;
}
/**
Legge una linea di input e la converte in uno short.
Eventuali spazi bianchi prima e dopo l'intero vengono ignorati.
@return l'intero dato in input dall'utente
*/
public static short readShort(){
String inputString = readString();
inputString = inputString.trim();
short n = Short.parseShort(inputString);
return n;
}
public static short readShort(String msg){
System.out.print(msg);
short n = readShort();
return n;
}
/**
Legge una linea di input e la converte in un int.
Eventuali spazi bianchi prima e dopo l'intero vengono ignorati.
@return l'intero dato in input dall'utente
*/
public static int readInt(){
String inputString = readString();
inputString = inputString.trim();
int n = Integer.parseInt(inputString);
return n;
}
public static int readInt(String msg){
System.out.print(msg);
int n = readInt();
return n;
}
/**
Legge una linea di input e la converte in un long.
Eventuali spazi bianchi prima e dopo l'intero vengono ignorati.
@return l'intero dato in input dall'utente
*/
public static long readLong(){
String inputString = readString();
inputString = inputString.trim();
long n = Long.parseLong(inputString);
return n;
}
public static long readLong(String msg){
System.out.print(msg);
long n = readLong();
return n;
}
/**
Legge una linea di input e la converte in un numero
in virgola mobile a precisione singola. Eventuali spazi bianchi prima e
dopo il numero vengono ignorati.
@return il numero dato in input dall'utente
*/
public static float readFloat(){
String inputString = readString();
inputString = inputString.trim();
float x = Float.parseFloat(inputString);
return x;
}
public static float readFloat(String msg){
System.out.print(msg);
float x = readFloat();
return x;
}
/**
Legge una linea di input e la converte in un numero
in virgola mobile a precisione doppia. Eventuali spazi bianchi prima e
dopo il numero vengono ignorati.
@return il numero dato in input dall'utente
*/
public static double readDouble(){
String inputString = readString();
inputString = inputString.trim();
double x = Double.parseDouble(inputString);
return x;
}
public static double readDouble(String msg){
System.out.print(msg);
double x = readDouble();
return x;
}
/**
Legge una linea di input e ne estrae il primo carattere.
@return il primo carattere della riga data in input dall'utente
*/
public static char readChar(){
String inputString = readString();
char c = inputString.charAt(0);
return c;
}
public static char readChar(String msg){
System.out.print(msg);
char c = readChar();
return c;
}
/**
Legge una linea di input e restituisce true se la stringa
e' equals a "true" a meno di maiuscole e minuscole, false altrimenti.
@return il booeano dato in input dall'utente
*/
public static boolean readBool(){
String inputString = readString();
inputString = inputString.trim();
boolean b = Boolean.parseBoolean(inputString);
return b;
}
public static boolean readBool(String msg){
System.out.print(msg);
boolean b = readBool();
return b;
}
/**
Legge una sequenza di stringhe conclusa dalla stringa vuota e
restituisce la sequenza in un nuovo array di stringhe.
@return l'array delle stringhe date in input dal'utente
*/
public static String[] readSeq(){
String[] seq = readSeq("");
return seq;
}
public static String[] readSeq(String prompt){
Vector<String> seqTemp = new Vector<String>();
System.out.print(prompt);
String inputString = readString();
while (inputString.length()>0) {
seqTemp.add(inputString);
System.out.print(prompt);
inputString = readString();
}
String[] seq = new String[seqTemp.size()];
return seqTemp.toArray(seq);
}
public static String[] readSeq(String msg, String prompt){
System.out.println(msg);
String[] seq = readSeq(prompt);
return seq;
}
}

View File

@@ -0,0 +1,59 @@
package berack96.test.games.minefield;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import berack96.games.minefield.object.Cell;
import berack96.games.minefield.object.CellStatus;
public class TestCell {
public Cell cell;
@BeforeAll
public void initialize() {
cell = new Cell();
assertEquals(cell.getStatus(), CellStatus.COVERED);
}
@Test
public void cellUncover() {
assertFalse(cell.isUncovered());
cell.uncover();
assertTrue(cell.isUncovered());
assertEquals(cell.getStatus(), CellStatus.UNCOVERED);
}
@Test
public void cellMine() {
assertFalse(cell.isMine());
cell.setMine();
assertFalse(cell.isUncovered());
assertTrue(cell.isMine());
}
@Test
public void cellDangerous() {
cell.setDangerous();
assertFalse(cell.isUncovered());
assertEquals(cell.getStatus(), CellStatus.DANGEROUS);
}
@Test
public void cellUncoveredMine() {
cell.setMine();
cell.uncover();
assertEquals(cell.getStatus(), CellStatus.EXPLODED);
}
@Test
public void cellUncoveredMineDangerous() {
cell.setMine();
cell.setDangerous();
cell.uncover();
assertEquals(cell.getStatus(), CellStatus.GOTRIGHT);
}
}

View File

@@ -0,0 +1,31 @@
package berack96.test.games.minefield;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import berack96.games.minefield.object.FieldNoSafe;
public class TestFieldNoSafe {
public FieldNoSafe field;
public final int height = 10;
public final int length = 20;
public final int mines = 10;
@BeforeAll
public void initialize() {
field = new FieldNoSafe(this.length, this.height, this.mines);
}
@Test
public void fieldStart() {
assertEquals(field.lines, this.height);
assertEquals(field.lines, this.length);
assertEquals(field.getNumCoveredCell(), this.height*this.length);
assertEquals(field.getNumDagerousCell(), 0);
assertEquals(field.getNumUncoveredCell(), 0);
assertEquals(field.getNumMines(), this.mines);
}
}

View File

@@ -0,0 +1,7 @@
package berack96.test.games.minefield;
public class TestFieldSafe {
}