From 6543c21363b39506d32f86342521ee204b19018a Mon Sep 17 00:00:00 2001 From: Berack96 Date: Mon, 3 Oct 2022 01:18:19 +0200 Subject: [PATCH] Initial Commit - upload to github --- .gitignore | 1 + pom.xml | 51 +++ .../java/berack96/games/minefield/Game.java | 201 +++++++++ .../java/berack96/games/minefield/Mode.java | 34 ++ .../games/minefield/assets/icons/1one.png | Bin 0 -> 378 bytes .../games/minefield/assets/icons/2two.png | Bin 0 -> 459 bytes .../games/minefield/assets/icons/3three.png | Bin 0 -> 525 bytes .../games/minefield/assets/icons/4four.png | Bin 0 -> 460 bytes .../games/minefield/assets/icons/5five.png | Bin 0 -> 532 bytes .../games/minefield/assets/icons/6six.png | Bin 0 -> 546 bytes .../games/minefield/assets/icons/7seven.png | Bin 0 -> 385 bytes .../games/minefield/assets/icons/8eight.png | Bin 0 -> 561 bytes .../games/minefield/assets/icons/flag.png | Bin 0 -> 510 bytes .../minefield/assets/icons/flagRight.png | Bin 0 -> 882 bytes .../minefield/assets/icons/flagWrong.png | Bin 0 -> 788 bytes .../games/minefield/assets/icons/mine.png | Bin 0 -> 985 bytes .../games/minefield/frame/EndFrame.java | 84 ++++ .../games/minefield/frame/GameFrame.java | 120 +++++ .../games/minefield/frame/MenuFrame.java | 366 +++++++++++++++ .../minefield/frame/strings/StringError.java | 26 ++ .../minefield/frame/strings/StringMode.java | 19 + .../minefield/frame/strings/StringSafe.java | 10 + .../listener/CellInFieldListener.java | 112 +++++ .../minefield/listener/EndFrameListener.java | 60 +++ .../minefield/listener/MenuFrameListener.java | 89 ++++ .../berack96/games/minefield/object/Cell.java | 139 ++++++ .../games/minefield/object/CellStatus.java | 41 ++ .../games/minefield/object/Decisor.java | 160 +++++++ .../games/minefield/object/Field.java | 415 ++++++++++++++++++ .../games/minefield/object/FieldNoSafe.java | 61 +++ .../games/minefield/object/FieldSafe.java | 60 +++ .../minefield/object/view/CellIcons.java | 41 ++ .../games/minefield/object/view/CellView.java | 213 +++++++++ .../minefield/object/view/FieldView.java | 119 +++++ .../runexception/OutOfBoundsException.java | 23 + .../runexception/TooHighValueException.java | 23 + src/main/java/jbook/util/Input.java | 217 +++++++++ .../test/games/minefield/TestCell.java | 59 +++ .../test/games/minefield/TestFieldNoSafe.java | 31 ++ .../test/games/minefield/TestFieldSafe.java | 7 + 40 files changed, 2782 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/berack96/games/minefield/Game.java create mode 100644 src/main/java/berack96/games/minefield/Mode.java create mode 100644 src/main/java/berack96/games/minefield/assets/icons/1one.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/2two.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/3three.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/4four.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/5five.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/6six.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/7seven.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/8eight.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/flag.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/flagRight.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/flagWrong.png create mode 100644 src/main/java/berack96/games/minefield/assets/icons/mine.png create mode 100644 src/main/java/berack96/games/minefield/frame/EndFrame.java create mode 100644 src/main/java/berack96/games/minefield/frame/GameFrame.java create mode 100644 src/main/java/berack96/games/minefield/frame/MenuFrame.java create mode 100644 src/main/java/berack96/games/minefield/frame/strings/StringError.java create mode 100644 src/main/java/berack96/games/minefield/frame/strings/StringMode.java create mode 100644 src/main/java/berack96/games/minefield/frame/strings/StringSafe.java create mode 100644 src/main/java/berack96/games/minefield/listener/CellInFieldListener.java create mode 100644 src/main/java/berack96/games/minefield/listener/EndFrameListener.java create mode 100644 src/main/java/berack96/games/minefield/listener/MenuFrameListener.java create mode 100644 src/main/java/berack96/games/minefield/object/Cell.java create mode 100644 src/main/java/berack96/games/minefield/object/CellStatus.java create mode 100644 src/main/java/berack96/games/minefield/object/Decisor.java create mode 100644 src/main/java/berack96/games/minefield/object/Field.java create mode 100644 src/main/java/berack96/games/minefield/object/FieldNoSafe.java create mode 100644 src/main/java/berack96/games/minefield/object/FieldSafe.java create mode 100644 src/main/java/berack96/games/minefield/object/view/CellIcons.java create mode 100644 src/main/java/berack96/games/minefield/object/view/CellView.java create mode 100644 src/main/java/berack96/games/minefield/object/view/FieldView.java create mode 100644 src/main/java/berack96/games/minefield/runexception/OutOfBoundsException.java create mode 100644 src/main/java/berack96/games/minefield/runexception/TooHighValueException.java create mode 100644 src/main/java/jbook/util/Input.java create mode 100644 src/test/java/berack96/test/games/minefield/TestCell.java create mode 100644 src/test/java/berack96/test/games/minefield/TestFieldNoSafe.java create mode 100644 src/test/java/berack96/test/games/minefield/TestFieldSafe.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f97022 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f453be4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + berack96 + Minefield + 1.0.1 + + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.2 + + + jar-with-dependencies + + + + berack96.games.minefield.Game + + + + + + package + + single + + + + + + + + 17 + 17 + + + \ No newline at end of file diff --git a/src/main/java/berack96/games/minefield/Game.java b/src/main/java/berack96/games/minefield/Game.java new file mode 100644 index 0000000..2c9b71e --- /dev/null +++ b/src/main/java/berack96/games/minefield/Game.java @@ -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.
+ * Il gioco puo' esser fatto partire per console o come finestra.
+ * Senza argomenti il gioco partira' in finestra.
+ *
+ * Lista dei possibili argomenti da passare al programma:
+ * -nogui indica che il gioco partira' su console.
+ * -safe=(true/false)
+ * -mode=(EASY/MEDIUM/HARD/CUSTOM)
+ * -dim=(colonne),(righe)
+ * -mines=(num)
+ * + * Questi argomenti per ora funzionano solo con il gioco in console
+ * 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(nummax) { + 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; + } +} diff --git a/src/main/java/berack96/games/minefield/Mode.java b/src/main/java/berack96/games/minefield/Mode.java new file mode 100644 index 0000000..42e5b18 --- /dev/null +++ b/src/main/java/berack96/games/minefield/Mode.java @@ -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.
+ * Insomma serve a velocizzare la partenza del gioco.
+ * 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 +} diff --git a/src/main/java/berack96/games/minefield/assets/icons/1one.png b/src/main/java/berack96/games/minefield/assets/icons/1one.png new file mode 100644 index 0000000000000000000000000000000000000000..4949a062c27834316f87f6ed3921aaae5aa2310f GIT binary patch literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6;>1s;*b z3=DkxL735kHCP3tqr^3$Bsf2dM2(jS679tUg=};n>Q-)f`WpMF3gX_Il`1WRGLzopr0F1|ziU0rr literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/assets/icons/2two.png b/src/main/java/berack96/games/minefield/assets/icons/2two.png new file mode 100644 index 0000000000000000000000000000000000000000..0628f66eea2a8d5b4da589404b1f6c8a28cb861c GIT binary patch literal 459 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6;>1s;*b z3=DkxK$!8B)5ZfpLCF%=h?3y^w370~qEv>0#LT=By}Z;C1rt33JwtQjy!k+r7(F~) z978<3lOh5RQ*zsL1WD3&-l?D8% z3!9?i@>}{Vt}a;gr1Ag%|IU#a3wpyP5;^;ML#Eg?Tox**IjHk6yrC;d^2$dQ=jK<8 zAuXpI-r6f0aLThq2OYPT)$&RWI3CTzyGqZCyd^4Z#t%`-KeT@*H(%bj^8Hvb98Fq0c9VBTSB#3s}P!is`U+KJ>Y@gkgtc zXw0Mo3Qb~)HSR0Y7-dSjiP000>X1^@s6#OZ}&00004XF*Lt006O% z3;baP00009a7bBm000iX000iX0Z03gtpET38FWQhbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMF*h@ApJM<30g6dPK~zXf?Uk=f1VI>vzrC3|5j=l^`UhCVESf|x2nLHqFxU(t zh+s3gpy9w|5p4=0f<=>Eu!(|EFc~Zg7Na=6GyCoAhwI6?v+-Vd*_+*&=h@l48>^cM=8{=oPKolXUXMOZQj;2VRRRLup60GY6$&q!}# zY0ZO3kD;$Dd7`);@seTzypOhfBYCGRT2Cal)XCGsA_ZU@4ON%rE`oLh z=oC5$@C=Tt=y@V?J>zL%k~AKI-vxxTnMgH~3nj!#oG9*&?0W!wpCxxZrFhaEcnQB~ z2-aBg=q7|Dh3888B$4P-p8Ee_@sWMrhB}7xg31C5(8^NoI@(eIIL<)o7RO8U0-x{2 z`NQ7?wtvP?B&q|l2iS84^>F;ZR2C()SzC^w+6ds|IF4djl~1=*c8I!lvI6;>1s;*b z3=DjGL736~_k^_|9VM<2CBgY=CFO}lsSE{)nRz98d8s7|CVB>XhUUh3^MNKYdV0Dz zhIn`rj+X>BVqH zV1whKub&%!*voKVZ4bCAv|yp1hFHUfgjfqRZ;$O;JR3NDxUb4LNyN-=N(mHs$@Yjz z>1(Ed^Xq$!KMTBHC9O>EOtBTeAbx%UTXw_IglQaCj|UzXTDU83#p-Y;*A+RP4!w4F z95fiDy+XZPUR`tMJ>A?Da8qdEt%Q!m()@)=2@bK|EwA;Od4<+&Z|rJd{HoLV(`m&! z{R^A=9sWq2U|Y6f7rR4q{y|;Ab-P(a>^V~W8(yg}a$Hqc;89}YzM9+iN=2~a+UkU( zN?)@)#HKLFE;)K2UZ3GAE87AE6)TCvu8W2SGyXa1avo6QKg_~t=4-&iGjIJ59YxLr zV}_PSyUOO%LRw7$X>1RJ;xyWCwe`mwIKaRVf7$;Y!=*R>fFaM|>FVdQ&MBb@09T)` AH2?qr literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/assets/icons/5five.png b/src/main/java/berack96/games/minefield/assets/icons/5five.png new file mode 100644 index 0000000000000000000000000000000000000000..7c4d189684a2b2bae4f1db8f7ebcf3bc8aa4a0ed GIT binary patch literal 532 zcmV+v0_**WP)P000>X1^@s6#OZ}&00004XF*Lt006O% z3;baP00009a7bBm000iX000iX0Z03gtpET38FWQhbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMF*h@ApJM<30g*{WK~zXf?UX-D13?hQCw2<4RtO}y3w{K#5-bEOKZAuN@x&sn zg+U7u3sJBW6tT02g`dDu6vfuU&c;57)%j-GfyuZD$woUL{J8xy^WNR%vJ|U4&mF%m zF&1+@m$k8E4f_$TkXeW*apOix9q`(ZWLbJ{5ucpc`49D=YHS2(uX z#h(8IgV*)pLK3?2RZi|ky!1FIn4D%Qt!QJWK1)+DKi~kSUZF)>qxm7di95XUMsI+R zd}pf3YShv_8u1$_yz5mMb?`)A#{3i9HfyxN#|oIR=26P000>X1^@s6#OZ}&00004XF*Lt006O% z3;baP00009a7bBm000iX000iX0Z03gtpET38FWQhbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMF*h@ApJM<30iQ`kK~zXf&6F`q13?glUn&tyKoBei8xaI61yRt_B1-mRBnaC3 z8^i>)vak!l+mX<$rD&a4PpM4uTOxXJ#i<#SM2M}RxZpOiz&-;{4Dukb7WCTqP6A0gP22B*iq zy&`v2ktdUT4O6&53Bv}cp>yb`xha1GmcoX7?G-BMu?;l1UdTmbZz(*>DylX-0%tZ+ z7!!k68*GO$Va4YEtN^QG($tL=bfb(JdS0Ly#VopPun9LQY>NqR*^wUqj!l09R)9tf zsBp?qI!!eiA6T_U7Lz>j#AhX zlZ!M14yr$jNnN@erRY4hOy1HAIH>+ECQH)gsCf(tfcLzZVlWxi=}5YQ+lyPpoH-2P|UHZv`UV$TvK|bprlD^M}b>pGg|PTU5dX k84TE9JKC;)fp)NfAFDjEE4z`R`Tzg`07*qoM6N<$g2dd|CjbBd literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/assets/icons/7seven.png b/src/main/java/berack96/games/minefield/assets/icons/7seven.png new file mode 100644 index 0000000000000000000000000000000000000000..6100a02d354f7e4aab5ffe11c677460fb673486f GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6;>1s;*b z3=DjGL736~_k^_|9VM<2CBgY=CFO}lsSE{)nRz98d8s7|CVB>XhUUh3^Fb#4^K@|x z@$h~-;bJ;~!=wu}pZ+Os>d-tG_(@{AM$w^Ty_yJM}q- zCaAbFUjHM`K7mnxM)SjmyRV1Z79?|uuacLtb&$T+6my|#?F8E=Nv~hKJ4=VO#9ZiG zJ3;lyqa{o|tr-PMZ*OzWbn>flI)04vgly5LJ7EsuMMk=t7p@4;p8r46L@kp2I&;c_ zHr>rVG44xT*r!^#&d%N3V{CI&%IHDHpX^D8y>yn^ihernaDvx(+J}eo-_AN@NXJz6 cZ|oGvU$_3jiuV;+ppanjboFyt=akR{0NFpFa{vGU literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/assets/icons/8eight.png b/src/main/java/berack96/games/minefield/assets/icons/8eight.png new file mode 100644 index 0000000000000000000000000000000000000000..36d9056a68c78e3f970fc63af01e7ed36f729953 GIT binary patch literal 561 zcmV-10?z%3P)P000>X1^@s6#OZ}&00004XF*Lt006O% z3;baP00009a7bBm000iX000iX0Z03gtpET38FWQhbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMF*h@ApJM<30j^0zK~zXf?UTJr13?tT&)AqELO?;AC}L@yLR+!a(#p;cEF)eK z?s9tvN)U-4sEDFqV-aE{SfsGg|3FYXML|0|MG-vb9q)zZu-VI{b70u)yxsY2AhFU^ z7>1EMrj7$hsX}VCT2?95!`ny#XbXbUqUU+%Sf6~~581EqF0z5PAr-GOrxpL@mvXt> zuLF!=cx5mAL1kE7xlAkeBgh|lwy)1jAw_;I6=f*X3y^s{yXGhnWKtmYdcB+DmNZC{ z_Qn7bE*AuX&#N3qqB7)nJeyAh5TRsKK=_5(lvS(MJoaatp9ml^goGl+h4kuMtY5r8 zN(CT7`GJ7g-^y3hsQ?_u8A9Pz450h4EeKxU2g|>Fn=*O1>$!`_erSd>jp#xW;qnfb zTyWHakTIL3IiDHlBWA+o8!lO}R6e5v#3+B`Gs}Fn=?uP000>X1^@s6#OZ}&00004XF*Lt006O$ zeEU(80000WV@Og>004&$004{<009A1004q3004bH008f=0027c000!12prSL00009 za7bBm000ic000ic0Tn1pfB*mh8FWQhbW?9;ba!ELWdLwtX>N2bZe?^JG%heMF*h@A zpJM<30Z&OpK~zXfV;HpHik21|lu3Q?QA$Jjjg)frTWRGvP$B98kjvl5sMNlZR{rr; zM&cbh$&$BH%CbO%7GWBU zjLEd*y_}ljI~kRk*bPO;WLN@3mDmlv0DJb zRET&OcrPz6@LF2Q3FyPcKuh0)d`fjo(7_g;!1Qf?LI2NM*wW6D`uchgApT!hS2t=2 zVK8b5Nq{Pr01dF}>guY%h1=WP=e4x7{0HL8*yLfjwY4=9Y9uD;?(VKReE9HxO7W5< zOYTFBgn-)GT63WHe}XX3Cx03n8~;;^f#&>!nOR+3Ee{GJi-v}V|I?;TqdEq~UvqOa z#FD0_Cam736eC-r1oYx;pdi&TFob4TR8$B90JlFomaVe+-2eap07*qoM6N<$f`Y%* AAOHXW literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/assets/icons/flagRight.png b/src/main/java/berack96/games/minefield/assets/icons/flagRight.png new file mode 100644 index 0000000000000000000000000000000000000000..7707ade2a012ee963da7527493d18fd104afdd42 GIT binary patch literal 882 zcmV-&1C9KNP)P000>X1^@s6#OZ}&00004XF*Lt006O$ zeEU(80000WV@Og>004&$004{<009A1004q3004bH008f=0027c000!12prSL00009 za7bBm000ib000ib0l1NC?EnA(8FWQhbW?9;ba!ELWdLwtX>N2bZe?^JG%heMF*h@A zpJM<30>eo}K~zXf#Z_NOQ*jtoS|QZKARmkkB)!C_$E1Ylp%5~#s9t&*L?Bc?M_rgY zorA$l_v_yhhW5~~hdua^R6ZGu5RB@<2ZJI59|WC^vZA5w>pS;;cW&-(ZXtBw@Z+BE z`_9?Dzk7eH`Trp0U|wK8X3jC!m?SH%p`-4Qi7G+L%lycM>2^e)S0*a}DJS!V3>yZ! zGeiE^jrNf*hdjSm-5Py5a(IIE7G^i<(g$MBDNZFos-F2?23DBfRaev5luMg~`6ina zGGW5JYxH9d^Yv1(0jX&;)@CCg;#b=^K$|TzFA)Neax>>KZ}`}P)J-((+8ADbbK+>i z-rS;12tcZVxdb1>uK=X#YX3yOp*Vh}&Bk;qON0QVIwT|wUr}pn>VDn1j>56oTiKLb z%i0^~vrGs;Dk(voqA*C|Z81bPIP=x5b@65=?E}DVLpsH8LKFt6MG-xs7)UoZI#*mx zr&I3cCmfpQb-lt6kN7Q$!Y~DrtCE=PxOnaP`AhV+^jFZFg&A~hr@$sP0CTbBX z3c0A}G_|Bh z@oNko{4qjZpA$6pZi=Q}zoKL^X{@-0j=I&0In2l7@ddFo(bLm&oNqq^@}t=3@9!tD zV=_eh)`oKi<%mA?TeIwwwLE=3Un8D#YhPa!vAI zTti14eRlKMzkz`PGb9iQ7>{A6nIF=`w-{q_$H`A9rtA9tzrIFW>x&`!!TWP)P000>X1^@s6#OZ}&00004XF*Lt006O$ zeEU(80000WV@Og>004&$004{<009A1004q3004bH008f=0027c000!12prSL00009 za7bBm000ib000ib0l1NC?EnA(8FWQhbW?9;ba!ELWdLwtX>N2bZe?^JG%heMF*h@A zpJM<30%b`=K~zXf&6H1T6G0fpXImQ@3>6y1l8s2Sdni4W9t!c$51_gB1M~~@AiXpY zviS>vTzaulXt5NEf&nRB>PZhl@t~+w@Z{NpyVw}TG-)%w?__qFo!xDdYQYzNY?Fh4QXM7JHj>}PTX{fJKCw;Vh`E-N;j z>V(E$NJa(*{k(FO_K4E;>jRI0(*wi;@w#9hgmrEmuE1E41_g1x0J~toU1^}q-vwa7 zkc$n00eNX)5a&LRi#>QWNCOx>LXKZ2lk`MUdVYNXeW(9~Q2^ZM2ASU<=H|+|T#i0V zrC!1P@P9^ZaDktZy-^|HHij66G5l)<7kI;CI3686dcL&upjxe_E0xN_a=A=_1H8v| z?ECoucM#lc3r&Y^Btk!KY|uud5y-op9eOl5>G5*5SwJ?MO>QkOciLlPE?&`|AiUYzqu=M}9lscofJfeh#eWX$&}KTFj{X4+#98$d SKy_;X0000P000>X1^@s6#OZ}&00004XF*Lt006O% z3;baP00009a7bBm000ia000ia0czHX2><{98FWQhbW?9;ba!ELWdLwtX>N2bZe?^J zG%heMF*h@ApJM<316D~yK~zXf+ndwYv=gwVbxUepI2&o|Q&5L+7)Ui2h4CwKeKJ-vxE7lfHlL;QPcm-iVmh7fs6f>gP17Re!2x0MIWqE2+48>P@|7zc&k<^2_;apa zJ6ztAws^}Ke?&$PMx)WT3RGQLjS#>C$;ADheBn!HI{TdrdA|;<)Baa_$OE(8oThsk z?gub+L6uQ3{y9c zpn4pek}CoucsUFdyL-G`w#zp#Jha!_*}r2UM^p?S?WA=lt{KN$TUt%v1+YtHRb*qt zCLWwdnFdwlc$8E>MDQS&>GF+IF1)dQqu!pu-Tpin;xpZQXhik1p$#Dkya0Bo_?{TL zakQQ%$iadq12sK~122GGF6)R`-5?qzbAEA7s=)97dRb1SeD5gd8c*^fa00j*g6aa3 z1rd!5yj)ye$N@qG531FL(78grxd2uv-o-ipbMGpb%kgqw-$`6RFG2{wWFp!Xs-C+jQ)mzm zIl#V^u=dl#F7)>HPBzqq@gEG(L3GnZBC&~<)<`M0P(c*phH=c$^)sZ8(~EmJ&u+!O z6}8%MzE~_K8~RV`3H^u$4cXf2GkV1YEJpSGmd*dVG&TJMY{h52kR~&@00000NkvXX Hu0mjf8IZqd literal 0 HcmV?d00001 diff --git a/src/main/java/berack96/games/minefield/frame/EndFrame.java b/src/main/java/berack96/games/minefield/frame/EndFrame.java new file mode 100644 index 0000000..bd29743 --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/EndFrame.java @@ -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.
+ *
+ * Essa contiene tre bottoni:
+ * Menu che fa tornare ad un {@link MenuFrame},
+ * Retry che fa riprovare la modalita' di gioco che era nel pannello {@link GameFrame},
+ * 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("
"+msg+"
"); + } +} diff --git a/src/main/java/berack96/games/minefield/frame/GameFrame.java b/src/main/java/berack96/games/minefield/frame/GameFrame.java new file mode 100644 index 0000000..b61f031 --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/GameFrame.java @@ -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.
+ * Essa si serve di un {@link MenuFrame} per la finestra finale {@link EndFrame}
+ * e anche di un {@link Field} gia' creato, in modo da creare una rappresentazione
+ * 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.
+ * 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 + + } +} diff --git a/src/main/java/berack96/games/minefield/frame/MenuFrame.java b/src/main/java/berack96/games/minefield/frame/MenuFrame.java new file mode 100644 index 0000000..2892c8c --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/MenuFrame.java @@ -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.
+ * Essa e' formata in modo da avere 4 zone: in ognuna di esse l'utente deve fare delle scelte.
+ * + * @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}
+ * 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(""+error+""); + } + + /** + * Se inserito un campo, verra' creata una finestra di gioco {@link GameFrame}
+ * 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(); + } +} \ No newline at end of file diff --git a/src/main/java/berack96/games/minefield/frame/strings/StringError.java b/src/main/java/berack96/games/minefield/frame/strings/StringError.java new file mode 100644 index 0000000..65baaf2 --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/strings/StringError.java @@ -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
" + + "per la grandezza del campo"; + + public static final String minesLessThanZero = "Inserisci dei valori positivi
" + + "per le mine"; + + public static final String minesGreaterThanField = "Inserisci un valore minore per le mine
" + + "siccome non possono essere maggiori
" + + "della grandezza del campo"; + + public static final String minesGreaterThanFieldSafe = "Inserisci un valore minore per le mine
" + + "siccome non possono essere maggiori
" + + "della grandezza del campo-8
" + + "(perche' la prima cella non
" + + "puo avere mine intorno)"; + + public static final String valueTooHigh = "Inserisci un valore minore per le grandezze
" + + "siccome entrambe devono avere un valore
" + + "minore di 100"; +} diff --git a/src/main/java/berack96/games/minefield/frame/strings/StringMode.java b/src/main/java/berack96/games/minefield/frame/strings/StringMode.java new file mode 100644 index 0000000..73c108f --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/strings/StringMode.java @@ -0,0 +1,19 @@ +package berack96.games.minefield.frame.strings; + +public class StringMode { + + public static final String easy = "
MODALITA' FACILE:
" + + "Il campo non e' molto grande (8x8)
" + + "e le mine non sono molte (10)
"; + + public static final String medium = "
MODALITA' MEDIA:
" + + "Il campo e' di medie dimensioni (16x16)
" + + "e le mine sono numerose (40)
"; + + public static final String hard = "
MODALITA' DIFFICILE:
" + + "Il campo e' molto grande (16x32)
" + + "e le mine sono molto numerose (80)
"; + + public static final String custom = "
MODALITA' PERSONALIZZATA:
"; + +} diff --git a/src/main/java/berack96/games/minefield/frame/strings/StringSafe.java b/src/main/java/berack96/games/minefield/frame/strings/StringSafe.java new file mode 100644 index 0000000..85be077 --- /dev/null +++ b/src/main/java/berack96/games/minefield/frame/strings/StringSafe.java @@ -0,0 +1,10 @@ +package berack96.games.minefield.frame.strings; + +public final class StringSafe { + + public static final String yes = "
La prima cella che viene scoperta
" + + "non avra' nessuna mina intorno.
"; + + public static final String no = "
La prima cella che viene scoperta
" + + "potra' avere mine intorno, o esserla.
"; +} diff --git a/src/main/java/berack96/games/minefield/listener/CellInFieldListener.java b/src/main/java/berack96/games/minefield/listener/CellInFieldListener.java new file mode 100644 index 0000000..0d31f47 --- /dev/null +++ b/src/main/java/berack96/games/minefield/listener/CellInFieldListener.java @@ -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}.
+ * Questa classe modifica la cella in base all'azione dell'utente tramite i movimenti
+ * 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 + } + +} diff --git a/src/main/java/berack96/games/minefield/listener/EndFrameListener.java b/src/main/java/berack96/games/minefield/listener/EndFrameListener.java new file mode 100644 index 0000000..e527a13 --- /dev/null +++ b/src/main/java/berack96/games/minefield/listener/EndFrameListener.java @@ -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
+ * 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(); + } + +} diff --git a/src/main/java/berack96/games/minefield/listener/MenuFrameListener.java b/src/main/java/berack96/games/minefield/listener/MenuFrameListener.java new file mode 100644 index 0000000..40bb9c9 --- /dev/null +++ b/src/main/java/berack96/games/minefield/listener/MenuFrameListener.java @@ -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
+ * 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); + } + } + +} diff --git a/src/main/java/berack96/games/minefield/object/Cell.java b/src/main/java/berack96/games/minefield/object/Cell.java new file mode 100644 index 0000000..c9d8ee5 --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/Cell.java @@ -0,0 +1,139 @@ +package berack96.games.minefield.object; + +import java.util.Observable; + +/** + * Classe che serve a creare una cella per il campo.
+ * Tramite le funzioni principali della cella si
+ * possono sapere 4 cose:
+ * - il numero di mine vicine {@link #nearMine}
+ * - se la cella e' una mina {@link #isMine()}
+ * - lo stato della cella {@link #getStatus()}
+ * + * @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"
+ * Una volta fatto la cella non potra' esser piu cambiata.
+ * Essa potra' avere i seguenti valori:
+ * - EXPLODED
+ * - UNCOVERED
+ * - GOTRIGHT
+ * - GOTWRONG
+ *
+ * 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.
+ * Vedi {@link CellStatus} per i possibili valori. + * + * @return CellStatus + */ + public CellStatus getStatus() { + return status; + } + + /** + * Setta la cella come una mina solamente se
+ * quest'ultima non e' stata scoperta.
+ * Questa azione e' irreversibile. + */ + public void setMine() { + if(!uncovered) + isMine = true; + } + + /** + * Setta la cella nello stato di {@link CellStatus}.DANGEROUS
+ * Se La funzione {@link #uncover()} e' gia stata chiamata
+ * 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
+ * e la mette come COVERED.
+ * Se la cella non e' in stato DANGEROUS, la funzione
+ * 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.
+ * AKA se la funzione {@link #uncover()} e' gia stata chiamata. + * + * @return true se non e' piu {@link CellStatus#COVERED} + */ + public boolean isUncovered() { + return uncovered; + } +} diff --git a/src/main/java/berack96/games/minefield/object/CellStatus.java b/src/main/java/berack96/games/minefield/object/CellStatus.java new file mode 100644 index 0000000..603948e --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/CellStatus.java @@ -0,0 +1,41 @@ +package berack96.games.minefield.object; + +/** + * Serve a comunicare lo stato della cella.
+ * Essa puo' assumere questi stati in base al
+ * 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 +} diff --git a/src/main/java/berack96/games/minefield/object/Decisor.java b/src/main/java/berack96/games/minefield/object/Decisor.java new file mode 100644 index 0000000..0628f20 --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/Decisor.java @@ -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
+ * {@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(); + } +} diff --git a/src/main/java/berack96/games/minefield/object/Field.java b/src/main/java/berack96/games/minefield/object/Field.java new file mode 100644 index 0000000..a2d2822 --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/Field.java @@ -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.
+ * Essa contiene un tot numero di celle della classe {@link Cell}
+ * + * @author Jack + * + */ +public abstract class Field implements Iterable { + + /** + * 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 false e che
+ * se messo a true, non fara' piu richiamare la funzione
+ * {@link #generateField(int, int)} quando la funzione
+ * {@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.
+ * 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 + * Se la cella e' in uno stato di {@link CellStatus}.DANGEROUS,
+ * essa non verra' scoperta e la funzione terminara'.
+ * 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.
+ * Se la cella e' in uno stato di {@link CellStatus}.DANGEROUS,
+ * essa VERRA' comunque scoperta.
+ * 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
+ * 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
+ * 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.
+ * 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.
+ * 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,
+ * e alla fine del gioco e' risultata essere una mina.
+ * 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.
+ * 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
+ * questa funzione puo' esser considerata un modo per
+ * 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.
+ * La funzione DEVE aggiornare il campo {@link #isGenerated},
+ * in modo che sia generato una sola volta il campo.
+ * Per creare il campo si possono usare le funzioni
+ * {@link #insertMine(int, int)} e {@link #updateNumNearMines(int, int)} gia fornite.
+ * Nel caso non si usasse questa funzione nel costruttore,
+ * essa viene richiamata nella funzione {@link #cellUncover(int, int)}.
+ * Il campo isGenerated evita che venga ripetuta l'operazione piu' volte,
+ * quindi e' necessario che venga aggiornata in questa funzione.
+ * Le coordinate sono fornite per passare, per esempio,
+ * 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
+ * Aaggiorna inoltre quante mine ci sono nel campo
+ * 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.
+ * 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 iterator() { + return new FieldIter(this); + } + + + private class FieldIter implements Iterator { + + 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); + } + } +} diff --git a/src/main/java/berack96/games/minefield/object/FieldNoSafe.java b/src/main/java/berack96/games/minefield/object/FieldNoSafe.java new file mode 100644 index 0000000..ac53077 --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/FieldNoSafe.java @@ -0,0 +1,61 @@ +package berack96.games.minefield.object; + +import berack96.games.minefield.runexception.TooHighValueException; + +/** + * Classe che crea un campo di celle {@link Cell}.
+ * 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() + * Quando l'utente scopre la prima cella, essa NON puo essere una mina,
+ * 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'
+ * 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()=x-1 && randX<=x+1 && randY>=y-1 && randY<=y+1) == false) + this.insertMine(randX, randY); + } + + for(int i=0; i + * [ ] - {@link CellStatus#UNCOVERED} 0 mine vicine
+ * [n] - {@link CellStatus#UNCOVERED} con "n" mine vicine
+ * [D] - {@link CellStatus#DANGEROUS}
+ * [*] - {@link CellStatus#EXPLODED}
+ * [V] - {@link CellStatus#GOTRIGHT}
+ * [X] - {@link CellStatus#GOTWRONG}
+ * [#] - {@link CellStatus#COVERED}
+ * + * @return String + */ + public String toString() + { + return string; + } + + /** + * Ritorna la rappresentazione della cella sottoforma di JLabel:
+ * {@link CellStatus#UNCOVERED} bianco con eventuale numero
+ * {@link CellStatus#DANGEROUS} con icona di una bandiera
+ * {@link CellStatus#EXPLODED} con una icona di una mina
+ * {@link CellStatus#GOTRIGHT} con una icona di una bandierina cerchiata di verde
+ * {@link CellStatus#GOTWRONG} - con una icona di una bandierina crociata di rosso
+ * {@link CellStatus#COVERED} - grigio chiaro
+ * + * @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
+ * 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
+ * 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; + } +} diff --git a/src/main/java/berack96/games/minefield/object/view/FieldView.java b/src/main/java/berack96/games/minefield/object/view/FieldView.java new file mode 100644 index 0000000..bd161a1 --- /dev/null +++ b/src/main/java/berack96/games/minefield/object/view/FieldView.java @@ -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
+ * 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.
+ * Per valori celle vedi {@link CellView#toString()}. + * + * @return String + */ + public String toString() + { + string = toString(field); + return string; + } + + /** + * Restituisce il campo sottoforma di jpanel.
+ * 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
+ * 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 + * 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 seqTemp = new Vector(); + 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; + } + +} diff --git a/src/test/java/berack96/test/games/minefield/TestCell.java b/src/test/java/berack96/test/games/minefield/TestCell.java new file mode 100644 index 0000000..c5e2fe3 --- /dev/null +++ b/src/test/java/berack96/test/games/minefield/TestCell.java @@ -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); + } +} diff --git a/src/test/java/berack96/test/games/minefield/TestFieldNoSafe.java b/src/test/java/berack96/test/games/minefield/TestFieldNoSafe.java new file mode 100644 index 0000000..4a4fc81 --- /dev/null +++ b/src/test/java/berack96/test/games/minefield/TestFieldNoSafe.java @@ -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); + } +} diff --git a/src/test/java/berack96/test/games/minefield/TestFieldSafe.java b/src/test/java/berack96/test/games/minefield/TestFieldSafe.java new file mode 100644 index 0000000..3d54f65 --- /dev/null +++ b/src/test/java/berack96/test/games/minefield/TestFieldSafe.java @@ -0,0 +1,7 @@ +package berack96.test.games.minefield; + + + +public class TestFieldSafe { + +}