Compare commits

..

103 Commits

Author SHA1 Message Date
512fcc069d
dernière correction par ma maman
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-05-22 02:12:50 +02:00
7a5a4a093e
spellcheck
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-21 17:54:47 +02:00
6d53865281 Merge pull request 'Rapport' (#53) from Rapport into master
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #53
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-20 23:36:13 +02:00
58810fff0c corrections
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-20 23:37:22 +02:00
a98c3cd3e1 Last modification by tonitch
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-20 14:17:42 +02:00
939f8566cd latex syntax
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-20 13:11:30 +02:00
03beebaeaf escape on the menu quit the game
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-20 12:45:52 +02:00
c7fe7853b4 Merge pull request 'restructuration des fichiers' (#84) from restructuration into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #84
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-20 12:32:10 +02:00
35c7ecf471 Merge pull request 'Random rotation to generated maps' (#83) from randomPieceRotation into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #83
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-20 12:31:53 +02:00
Mat
229782c772 Corriger qlq faute vu sur relecture
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-19 23:28:27 +02:00
Mat
2d27786e48 Make conclusion and correct some accent
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-19 23:06:18 +02:00
Mat
3bcfdfc084 Add some explain about MapGenerator
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-19 22:12:17 +02:00
Mat
878caf1c99 Add Apport Positifs et négatifs 2023-05-19 20:25:58 +02:00
0bb327abb2
restructuration des fichiers
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-19 16:44:45 +02:00
621be3af64
removing smap from the console
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-19 16:30:02 +02:00
Mat
9671f8ec53 Add Point forts
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-19 15:32:50 +02:00
Mat
2d4462735a Add Point faibles dans le rapport 2023-05-19 15:32:50 +02:00
7467abfd11
Random rotation to generated maps
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-19 14:55:48 +02:00
59fd891fd9
minor corrections
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-19 14:46:17 +02:00
e6853ab3d3
Parser de fichier + Consignes de base
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-19 10:20:11 +02:00
ff5ed0c85f
correction fautes 2023-05-19 10:20:11 +02:00
0330303129
Avancement global
- Section Personelle
- Generateur de niveaux
- Organisation
2023-05-19 10:20:11 +02:00
0354679969
File Parser 2023-05-19 10:20:11 +02:00
714e904d1c
Base de Rapport 2023-05-19 10:20:10 +02:00
d52d1cab77 Clean the pieces position when restarting the game
All checks were successful
continuous-integration/drone/push Build is passing
without that, the old pieces where still in game and this would break
the gameplay
2023-05-19 00:32:44 +02:00
9bc66ad6b1 Solve the position problem
All checks were successful
continuous-integration/drone/push Build is passing
The position was set to (70,76) for all floating pieces because it was
the value received.
nowk, if thes values are given (for the characters F & L as specified in
the specification in the rapport), the piece is set in a floating state
(position = null)
2023-05-19 00:32:26 +02:00
41be423f94 Draw the piece at their places at the start of the level
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-19 00:32:12 +02:00
774c594cb8
avoid too bright colors
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-18 19:46:19 +02:00
fed275ba09 Make a Button to load the previous game done by the player in case if he want to do it one more time(#73)
All checks were successful
continuous-integration/drone/push Build is passing
Make a Button to load the previous game done by the player in case if he want to do it one more time

Co-authored-by: Mat <diletomatteo@gmail.com>
Reviewed-on: #73
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-18 19:31:47 +02:00
8c8dacadd0
Bug Correction, Load Button linked
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-18 19:24:01 +02:00
a726019b18
lock fullscreen
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-18 19:11:43 +02:00
391d94afbe Make a screen when the player finish the level (#64)
All checks were successful
continuous-integration/drone/push Build is passing
Make a screen when the level is finish and also change the button play for select a difficulty

Co-authored-by: Mat <diletomatteo@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #64
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-18 19:03:53 +02:00
7bd43062d0 Make a Button to load the previous game (#68)
All checks were successful
continuous-integration/drone/push Build is passing
A simple button to load a previous game

Co-authored-by: Mat <diletomatteo@gmail.com>
Reviewed-on: #68
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-18 18:36:25 +02:00
4c185f0a81 saveLevel (#69)
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #69
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-18 18:32:16 +02:00
ac6c8611e7 Adding all levels + linking buttons
All checks were successful
continuous-integration/drone/push Build is passing
to create new level just do

`gradle -q --console plain -PmainClass=school_project.Parsers.FileParserFactory run`

Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #56
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-17 23:42:44 +02:00
ff167b4d0f deleting piece position when clicked to avoid fantom pieces
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-17 23:41:55 +02:00
34ea408202 stop piece screen overflow
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-17 22:38:00 +02:00
c9fdb4a7db removing println to stop spamming the console
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-17 20:43:20 +02:00
3d4730cfc0 Merge pull request 'change acceuil to accueil' (#55) from Acceuil_to_Accueil into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #55
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-16 20:25:57 +02:00
518a37ba8c Merge pull request 'correct_lonely_piece' (#54) from correct_lonely_piece into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #54
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-16 20:25:31 +02:00
Mat
aecbf2cb9a add a comment and delete space useless
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-16 10:35:46 +02:00
Mat
178d076883 change acceuil to accueil
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-15 23:58:12 +02:00
Mat
16d2c89e95 Make the code to sub a piece alone without link to others pieces
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-15 19:31:21 +02:00
3dd1b6b059
Less Small Pieces
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-12 11:38:21 +02:00
3e4b4d257e Merge pull request 'This commit will align piece to their in game position' (#48) from pieceDrawing into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #48
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-11 20:09:46 +02:00
d389b22f2d Merge pull request 'Place pieces on the board' (#46) from pieceInteraction into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #46
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-11 20:09:23 +02:00
9fabc8128b Merge pull request 'Set the matrix size of a new piece to its minimum size' (#45) from matrixMinimumSize into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #45
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-11 20:08:39 +02:00
def25d9e38
Check if the baord is completed and return to main menu
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-11 12:24:56 +02:00
e424cdca4e
selected piece get to the front
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-11 12:01:59 +02:00
201eb3ec10
avoid piece to be placed when right clicking 2023-05-11 11:56:00 +02:00
cb54e753d7
align piece when placed
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-11 11:51:53 +02:00
0f1ecc753b
leaving debug printing and reseting piece position if not placed
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-11 11:47:16 +02:00
334e0ad99b
Piece overlap detection
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
there is 3 addition:
- `ArrayList getOccupation()` to get a list of all spot occupied by a piece
- Fixing a bug to rotate right where width and height where inverted
- Check if a piece is overlapping another when placing and refusing the
  placement if so
2023-05-11 11:34:50 +02:00
a35d823ec4
Adding documentation
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-10 23:09:57 +02:00
4f821b44bc
When a piece is placed at a position, check if this space is placable and place it there.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-10 22:59:43 +02:00
9aa09f8fbd
Method to add a piece to a map with it's position 2023-05-10 22:55:42 +02:00
90d6d47cc8
limit piece matrix to their minimum size
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-10 22:49:29 +02:00
8ec5a622d8
isColumn/RowOnlyFalse 2023-05-10 20:22:20 +02:00
e7c7065a8d
Adding MatrixRemoveRow/Column 2023-05-10 20:02:10 +02:00
a472df26ed Merge pull request 'menu' (#43) from menu into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #43
Reviewed-by: Debucquoy Anthony <d.tonitch@gmail.com>
2023-05-09 15:52:13 +02:00
Debucquoy
24730a1362
Merge branch 'menu'
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-09 13:05:53 +02:00
Mat
af3489d078 change the switchRoot method
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2023-05-09 12:56:33 +02:00
7320fea2f9 Merge pull request 'Game UI' (#38) from gameui into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #38
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-09 12:51:18 +02:00
60bf1fa5d0
make white space on detached pieces
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-07 16:13:13 +02:00
7c37c46830
Correct position on draging pieces 2023-05-07 16:13:13 +02:00
6280b39c20
Cleaner code 2023-05-07 16:13:09 +02:00
592780bb73
DownDate to java 11 2023-05-07 16:07:08 +02:00
e3d28b21b4
Positionning on the screen
Signed-off-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2023-05-07 16:07:07 +02:00
7b6291bda9
Keep the Shape Size
Signed-off-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
2023-05-07 16:07:07 +02:00
382af6b541
Piece rotation 2023-05-07 16:07:07 +02:00
15e1745ad1
Adding Gap and texture 2023-05-07 16:07:07 +02:00
4583bbd7e6
set default color of pieces 2023-05-07 16:07:07 +02:00
c68e680768
Show Map and pieces shape in gameui 2023-05-07 16:07:05 +02:00
Mat
a043cb487f Correct all thing say expect the one about switchRoot I didn't understand (Btw add some comment)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-06 21:45:56 +02:00
Mat
1af5db700e Add the picture of background
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-05 12:18:54 +02:00
752c722b0c Merge branch 'master' into menu
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-05 12:11:19 +02:00
Mat
a3ad448fba Finally finish the menu
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-05 11:50:17 +02:00
a7a3e8b36e
DownDate to java 11
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2023-05-04 22:12:13 +02:00
Mat
8110a93910 Make operational and also organize all the buttons
All checks were successful
continuous-integration/drone/push Build is passing
2023-05-04 18:22:23 +02:00
Debucquoy
53972cd1ef
Merge branch 'master' of git.herisson.ovh:undefined_name/School_project
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-04 15:40:31 +02:00
Debucquoy
de146b216d
Down to java11 2023-05-04 15:40:05 +02:00
f1519ba40c levelMaker (#36)
All checks were successful
continuous-integration/drone/push Build is passing
This is a really simple and not efficient level Maker to build levels.

you have to run the main method in FileParserFacotry.java with your idea and respond to all the questions. it's painfully slow but less than doing it by hand on a paper I guess.

I added level11.level as an example for where to put the level when finished.

To access it you have to do: `new File(getClass().getResources("level11.level").getFile())` and put it into `FileParserFactory.loadMapFromFile(File f)`

Co-authored-by: Debucquoy <debucqquoy.anthony@gmail.com>
Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #36
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-03 17:29:10 +02:00
72dcbcbf4f Adding Color to pieces (#31)
All checks were successful
continuous-integration/drone/push Build is passing
Just adding a color field to pieces for drawing later

Carefull when you review, I also moved Vec2 to Utils where I feel it belong.

Solve #29

Co-authored-by: Anthony Debucquoy <debucquoy.anthony@gmail.com>
Reviewed-on: #31
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-03 17:27:10 +02:00
Mat
a43e3b150a Finish initiate all the button in the gridPane For MenuLevel
Some checks failed
continuous-integration/drone/push Build is failing
2023-05-01 20:48:49 +02:00
Mat
7ac860850c Finish initiate all the button in the gridPane For MenuLevel 2023-05-01 20:47:40 +02:00
Mat
a076ca12cb Finish initiate all the button in the gridPane For MenuLevel 2023-05-01 20:45:51 +02:00
Mat
dc5da4956a Affichage des boutons pour les levels ok 2023-05-01 20:07:44 +02:00
c6df656381 MapGenerator (#34)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
This generate maps following a simple structure

First we choose map size depending on the difficulty

we grind the edge with a random pattern so the map is not just a square

we pick a random open piece and try to make a piece out of it between a size of 1 to 3

and we do this in a loop until all open spaces are filled

this is not the best but it's efficient

known problem:

- We can have sometime a lot of small pieces
- We can have weird shape, for instance pieces that are only connected by corner

I think this is technically not a problem in the end. but this could be changed

Co-authored-by: Debucquoy <debucqquoy.anthony@gmail.com>
Reviewed-on: #34
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-01 18:38:52 +02:00
692e22b5b9 Merge pull request 'Adding Array Copy for matrix' (#33) from ArrayDeepCopy into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #33
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-01 17:53:54 +02:00
f21c036b1c Merge pull request 'addition of vectors' (#32) from Vec2Upgrade into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #32
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-05-01 17:53:05 +02:00
Mat
b4b89bcd86 Finishing MenuAcceuil 2023-05-01 16:05:59 +02:00
Mat
644af67a55 Make a package for all the Menu class 2023-05-01 12:31:27 +02:00
Mat
ee0350c251 clear CreateLevelMenu2 and all object useless in Controller
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-30 13:50:44 +02:00
Mat
d455b7f450 Clear CreateLevel1 to make a new class 2023-04-30 13:44:08 +02:00
Mat
02b4ab8a35 Clear the method CreateMenu to make a new class with the same role 2023-04-30 13:07:36 +02:00
Mat
24a7a73f36 forget to update syntaxe with the array 2023-04-28 12:04:22 +02:00
Mat
ce99e1faf9 Make an array for buttons and add a constructor 2023-04-28 12:01:30 +02:00
Mat
075bdd9338 Sub element from Controller to a new class 2023-04-28 11:48:31 +02:00
Mat
25a6782f3c beginning of the final interface
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-28 11:28:10 +02:00
Debucquoy
0baef08205
Adding Array Copy for matrix
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Currently only boolean but we can add more if we need
2023-04-27 11:16:31 +02:00
Debucquoy
f71675dd21
addition of vectors
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Vector to string
2023-04-27 11:09:56 +02:00
9711be3665 Bug journal de bord
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-21 21:00:46 +02:00
8749c23333 File Parser for levels (#18)
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Debucquoy Anthony (tonitch) <debucquoy.anthony@gmail.com>
Reviewed-on: #18
Reviewed-by: Mat_02 <diletomatteo@gmail.com>
2023-04-21 20:00:15 +02:00
84 changed files with 2156 additions and 1078 deletions

View File

@ -5,14 +5,14 @@ name: Check_Requirement
steps:
- name: base_check
image: gradle:jdk11-alpine
image: gradle:jdk11-alpine
commands:
- ./gradlew clean
- ./gradlew build
- ./gradlew test
- name: syntax_check
image: gradle:jdk11-alpine
image: gradle:jdk11-alpine
commands:
- ./gradlew check
@ -44,6 +44,6 @@ depends_on:
- Check_Requirement
---
kind: signature
hmac: 9ca9095fdb69d7b89fda6b4db867877e76666c109607cc7b1e513814ad42bb7e
hmac: 6b154c74ec624ce2d5867386bb7a6ee51cae9153457a8ce15f53e54546ccbc0e
...

1
.gitignore vendored
View File

@ -53,3 +53,4 @@ build
.idea/
.settings/
*.slevel

2
JournalDeBord/rapport/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
rapport.aux
rapport.toc

Binary file not shown.

View File

@ -0,0 +1,274 @@
\documentclass[12pt,a4paper]{article}
\usepackage{amsmath}
\usepackage{listings}
\usepackage{tikz}
\usepackage{csquotes}
\begin{document}
\title{Rapport du projet informatique 2023 \\ "Road to Master"}
\author{Debucquoy Anthony \and Matteo Di Leto}
\date{May 2023}
\maketitle
\newpage
\tableofcontents
\newpage
\section*{Introduction}
Lors de ce deuxième quadrimestre, le projet Informatique proposé par notre université fut partie intégrante de notre emploi du temps.
Régulièrement, nous nous sommes rassemblés pour nous organiser et trouver une direction dans laquelle nous voulions voir notre projet évoluer.
Grâce aux objectifs fixés par nos enseignants, nous sommes - nous le pensons - maintenant plus aptes à nous confronter à ce genre d'objectifs, tant au niveau personnel qu'en tant que groupe.
Il va sans dire que comme pour tout projet, notre chemin a été semé d'embûches. En l'occurrence, nous souhaitons faire part de l'abandon d'un de nos membre. Eddy Jiofak qui souhaite se réorienter.
Nous lui souhaitons une bonne reconversion.
\section*{Objectifs}
Voici l'objectif fixé par nos enseignants. (document de consignes)
\begin{displayquote}
Le but final de ce projet est de réaliser une application graphique en Java permettant de
jouer au jeu "Cats Organized Neatly". Ce jeu est un jeu de type "puzzle" où le joueur doit
placer des pièces de formes différentes pour combler l'aire de jeu. L'application devra permettre
de sauvegarder et charger une partie et de créer des niveaux automatiquement.
\end{displayquote}
\newpage
\section{Organisation}
Lors de nos rassemblement pour le projet, toutes les idées émises se sont retrouvés sur un blog afin de pouvoir y accéder de manière efficace.
Ce blog nous sert également à garder une trace de l'évolution du projet.
\subsection{Choix}
\begin{itemize}
\item{le VCS \verb|git| pour garder une trace de l'avancement du projet. Avec comme remote une instance privée de gitea nous permettant de vérifier les MR/PR plus efficacement.}
\item{Une instance de DroneCI permettant de vérifier que le projet soit toujours compilable et que les tests ne soient pas ratés sans que nous nous en rendions compte.}
\item{Javafx, comme recommandé par nos enseignants.}
\item{Les pièces et niveaux sont stockées sous forme de matrice de booléen}
\item{Un parser de fichiers efficace et donnant des fichier légers.}
\end{itemize}
\subsubsection*{Shapes}
Les pièces ainsi que la carte sont représentés par une matrice de booléen \verb|boolean[][]|.
Nous avons donc une classe \verb|shape|, parent de \verb|Map| et de \verb|Piece| dans lequel nous stockons notre matrice.
Ensuite, \verb|Map| Contient une liste de \verb|Piece|. Ces pièces contiennent une position représentée par la classe \verb|Vec2|.
Cette position est la position du carré supérieur gauche dans la \verb|Map|.
Avec toutes ces informations nous avons le nécessaire pour le moteur du jeu.
Il est facilement possible de manipuler la carte et les pièces. Il nous suffit alors de faire correspondre l'affichage avec
ces différentes classes. Ce qui est entrepris par la classe \verb|GameUI|.
Le tout est géré par la classe \verb|Controller| qui permet de choisir entre l'affichage d'un menu ou d'une partie en cours.
% \subsection{Difficultés}
\section{Points Forts}
\subsection{Parser de fichiers}
Pour la rétention des niveaux, plusieurs possibilités s'offraient à nous. Nous avons alors décidé d'accomplir une série d'objectifs propres à notre projet avec un parser de fichiers dédié.
Nous voulions que ce parser accomplisse les objectifs suivants:
\begin{itemize}
\item{Les données du niveau seront encapsulées dans un header/footer pour laisser la possibilité d'enregistrer plus d'informations (images/musiques) dans un seul fichier dans le futur.}
\item{La taille du fichier devra être aussi petite que possible, tout en gardant les informations nécessaires au bon fonctionnement du jeu.}
\item{Il sera possible d'enregistrer l'état d'une partie en cours.}
\end{itemize}
Ce parser est implémenté par la classe \verb|BinaryParser|.
\subsubsection*{spécification}
\begin{description}
\item[Header/Footer]{ Les données du niveau commencent par les 3 \emph{caractères} 'S', 'M', 'S' (ou \verb|0x534D53|) et se terminent par les 3 \emph{caractères} 'S', 'M', 'E' (ou \verb|0x534D45|)}
\item[Taille de carte]{ Le premier octet des données représente la largeur de la carte, le second sa hauteur.}
\item[Forme de la carte]{ Chaque cellule de la carte est représenté par un 1 ou un 0. Le 1 représente un emplacement libre, un 0 une cellule vide.
La forme de la carte peut alors être répartie sur un nombre indéterminé d'octets.
Nous pouvons déterminer ce nombre grace à
$$\frac{\text{largeur} * \text{hauteur } (+1 \text{ si multiple de } 8)}{8}$$
en division entière.}
\item[Nombre de pièce]{ L' (les) octet(s) qui forme(nt) la carte représente le nombre de pièce}
\item[Pour chaque pièces]{
\
\begin{description}
\item[Taille de la pièce]{La taille est représentée sur un seul octet sous forme de nibble\footnote{https://en.wikipedia.org/wiki/Nibble}. La première partie du nibble est la largeur. La seconde partie du nibble est la hauteur }
\item[Forme de la pièce]{ Chaque cellules de la pièce est représentée par un 1 ou un 0. La manière de le représenter et exactement la même que pour la forme de la carte }
\end{description}
Dans le cas où le fichier sauvegarde l'état de la partie, à la fin, et pour chaque pièce dans le même ordre que l'apparition des pièces:
\begin{description}
\item[Position de la pièce]{2 octets par pièces, 1 octet pour sa position en x et 1 octet pour sa position en y.
Dans le cas où la pièce est flottante (n'est pas placée dans la carte.), les octets contenant les caractères F puis L (0x464C) remplacent les coordonnées}
\end{description}
}
\end{description}
\subsubsection*{Exemple}
Voici le 'hexdump' du niveau 11
\begin{verbatim}
53 4d 53 05 05 e7 ff ff 80 06 33 ff 80 22 f0 22 |SMS.......3.."."|
b0 22 70 22 b0 11 80 53 4d 45 |."p"...SME|
\end{verbatim}
Représente une carte de la forme :
\begin{tikzpicture}
\filldraw[blue] (0,0) -- (0,5) -- (3,5) -- (3,4) -- (5,4) -- (5,0) -- cycle;
\draw[step=1cm,gray] (0, 0) grid (5,5);
\end{tikzpicture}
Avec les pièces :
\begin{tikzpicture}
\fill[red] (1,1) rectangle (4,4);
\fill[red] (5,1) rectangle (7,3);
\fill[red] (8,1) -- (8,3) -- (9,3) -- (9,2) -- (10,2) -- (10,1) -- cycle;
\fill[red] (11,1) -- (11,2) -- (12,2) -- (12,3) -- (13,3) -- (13,1) -- cycle;
\fill[red] (1,-2) -- (1,0) -- (2,0) -- (2,-1) -- (3,-1) -- (3,-2) -- cycle;
\fill[red] (4, -2) rectangle (5, -1);
\draw[step=1cm,gray] (0.5, -2.5) grid (13.5, 4.5);
\end{tikzpicture}
En plus de ce parser, et dans le cas où ce premier ne serait pas capable de stocker certaine carte (par exemple si une pièce mesure plus de 15x15),
nous avons également implémenté un parser très simple en utilisant l'interface \verb|Serialize| de java. Ce parser est implémenté et fonctionnel,
mais n'est pas utilisé dans le projet à l'heure actuelle.
Ces deux parseurs implémentent l'interface \verb|FileParser|.
Finalement, La classe \verb|FileParserFactory| permet une utilisation simple de ces parseurs. Celle-ci contient deux fonctions statiques.
\begin{itemize}
\item{\verb|Map loadMapFromFile(File)|}
permet de retourner la Map d'un fichier chargé.
\item{\verb|void saveFileFromMap(File, Map)|}
permet de sauvegarder une map dans un fichier.
\end{itemize}
Dans le cas d'une sauvegarde ou d'un chargement, le parser est choisi en fonction de l'extension de fichier ('.level', '.slevel', .'serialized', '.sserialized').
L'avantage de ce système est que nous pouvons facilement ajouter d'autres parser de fichiers dans le futur.
\subsection{Générateur de niveaux}
Le générateur de niveaux a été conçu de sorte à proposer 3 difficultés différentes:
\begin{itemize}
\item{Niveau Facile}
\item{Niveau Moyen}
\item{Niveau Difficile}
\end{itemize}
L'algorithme derrière est le même. En voici le principe :
\subsubsection*{Gestion du plateau}
Le joueur choisit une difficulté. En fonction de la difficulté choisie, la grandeur du plateau de jeu sera différente.
Si la difficulté choisie est facile ou moyenne, alors un curseur parcourt les extrémités du niveau.
Ce curseur sélectionne aléatoirement les cellules qui seront gardées ou non.
Grâce à ça, la forme du plateau n'est pas trop carrée.
Nous nous sommes basés sur le même principe pour le niveau de difficulté difficile mais en plus d'une taille encore plus grande,
le curseur parcourt les extrémités avec une profondeur de 2 afin de faire varier la carte plus grande.
Cela introduit le problème des cases isoléss. C'est pourquoi une boucle vérifie chaque cellule et la supprime si celle-ci est isolée.
\subsubsection*{Gestion des pièces}
Peu importe la difficulté du niveau, voici le fonctionnement :
Une taille maximum des pièces a été fixée au préalable à 3x3.
Par la suite, un curseur parcourt des cases de la carte préalablement conçue de manière aléatoire.
Pour chaque case, l'algorithme teste pour chaque case de la pièce, si l'espace est disponible.
Si ça n'est pas le cas, alors la pièce est modifiée afin de faire correspondre la pièce et la carte.
L'avantage de cette méthode est que les niveaux sont tous très différents.
Les désavantages sont que, par malchance, il est possible d'avoir énormément de piece 1x1.
il est aussi plus difficile d'appliquer des textures et dessins - à l'image du jeu de base - sur les pièces.
Malgré tout, avec nos nombreux tests, ce générateur de niveaux nous satisfait vraiment bien et la difficulté des niveaux correspond bien aux attentes.
\subsection{Interface graphique}
L'interface graphique du jeu tient sur 5 classes différentes.
\subsubsection*{Controller}
Classe principale. Elle s'occupe de la gestion des autres classes et de la cohérence entre elles.
Toutes les autres classes (présentes dans le package \verb|Scenes|) sont des sous classe de Parents.
Cela permet de les afficher grâce à la méthode statique \verb|switchRoot|.
C'est aussi le point d'entrée du programme.
\subsubsection*{MenuAccueil}
Classe s'occupant de générer la page d'accueil du jeu.
C'est-à-dire la première page que verra l'utilisateur.
Cette page permet d'accéder aux niveaux du jeu de base, mais également de générer les niveaux aléatoires.
De plus un dernier bouton "Load Game" permet de revenir sur la dernière partie en cours du joueur.
\subsubsection*{MenuLevel}
Classe s'occupant d'afficher les niveaux proposés dans le jeu, et qui,
en fonction du jour choisi, change les boutons et les niveaux disponibles.
\subsubsection*{ScreenLevelFinish}
Classe qui s'affiche à l'écran dès que le joueur a fini le niveau.
Celle-ci propose également de réessayer le niveau ou de retourner au menu principal.
\subsubsection*{GameUI}
Classe s'occupant de l'affichage d'un niveau.
S'occupe dans un premier temps d'afficher le plateau au milieu de l'écran.
Par la suite, les pièces sont dispersées à la gauche de l'écran et sont rendues disponibles à l'utilisateur.
Ces pièces sont déplaçables à l'aide de la souris.
Si elles sont lâchées sur un emplacement disponible du plateau, alors elles vont s'aligner avec ses cellules.
Pour se faire, nous regardons si le centre d'une cellule (la plus en haut à gauche) est présente dans une cellule du plateau.
Ensuite, on vérifie que toutes les cellules de la pièce ont bien la place dans le plateau pour se poser. Si c'est le cas, alors la pièce est posée.
\section{Points Faibles}
Bien que l'interface graphique permet de naviguer de manière fluide dans le jeu, il y a clairement un manque d'animation et de dynamisme
\emph{i.e}: transition de page à une autre, apparition des boutons ainsi qu'un manque de musique.
Toujours concernant l'affichage l'adaptation à la taille de l'écran peut être revue.
De plus suite à la perte de notre membre nous n'avons pas su gérer la partie du projet qui concerne le design/textures des pièces ainsi que l'histoire jeu préparée auparavant.
\section{Apports Positifs et négatifs}
\subsection{Anthony}
Personnellement, ce projet m'a permis de me plonger dans la conception d'un format de fichier personnalisé.
Cest un exercice que je navais pas encore fait jusqua maintenant. Malgré mes efforts pour prévoir un maximum de choses à lavance afin déviter de devoir modifier ma spécification pendant le développement, je me suis vite rendu compte que je navais pas pensé à tout et que je devrais changer des étapes pour pouvoir arriver à mes fins. Je pense que ce parser de fichier est vraiment améliorable mais je suis relativement fier du résultat.
J'ai pu présenter ce parser à Dr Quoitin qui a pu me conseiller sur différentes approches à ce problème.
J'en prends bonne note.
\subsection{Matteo}
Il est clair que je peux tirer plusieurs enseignements grâce à la réalisation de notre projet.
Tout d'abord, j'ai pu en apprendre beaucoup plus concernant la P.O.O en java, mais aussi j'en ai appris
d'avantage sur l'utilisation de la bibliothèque JavaFx.
De plus, durant la réalisation du projet, comme dit précédemment, nous avons utilisé plusieurs outils dont la plus grande découverte pour moi est
Git qui révèle son intérêt pour les travaux de groupes et qui, selon moi, se révélera tout aussi essentiel pour mes futurs projets
scolaires ainsi que professionnels.
\section{conclusion}
En conclusion, nous pouvons séparer notre travail en trois parties différentes:
\begin{enumerate}
\item Le parser de fichier (gestion sauvegarder/charger partie)
\item Logique du jeu (Map,Vec2,Shapes)
\item Liaison à l'UI (Javafx)
\end{enumerate}
Malgré notre travail concentré sur le bon fonctionnement du jeu avec un parser suivant nos objectifs, une utilisation de la P.O.O de manière très efficace
ainsi qu'une approche correcte de l'utilisation du framework Javafx, d'autres améliorations sont toujours possibles!
En effet, l'idée d'ajouter une histoire, des trophées, un Easter egg, des pièces spéciales ou un encore une table de score basée sur le temps,
reste possible afin de rendre notre jeu encore plus complet.
En conclusion, notre jeu a encore plein de possibilité afin d'être encore plus complet et amusant!
\end{document}

View File

@ -6,6 +6,10 @@
- [Deuxième entrevue](./rapports/200223.md)
- [Troisième entrevue](./rapports/230323.md)
# Specification
- [File Parser](./spec/FileParser.md)
# Histoire
- [Plot Story](./histoire/plot_story.md)

View File

@ -0,0 +1,50 @@
<!-- --- -->
<!-- title: File Parser -->
<!-- author: Debucquoy Anthony (tonitch) -->
<!-- date: 5 March 2023 -->
<!-- --- -->
# File Parser Specification
For the Project, I wanted to challenge myself, I decided to do my own file parser with my own specification that would
have the special objective of being really small.
## The File format
The file would use the .level file extension.
The file can contain anything, the used data is enclosed between a header and a footer.
This could be used to add: musics, images and other stuff in the level file itself
Only one Header and One Footer should be present in the file.
The parser will only read the first one it finds so to avoid problem, it is best practise to put the
level data at the top of the file.
- The HEADER will be defined by the succesion of the characters 'S', 'M' then 'S'
- The FOOTER will be defined by the succesion of the characters 'S', 'M', then 'E'
- The bytes in between are the level data
- byte 1: Width of the map
- byte 2: Height of the map
- bytes 3 -> Width * Height (+1 if Width * Height % 8 is not 0)
- byte after Map Data: Pieces amount
- for each pieces
- 1 byte: size of the piece
- 4 first bits : width
- 4 last bits: height
- next bytes -> Width * Height (+1 if Width * Height % 8 is not 0)
### Saved file
For saved file, the extension will be .slevel
The only difference is that at the end of the map data (after the pieces and before the
Footer. there will be the position of each pieces from their top-left corner in the map.
following this pattern for each pieces
- 'F' and 'L' on 2 bytes for floating positions when the piece is not placed
- x and y on 2 bytes for position if the piece is placed
## Known Limitation
1) by putting the piece size on one byte. We limit the maximum piece size to 15 x 15 (1111 | 1111)
I don't think we will ever need a piece larger than 5x5 so this is clearly a feature, not a bug! :-)
We might use the same methods for the pieces positions but there could be a posibility to have
larger map if I use 2 bytes for the positions.

View File

@ -19,7 +19,9 @@ repositories {
dependencies {
// Use JUnit Jupiter for testing.
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.2'
// This dependency is used by the application.
implementation 'com.google.guava:guava:31.1-jre'
@ -27,7 +29,7 @@ dependencies {
application {
// Define the main class for the application.
mainClass = 'school_project.Controller'
mainClass = project.hasProperty("mainClass") ? project.getProperty("mainClass") : 'school_project.Controller'
}
javafx {
@ -39,3 +41,7 @@ tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}
run{
standardInput = System.in
}

View File

@ -1,222 +1,77 @@
package school_project;
package school_project;
import javafx.application.Application;
import javafx.scene.Node;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.Cursor;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import javafx.animation.RotateTransition;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCombination;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Controller extends Application{
double x;
double y;
public void start(Stage primaryStage) throws Exception {
Polygon piece1 = new Polygon();
Polygon piece2 = new Polygon();
Polygon piece3 = new Polygon();
Polygon piece4 = new Polygon();
Polygon piece5 = new Polygon();
Polygon piece6 = new Polygon();
Polygon piece7 = new Polygon();
import school_project.Scenes.GameUI;
import school_project.Scenes.MenuAccueil;
import school_project.Parsers.FileParserFactory;
piece1.getPoints().addAll(new Double [] {
0.0,0.0,
200.0,0.0,
200.0,200.0,
100.0,200.0,
100.0,100.0,
0.0,100.0});
piece2.getPoints().addAll(new Double [] {
100.0,0.0,
200.0,0.0,
200.0,300.0,
100.0,300.0,
});
piece3.getPoints().addAll(new Double [] {
0.0,0.0,
200.0,0.0,
200.0,200.0,
0.0,200.0,
});
piece4.getPoints().addAll(new Double [] {
0.0,0.0,
200.0,0.0,
200.0,300.0,
0.0,300.0,
});
piece5.getPoints().addAll(new Double [] {
0.0,0.0,
100.0,0.0,
100.0,100.0,
0.0,100.0,
});
piece6.getPoints().addAll(new Double [] {
0.0,0.0,
200.0,0.0,
200.0,300.0,
100.0,300.0,
100.0,100.0,
0.0,100.0});
piece7.getPoints().addAll(new Double [] {
100.0,0.0,
200.0,0.0,
200.0,200.0,
100.0,200.0,
});
/*for(int i ; i<tab.lenght ; i++ ) {
for (int j , i<tab.widnth , j++) {
if (tab[0][0]==TRUE;) {
if(tab[
}
}
}*/
Group root = new Group();
root.getChildren().addAll(piece2,piece1,piece3,piece4,piece5,piece6,piece7/*,....,pieceN*/);
Scene scene = new Scene(root,690,650,Color.WHEAT);
root.getChildren().forEach(n -> makeDraggable((Polygon) n));
root.getChildren().forEach(n -> rotation((Polygon) n, scene));
primaryStage.setScene(scene);
primaryStage.setTitle("piece 1");
primaryStage.show();
piece1.setFill(Color.LIMEGREEN);
piece1.setStroke(Color.BLACK);
piece1.setStrokeWidth(3);
piece2.setFill(Color.LIMEGREEN);
piece2.setStroke(Color.BLACK);
piece2.setStrokeWidth(3);
piece3.setFill(Color.LIMEGREEN);
piece3.setStroke(Color.BLACK);
piece3.setStrokeWidth(3);
piece4.setFill(Color.LIMEGREEN);
piece4.setStroke(Color.BLACK);
piece4.setStrokeWidth(3);
piece5.setFill(Color.LIMEGREEN);
piece5.setStroke(Color.BLACK);
piece5.setStrokeWidth(3);
piece6.setFill(Color.LIMEGREEN);
piece6.setStroke(Color.BLACK);
piece6.setStrokeWidth(3);
piece7.setFill(Color.LIMEGREEN);
piece7.setStroke(Color.BLACK);
piece7.setStrokeWidth(3);
}
//double click delayed bug to fix
//ftm just the last piece implemented can be rotated
public static void rotaterght (Node node) {
RotateTransition rotaterght = new RotateTransition();
//setting attributes for the RotateTransition
rotaterght.setByAngle(90);
rotaterght.autoReverseProperty();
rotaterght.setDuration(Duration.millis(1000));
rotaterght.setNode(node);
rotaterght.setAxis(Rotate.Z_AXIS);
rotaterght.play();}
public static void rotatelft (Node node) {
RotateTransition rotatelft = new RotateTransition();
rotatelft.setByAngle(-90);// minus to rotate to the left
rotatelft.autoReverseProperty();
rotatelft.setDuration(Duration.millis(1000));
rotatelft.setNode(node);
rotatelft.setAxis(Rotate.Z_AXIS);
rotatelft.play();}
public void rotation (Polygon node, Scene scene) {
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
public void handle(KeyEvent event) {// 'event' means corresponds to clicking on the clipboard
switch (event.getCode()) {// 'getCode' gets the code of the key pressed on the clipboard
case RIGHT: rotaterght(node); break;
//args to set
case LEFT: rotatelft(node); break;
default: System.out.println("this case hasn't been taken in charge yet");
}
}
});
}
import java.io.File;
import java.io.IOException;
public void makeDraggable(Polygon node) {
node.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
// record a (x,y) distance for the drag and drop operation.
x = node.getLayoutX() - mouseEvent.getSceneX();
y = node.getLayoutY() - mouseEvent.getSceneY();
node.requestFocus();
node.setFocusTraversable(true);
node.focusedProperty();
node.focusVisibleProperty();
/*node.setFocused(true);*/
node.setCursor(Cursor.CLOSED_HAND);
node.setFill(Color.AZURE);
}
});
node.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
node.setCursor(Cursor.HAND);
node.setFill(Color.LIMEGREEN);
}
});
node.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
node.setLayoutX(mouseEvent.getSceneX() + x);
node.setLayoutY(mouseEvent.getSceneY() + y);
}
});
node.setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
node.setCursor(Cursor.HAND);
}
});
}
public static void main(String[] args) {
launch(args);
public class Controller extends Application {
private static Stage stage;
Parent root;
public static Vec2 screen_size;
@Override
public void start(Stage primaryStage) throws IOException {
new File("save.slevel");
stage = primaryStage;
screen_size = new Vec2(
(int) Screen.getPrimary().getBounds().getWidth(),
(int) Screen.getPrimary().getBounds().getHeight()
);
stage.setTitle("ROAD TO MASTER YOU");
// Full Screen mode
root = new MenuAccueil();
switchRoot(root);
stage.show();
}
public static void switchRoot(Parent root){
Scene scene = new Scene(root);
if(root instanceof GameUI){
scene.setOnKeyPressed(event ->{
GameUI game = (GameUI) root;
if(event.getCode() == KeyCode.ESCAPE){
try {
FileParserFactory.saveFileFromMap(new File("save.slevel"), game.getLevel());
switchRoot(new MenuAccueil());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
else if(root instanceof MenuAccueil){
scene.setOnKeyPressed(event ->{
if(event.getCode()==KeyCode.ESCAPE){
stage.close();
}
});
}
stage.setScene(scene);
stage.setFullScreen(true);
stage.setFullScreenExitHint("");
stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
}
public static void main(String[] args) {
launch();
}
}

View File

@ -14,11 +14,72 @@ public class Map extends Shape{
super(matrix);
}
public Map() {
super();
}
public void addPiece(Piece piece){
piece.setLinked_map(this);
pieces.add(piece);
}
public void addPiece(Piece[] pieces) {
for (Piece p : pieces)
this.addPiece(p);
}
/**
* try to place a piece on the map, return true if succeed and false if it failed
* @param piece the piece to place
* @param pos the position to place the piece in matrix position
* @return true if the piece can and is placed and false if it can't and won't not be palced
*/
public boolean placePiece(Piece piece, Vec2 pos){
if(!pieces.contains(piece))
return false;
piece.setPosition(null);
// In the map limits
if ( pos.x + piece.height > height
|| pos.y+piece.width > width
|| pos.x < 0
|| pos.y < 0)
return false;
ArrayList<Vec2> occupation = new ArrayList<>();
for(Piece p: pieces){
if(p.getPosition() == null || p == piece)
continue;
for (Vec2 o : p.getOccupation()) {
occupation.add(o);
}
}
for (int x = pos.x; x < pos.x + piece.height; x++) {
for (int y = pos.y; y < pos.y + piece.width; y++) {
if ((!getShape()[x][y] || occupation.contains(new Vec2(x, y))) && piece.getShape()[x - pos.x][y - pos.y]) {
return false;
}
}
}
piece.setPosition(pos);
return true;
}
/**
* Check if every pieces has a space on the board to know if the game is finished
* @return true if the game is finished, false if not
*/
public boolean gameDone(){
ArrayList<Vec2> posList = getPosList();
for(Piece p: pieces){
posList.removeAll(p.getOccupation());
}
return posList.isEmpty();
}
/**
* Return a matrix with all used space on the map to see if a piece can fit in a space
*
@ -33,6 +94,8 @@ public class Map extends Shape{
}
for (Piece p : pieces) {
if(p.getPosition() == null)
continue;
for(int x = 0; x < p.height; x++){
for(int y = 0; y < p.width; y++){
if (p.getShape()[x][y]){
@ -43,4 +106,31 @@ public class Map extends Shape{
}
return used;
}
public ArrayList<Piece> getPieces() {
return pieces;
}
/**
* return a new Clean Map without any pieces on it for saving purpose
* @return a New Map Object without any pieces or saved data
*/
public Map getCleanedMap() {
try {
Map ret = (Map) this.clone();
ret.getPieces().clear();
return ret;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* set the position of each pieces in the map to null
*/
public void resetPiecesPositions(){
for (Piece p : pieces) {
p.setPosition(null);
}
}
}

View File

@ -0,0 +1,104 @@
package school_project;
import school_project.Utils.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
public class MapGenerator {
private static final Random rand = new Random();
public enum Difficulty {
Easy,
Medium,
Difficult,
}
public static Map generate(Difficulty difficulty){
Vec2 map_size;
int depth = 1; // how much the map shape generator could grind
// define map size depending on the difficulty
switch (difficulty){
case Easy:
map_size = new Vec2(rand.nextInt(2) + 3, rand.nextInt(2) + 3);
break;
case Medium:
map_size = new Vec2(rand.nextInt(3)+5, rand.nextInt(3)+5);
break;
case Difficult:
map_size = new Vec2(rand.nextInt(2)+8, rand.nextInt(2)+8);
depth = 2;
break;
default:
map_size = new Vec2();
break;
}
// Cut edges
boolean[][] map_shape = new boolean[map_size.x][map_size.y];
for (boolean[] b : map_shape) {
Arrays.fill(b, true);
}
for (int i = 0; i < map_shape.length; i++) {
for (int j = 0; j < map_shape[0].length; j++) {
if(i > depth - 1 && i < map_shape.length - depth && j > depth - 1 && j < map_shape[0].length - depth){
j = map_shape[0].length - depth;
}
map_shape[i][j] = rand.nextBoolean();
}
}
//delete lonely piece
for (int i =0;i<map_shape.length;i++){
for (int j = 0; j<map_shape[i].length;j++){
boolean test = false;
if(map_shape[i][j]){
for(int k = Math.max(i - 1, 0); k<= Math.min(i+1,map_shape.length-1); k++){
for (int l = Math.max(j - 1, 0); l<= Math.min(j+1,map_shape[i].length-1); l++){
if (k==i && l == j)
continue;
if (map_shape[k][l])
test = true;
}
}
if (!test)
map_shape[i][j] = false;
}
}
}
Map ret = new Map(map_shape);
boolean[][] piece_layout = Array.MatrixCopyOf(map_shape);
ArrayList<Vec2> EmptySlots = new ArrayList<>();
for (int i = 0; i < piece_layout.length; i++) {
for (int j = 0; j < piece_layout[i].length; j++) {
if(piece_layout[i][j]){
EmptySlots.add(new Vec2(i, j));
}
}
}
while (EmptySlots.size() > 0){
Collections.shuffle(EmptySlots);
Vec2 selected = EmptySlots.get(0);
int size = 3;
boolean[][] shape = new boolean[size][size];
for(int i = 0; i < size; i++){
for (int j = 0; j < size; j++) {
Vec2 checked = new Vec2(i, j).add(selected);
if(EmptySlots.contains(checked)){
EmptySlots.remove(checked);
piece_layout[checked.x][checked.y] = false;
shape[i][j] = true;
}
}
}
Piece piece = new Piece(shape);
piece.RotateRight(rand.nextInt(4));
ret.addPiece(piece);
}
//generate pieces
return ret;
}
}

View File

@ -1,24 +0,0 @@
package school_project;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Menu extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
//set up the page
BorderPane root = new BorderPane();
Scene scene = new Scene(root,300,200);
primaryStage.setScene(scene);
primaryStage.show();
}
}

View File

@ -0,0 +1,221 @@
package school_project.Parsers;
import school_project.Map;
import school_project.Piece;
import school_project.Utils.Bitwise;
import school_project.Vec2;
import java.io.*;
import java.util.Arrays;
public class BinaryParser implements FileParser {
@Override
public Map getLevel(File file, boolean saved_data) throws IOException {
Map ret;
FileInputStream fileStream = new FileInputStream(file);
byte[] level_data = ExtractLevelData(fileStream);
ret = new Map(ExtractMapFromLevelData(level_data));
ret.addPiece(ExtractPiecesFromLevelData(level_data, saved_data));
fileStream.close();
return ret;
}
@Override
public void saveLevel(File file, Map level_data, boolean save_data) throws IOException {
int byteSize = getByteSizeForMap(level_data, save_data);
byte[] data = new byte[byteSize];
int i = 0;
data[i++] = 'S'; data[i++] = 'M'; data[i++] = 'S';
data[i++] = (byte) level_data.getWidth(); data[i++] = (byte) level_data.getHeight();
for(byte b : BuildByteFromMatrix(level_data.getShape())){
data[i++] = b;
}
data[i++] = (byte) level_data.getPieces().size();
for (Piece p : level_data.getPieces()) {
data[i++] = Bitwise.NibbleToByte((byte) p.getWidth(), (byte) p.getHeight());
for(byte b : BuildByteFromMatrix(p.getShape())){
data[i++] = b;
}
}
if (save_data){
for (Piece p : level_data.getPieces()) {
Vec2 _piece_pos = p.getPosition();
if(_piece_pos == null){
data[i++] = 'F';
data[i++] = 'L';
}else{
data[i++] = (byte) _piece_pos.x;
data[i++] = (byte) _piece_pos.y;
}
}
}
data[i++] = 'S'; data[i++] = 'M'; data[i++] = 'E';
FileOutputStream save_file = new FileOutputStream(file);
save_file.write(data);
save_file.flush();
save_file.close();
}
/**
* Extract Level data from file content
* @param fileStream file stream to read extract data from
* @return Level data as an array of byte
* @throws IOException Expected if we can't read the file
*/
static byte[] ExtractLevelData(InputStream fileStream) throws IOException {
byte[] bytes = fileStream.readAllBytes();
int start_position = 0, end_position = 0;
for (int i = 0; i < bytes.length; i++) {
if(bytes[i] == 83 && bytes[i+1] == 77 && bytes[i+2] == 83){ // SMS
start_position = i+3;
break;
}
}
for (int i = start_position; i < bytes.length - 2; i++) {
if(bytes[i] == 83 && bytes[i+1] == 77 && bytes[i+2] == 69){ // SME
end_position = i;
break;
}
}
return Arrays.copyOfRange(bytes, start_position, end_position);
}
/**
* Get Pieces out of the level data
*
* @param levelData full data of the level without header and footer
* @param saved_data Should extract saved data and included it in the pieces
* @return array of Piece from level data
*/
static Piece[] ExtractPiecesFromLevelData(byte[] levelData, boolean saved_data) {
byte map_width = levelData[0], map_height = levelData[1];
byte piece_count = levelData[2 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0)];
Piece[] ret = new Piece[piece_count];
byte[] pieces_data = Arrays.copyOfRange(levelData, 3 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0), levelData.length);
byte[] pieces_positions = saved_data ? Arrays.copyOfRange(levelData, levelData.length - piece_count*2,levelData.length ): null;
int piece_offset = 0;
for (int piece_index = 0; piece_index < piece_count; piece_index++) {
Vec2 _piece_size = Bitwise.ByteToNible(pieces_data[piece_index + piece_offset]);
byte[] _piece_data = Arrays.copyOfRange(pieces_data, piece_index + piece_offset + 1, piece_index + piece_offset + 1 + _piece_size.x * _piece_size.y / 8 + (_piece_size.x * _piece_size.y % 8 != 0 ? 1 : 0));
boolean[][] _piece_matrix = BuildMatrixFromBytes(_piece_size.x, _piece_size.y, _piece_data);
ret[piece_index] = new Piece(_piece_matrix);
if(saved_data){
Vec2 _piece_pos = (pieces_positions[piece_index*2] == 70 && pieces_positions[piece_index*2+1] == 76) ?
null : new Vec2(pieces_positions[piece_index*2], pieces_positions[piece_index*2 + 1]);
ret[piece_index].setPosition(_piece_pos);
}
piece_offset += _piece_size.x * _piece_size.y / 8 + (_piece_size.x * _piece_size.y % 8 != 0 ? 1 : 0);
}
return ret;
}
/**
* Get the Map Matrix out of the level data
* @param level_data full data of the level without header and footer
* @return boolean matrix of the map
*/
static boolean[][] ExtractMapFromLevelData(byte[] level_data){
int map_width = level_data[0], map_height = level_data[1];
byte[] map_data = Arrays.copyOfRange(level_data, 2, 2 + map_width * map_height / 8 + (map_height * map_width % 8 != 0 ? 1 : 0));
return BuildMatrixFromBytes(map_width, map_height, map_data);
}
/**
* take a boolean matrix and build an array of byte following the specs of the parser
* @param shape bolean matrix where true are 1 and false are 0
* @return byte array with each element compiled for file format
*/
static byte[] BuildByteFromMatrix(boolean[][] shape){
int width = shape[0].length , height = shape.length;
boolean[] b_list = new boolean[width * height];
for (int x = 0; x < shape.length; x++) {
for (int y = 0; y < shape[x].length; y++) {
b_list[x * shape[x].length + y] = shape[x][y];
}
}
byte[] ret = new byte[width * height / 8 + (width * height % 8 == 0 ? 0 : 1)];
for (int i = 0; i < ret.length; i++) {
byte current_byte = 0;
boolean[] current_byte_data = Arrays.copyOfRange(b_list, i * 8, i * 8 + 8);
for (boolean curr_data: current_byte_data) {
current_byte = (byte) (current_byte << 1);
current_byte = (byte) (current_byte | (curr_data ? 1 : 0));
}
ret[i] = current_byte;
}
return ret;
}
/**
* Build a boolean Matrix From a byte array
* Each Byte is composed of 8 bit, each bit is 1 or 0
* if the bit is 0 then it's a false for this cell
* else it's true for this cell
* @param matrix_width width of the matrix
* @param matrix_height height of the matrix
* @param matrix_data byte array of the data to export
* @return boolean Matrix of the data decompiled
*/
static boolean[][] BuildMatrixFromBytes(int matrix_width, int matrix_height, byte[] matrix_data){
boolean[][] ret = new boolean[matrix_height][matrix_width];
// Transforming the bit from matrix_data's byte into boolean array for better manipulation
boolean[] b_array = new boolean[matrix_height * matrix_width];
int index = 0;
for(byte b: matrix_data){
for (int i = 0; i < 8; i++) { // because 8 bit in a byte
b_array[index] = Bitwise.IsBitSetAt(b, i);
index++;
if(index >= matrix_height * matrix_width)
break;
}
}
// Transforming b_array to a 2D matrix
for (int x = 0; x < matrix_height; x++) {
for (int y = 0; y < matrix_width; y++) {
ret[x][y] = b_array[y + x * matrix_width];
}
}
return ret;
}
/**
* give the amount of byte needed to store the given Map
* following the binary file format
* @param level the map to check
* @param data should add save data or only level data
* @return integer of the ammount of byte needed
*/
public static int getByteSizeForMap(Map level, boolean data){
int ret = 6; // header + footer
ret += 2; //size of the piece
ret += ((level.getWidth() * level.getHeight()) / 8); // size of the map
ret += level.getHeight() * level.getWidth() % 8 == 0 ? 0 : 1; // Add 1 if the size of map is not a mult of 8
ret += 1; // amount of pieces
for(Piece p: level.getPieces()){
ret += 1; // size of the piece
ret += p.getHeight() * p.getWidth() / 8;
ret += p.getHeight() * p.getWidth() % 8 == 0 ? 0 : 1; // add 1 if the size of the piece is not mult of 8
if(data){
ret += 2; // if the piece is not placed, only one byte else 2
}
}
return ret;
}
}

View File

@ -0,0 +1,33 @@
package school_project.Parsers;
import school_project.Map;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public interface FileParser {
/**
* Parse the file and create a Map with its shape and pieces setup
*
* @param file file to parse
* @param saved_data does the saved data should be added to the map
* @return Map Object parsed with file data
* @see <a href="http://school.debucquoy.me/spec/FileParser.html#file-parser-specification"> Parser Specification</a>
* @throws FileNotFoundException if the file was not found or was not accessible
* @throws IOException if an I/O occurs
*/
Map getLevel(File file, boolean saved_data) throws IOException;
/**
* Save Map to a file without all it's data
* Could be used for generating level file. might not be used in game.
* @param file the file where to save
* @param levelData the map to save
* @param save_data should save the map data (need to be false only in development I think)
* @throws FileNotFoundException The file could not be created
* @throws IOException if an I/O occurs
*/
void saveLevel(File file, Map levelData, boolean save_data) throws IOException;
}

View File

@ -0,0 +1,132 @@
package school_project.Parsers;
import javafx.util.Pair;
import school_project.Map;
import school_project.Piece;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.NotSerializableException;
import java.util.Scanner;
/**
* This is used to find the right parser to parser a save/level file.
* This should be the only right way to save/load a file! you can just use `Map loadMapFromFile(File)` to load a file
* and `void saveFileFromMap(File, Map)` to save a file
*
* <p>
* there is currently 2 file format with 2 variation each (save file or level file)
* - BinaryParser
* - ".level"
* - ".slevel"
* - SerializeParser
* - ".serialized"
* - ".sserialized"
* </p>
*
* <p>
* More file format can be added in the future by adding a new class that implement parser
* and adding it to this file
* </p>
*
* @author tonitch
*/
public class FileParserFactory {
/**
* Load a file and return a map
* If this is a save map, return the map with its save data
* @param file file to get data from
* @return Map generated from the file
* @throws FileNotFoundException if the file was not found or was not accessible
* @throws IOException if an I/O occurs
*/
public static Map loadMapFromFile(File file) throws IOException {
Pair<FileParser, Boolean> parser= getFileParser(file);
return parser.getKey().getLevel(file, parser.getValue());
}
/**
* Save a file in a specific format, this format is defined by the file extension
* This file extention could be: ".level", ".slevel", ".serialized", ".sserialized"
* for save file use the .s variations
* @param file file name to be saved to with the right extension
* @param map map file to save
* @throws NotSerializableException the file extension is not recognised
* @throws FileNotFoundException The file could not be created
* @throws IOException if an I/O occurs
*/
public static void saveFileFromMap(File file, Map map) throws IOException {
Pair<FileParser, Boolean> parser= getFileParser(file);
parser.getKey().saveLevel(file, map, parser.getValue());
}
private static Pair<FileParser, Boolean> getFileParser(File file) throws NotSerializableException {
FileParser fileParser;
boolean save_data;
if (file.toString().toLowerCase().endsWith(".level")){
fileParser = new BinaryParser();
save_data = false;
}else if(file.toString().toLowerCase().endsWith(".slevel")){
fileParser = new BinaryParser();
save_data = true;
}else if(file.toString().toLowerCase().endsWith(".serialized")){
fileParser = new SerializeParser();
save_data = false;
}else if(file.toString().toLowerCase().endsWith(".sserialized")) {
fileParser = new SerializeParser();
save_data = true;
}else {
throw new NotSerializableException("This file format is not supported");
}
return new Pair<FileParser, Boolean>(fileParser, save_data);
}
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
Map level = new Map();
System.out.print("Entrez le nom du fichier:");
File file = new File(in.nextLine());
System.out.print("Entrez la largeur de la map:");
int map_width = in.nextInt();
System.out.print("Entrez la hauteur de la map:");
int map_height = in.nextInt();
boolean[][] map_shape = new boolean[map_height][map_width];
for (int i = 0; i < map_height; i++) {
for (int j = 0; j < map_width; j++) {
System.out.print("mur (" + i + ", " + j + ")? (y/n):");
map_shape[i][j] = in.next(".").charAt(0) != 'y';
}
}
level.setShape(map_shape);
System.out.println(level);
System.out.print("Entrez le nombre de pieces:");
int piece_amount = in.nextInt();
for (int i = 0; i < piece_amount; i++) {
System.out.print("Entrez la largeur de la piece" + (i+1) +": ");
int _piece_width = in.nextInt();
System.out.print("Entrez la hauteur de la piece" + (i+1) +": ");
int _piece_height = in.nextInt();
boolean[][] _piece_shape = new boolean[_piece_height][_piece_width];
for (int k = 0; k < _piece_height; k++) {
for (int j = 0; j < _piece_width; j++) {
System.out.print("mur (" + k + ", " + j + ")? (y/n):");
_piece_shape[k][j] = in.next(".").charAt(0) != 'y';
}
}
level.addPiece(new Piece(_piece_shape));
}
saveFileFromMap(file, level);
}
}

View File

@ -0,0 +1,32 @@
package school_project.Parsers;
import school_project.Map;
import java.io.*;
public class SerializeParser implements FileParser{
@Override
public Map getLevel(File file, boolean saved_data) throws IOException {
// saved_data is ignored in this case because the file is serialized data and it already knows if should have saved_data or not at this point
FileInputStream fileStream = new FileInputStream(file);
ObjectInputStream objectStream = new ObjectInputStream(fileStream);
try {
return (Map) objectStream.readObject();
} catch (ClassNotFoundException e) {
throw new IOException("the serialized file format has not found any object in the file");
}
}
@Override
public void saveLevel(File file, Map levelData, boolean save_data) throws IOException {
FileOutputStream fileStream = new FileOutputStream(file);
ObjectOutputStream objectStream = new ObjectOutputStream(fileStream);
objectStream.writeObject(save_data ? levelData : levelData.getCleanedMap());
objectStream.close();
fileStream.close();
}
}

View File

@ -1,5 +1,11 @@
package school_project;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import java.util.ArrayList;
import java.util.Random;
/**
* Represent a Piece in the game.
* Every Piece should be contained in a Map Object.
@ -10,13 +16,21 @@ public class Piece extends Shape{
private Vec2 Position;
private Map linked_map;
public Piece() {
super();
}
private transient Paint color; // https://www.baeldung.com/java-transient-keyword
public Piece(boolean[][] matrix) {
super(matrix);
Random rand = new Random();
// the %.8 is there to avoid pieces that are too "white" so that we can see them
color = new Color(rand.nextDouble()%.8, rand.nextDouble() %.8, rand.nextDouble()%.8, 1);
}
public void setColor(Paint p){
color = p;
}
public Paint getColor(){
return color;
}
public Vec2 getPosition() {
@ -24,13 +38,23 @@ public class Piece extends Shape{
}
public void setPosition(Vec2 position){
if (linked_map == null) {
return;
}
this.Position = position;
}
public ArrayList<Vec2> getOccupation(){
ArrayList<Vec2> ret = new ArrayList<>();
if(Position == null)
return ret;
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
if(getShape()[x][y]){
ret.add(new Vec2(getPosition().x + x, getPosition().y + y));
}
}
}
return ret;
}
/**
* set the map the piece is into the the map argument
* @param map map where to place the piece
@ -54,6 +78,20 @@ public class Piece extends Shape{
}
times--;
matrix = temp_matrix;
height = matrix.length;
width = matrix[0].length;
}
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Piece){
Piece pieceObj = (Piece) obj;
if (pieceObj.getPosition() != null && this.getPosition() != null){
return pieceObj.getPosition().equals(this.getPosition()) && pieceObj.getShape().equals(getShape());
}
return pieceObj.getShape().equals(getShape());
}
return false;
}
}

View File

@ -0,0 +1,100 @@
package school_project.Scenes;
import javafx.scene.Group;
import javafx.scene.input.MouseButton;
import school_project.Controller;
import school_project.Map;
import school_project.Piece;
import school_project.Scenes.ScreenLevelFinish;
import school_project.Utils.MatrixShape;
import school_project.Vec2;
import java.io.FileNotFoundException;
public class GameUI extends Group{
public final static int SEGMENT_SIZE = 50;
public final static int SPACE_SIZE = 5;
private final Vec2 piece_pos_click = new Vec2();
private Map level;
public GameUI(Map level) throws FileNotFoundException {
super();
this.level = level;
MatrixShape grid = new MatrixShape(level);
//center the grid
grid.setLayoutX((Controller.screen_size.x - grid.boundary_size.x) >> 1);
grid.setLayoutY((Controller.screen_size.y - grid.boundary_size.y) >> 1);
getChildren().add(grid);
Vec2 piece_space = new Vec2(SPACE_SIZE, SPACE_SIZE);
int column = 0;
for (Piece p : level.getPieces()) {
MatrixShape _piece = new MatrixShape(p);
if(piece_space.y + _piece.boundary_size.y >= Controller.screen_size.y){
column++;
piece_space.y = SPACE_SIZE;
piece_space.x = (SEGMENT_SIZE*3 + SPACE_SIZE*4 )* column;
}
_piece.setLayoutX(piece_space.x);
_piece.setLayoutY(piece_space.y);
piece_space.y += _piece.boundary_size.y;
if(p.getPosition() != null){
_piece.setLayoutX(grid.getLayoutX() + p.getPosition().y * (SEGMENT_SIZE+SPACE_SIZE));
_piece.setLayoutY(grid.getLayoutY() + p.getPosition().x * (SEGMENT_SIZE+SPACE_SIZE));
}
// Pieces Events
_piece.setOnMouseClicked(event -> {
if(event.getButton() == MouseButton.SECONDARY){
((Piece) _piece.shape).RotateRight(1);
_piece.update();
}
});
_piece.setOnMousePressed(event -> {
piece_pos_click.x = (int) event.getX();
piece_pos_click.y = (int) event.getY();
});
_piece.setOnMouseDragged(event -> {
_piece.toFront();
_piece.setLayoutX(event.getSceneX() - piece_pos_click.x);
_piece.setLayoutY(event.getSceneY() - piece_pos_click.y);
});
_piece.setOnMouseReleased(event -> {
if(event.getButton() != MouseButton.PRIMARY)
return;
p.setPosition(null);
if(event.getSceneX() > grid.getLayoutX() && event.getSceneX() < grid.getLayoutX() + grid.boundary_size.x
&& event.getSceneY() > grid.getLayoutY() && event.getSceneY() < grid.getLayoutY() + grid.boundary_size.y )
{
// Inverted because screen is x ; y and matrix is x ; y
Vec2 piece_position_in_grid = new Vec2(
(int) (_piece.getLayoutY() + (SEGMENT_SIZE+SPACE_SIZE)/2 - grid.getLayoutY())/(SEGMENT_SIZE+SPACE_SIZE),
(int) (_piece.getLayoutX() + (SEGMENT_SIZE+SPACE_SIZE)/2 - grid.getLayoutX())/(SEGMENT_SIZE+SPACE_SIZE)
);
level.placePiece(p, piece_position_in_grid);
if(p.getPosition() != null){
_piece.setLayoutX(grid.getLayoutX() + p.getPosition().y * (SEGMENT_SIZE+SPACE_SIZE));
_piece.setLayoutY(grid.getLayoutY() + p.getPosition().x * (SEGMENT_SIZE+SPACE_SIZE));
}
if(level.gameDone()){
Controller.switchRoot(new ScreenLevelFinish(level));
}
}
});
getChildren().add(_piece);
}
}
public Map getLevel() {
return level;
}
}

View File

@ -0,0 +1,88 @@
package school_project.Scenes;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import school_project.Controller;
import school_project.MapGenerator;
import school_project.Parsers.FileParserFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MenuAccueil extends StackPane {
public MenuAccueil(){
super();
//create all the objet that I need
ChoiceBox<String> SlctDifficulty = new ChoiceBox<>();
SlctDifficulty.getItems().addAll("Easy", "Medium", "Difficult");
Label RdmLvl = new Label("Random Level : ");
Button LoadLvl = new Button("Load game");
Button SelectLevel= new Button("Select Level");
Label Title = new Label("Welcome to Road to Master");
SlctDifficulty.setOnAction(event -> {
String choosediff = SlctDifficulty.getSelectionModel().getSelectedItem();
switch (choosediff) {
case "Easy":
try {
Controller.switchRoot(new GameUI(MapGenerator.generate(MapGenerator.Difficulty.Easy)));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
break;
case "Medium":
try {
Controller.switchRoot(new GameUI(MapGenerator.generate(MapGenerator.Difficulty.Medium)));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
break;
case "Difficult":
try {
Controller.switchRoot(new GameUI(MapGenerator.generate(MapGenerator.Difficulty.Difficult)));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
break;
}
});
//set up all the Button where I need
getChildren().addAll(Title,SlctDifficulty,SelectLevel,RdmLvl,LoadLvl);
RdmLvl.setFont(Font.font(25));
RdmLvl.setTextFill(Color.GOLD);
Title.setFont(Font.font(40));
Title.setTextFill(Color.RED);
setAlignment(Title, Pos.TOP_CENTER);
setAlignment(LoadLvl,Pos.BOTTOM_CENTER);
setAlignment(SlctDifficulty,Pos.CENTER_LEFT);
setAlignment(SelectLevel,Pos.CENTER_RIGHT);
setAlignment(RdmLvl, Pos.CENTER_LEFT);
setMargin(RdmLvl,new Insets(0,0,0,100));
setMargin(SlctDifficulty,new Insets(0,0,0,300));
setMargin(SelectLevel,new Insets(0,300,0,0));
setMargin(Title,new Insets(200,0,0,0));
setMargin(LoadLvl,new Insets(0,0,200,0));
SelectLevel.setOnAction(event -> Controller.switchRoot(new MenuLevel(1)));
LoadLvl.setOnAction(event -> {
try {
Controller.switchRoot(new GameUI(FileParserFactory.loadMapFromFile(new File("save.slevel"))));
} catch (IOException e) {
throw new RuntimeException(e);
}
});
getStyleClass().add("BorderPane");
getStylesheets().add(String.valueOf(getClass().getResource("StyleMenuAcceuil.css")));
}
}

View File

@ -0,0 +1,121 @@
package school_project.Scenes;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import school_project.Controller;
import school_project.Parsers.FileParserFactory;
import java.io.File;
import java.io.IOException;
public class MenuLevel extends GridPane {
private int StartLevel;
public MenuLevel(int choose_day) {
//create all Object that I need
RowConstraints[] Rows = new RowConstraints[5];
ColumnConstraints[] Columns = new ColumnConstraints[3];
Button[] Days = new Button[3];
Button BckMenu = new Button("Back to menu");
BckMenu.setOnAction(event -> Controller.switchRoot(new MenuAccueil()));
setHalignment(BckMenu,HPos.CENTER);
add(BckMenu,2,4);
for (int i = 0; i < Days.length; i++){
Days[i] = new Button("Day"+(i+1));
}
//it's here that I know which day I can show on the screen
if (choose_day == 1) {
StartLevel = 1;
add(Days[1],0,0);
add(Days[2],2,0);
setHalignment(Days[1], HPos.CENTER);
setHalignment(Days[2], HPos.CENTER);
}
else if (choose_day == 2) {
StartLevel = 11;
add(Days[0], 0, 0);
add(Days[2], 2, 0);
setHalignment(Days[0], HPos.CENTER);
setHalignment(Days[2], HPos.CENTER);
}
else if (choose_day == 3) {
StartLevel = 21;
add(Days[0], 0, 0);
add(Days[1], 2, 0);
setHalignment(Days[0], HPos.CENTER);
setHalignment(Days[1], HPos.CENTER);
}
Days[0].setOnAction(event -> Controller.switchRoot(new MenuLevel(1)));
Days[1].setOnAction(event -> Controller.switchRoot(new MenuLevel(2)));
Days[2].setOnAction(event -> Controller.switchRoot(new MenuLevel(3)));
//It's here that I put all buttons where I need (base on column not row)
for (int i = 0; i < 3; i++) {
for (int j = 1; j < 5; j++) {
Button levelButton = new Button("level "+(StartLevel));
levelButton.setOnAction(event -> {
try {
String levelName = ((Button)event.getSource()).getText().replace(" ", "") + ".level";
GameUI level = new GameUI(FileParserFactory.loadMapFromFile(new File(Controller.class.getResource("levels/" + levelName).getFile())));
Controller.switchRoot(level);
} catch (IOException e) {
System.out.println("Le niveau " + StartLevel + "n'existe pas.");
}
});
if(i==0){
StartLevel+=3;
add(levelButton,i,j);
setHalignment(levelButton,HPos.CENTER);
if(j==4){
StartLevel-=11;
}
}
else if(i==1&&j!=4) {
StartLevel += 3;
add(levelButton, i, j);
setHalignment(levelButton,HPos.CENTER);
if (j == 3) {
StartLevel -=8;
}
}
else if(i==2&&j!=4){
StartLevel+=3;
add(levelButton,i,j);
setHalignment(levelButton,HPos.CENTER);
}
}
}
for(int i=0;i<=2;i++){
Columns[i] = new ColumnConstraints();
Columns[i].setPercentWidth(33);
getColumnConstraints().addAll(Columns[i]);
}
for (int i= 0;i<=4;i++){
Rows[i] = new RowConstraints();
Rows[i].setPercentHeight(20);
getRowConstraints().addAll(Rows[i]);
}
setHgap(20);
setVgap(20);
setPadding(new Insets(20,10,10,20));
getStyleClass().add("GridPane");
getStylesheets().add(String.valueOf(getClass().getResource("StyleMenuAcceuil.css")));
}
}

View File

@ -0,0 +1,51 @@
package school_project.Scenes;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Font;
import school_project.Controller;
import school_project.Map;
import java.io.FileNotFoundException;
public class ScreenLevelFinish extends StackPane {
public ScreenLevelFinish(Map lastlevel){
super();
Button retry = new Button("Retry Level");
Label CongraMess = new Label(" LEVEL DONE GREAT JOB ");
CongraMess.setFont(Font.font(40));
Button BckMenu = new Button("Back to Menu");
BckMenu.setFont(Font.font(25));
Button ChooseLvl = new Button("Choose level");
ChooseLvl.setFont(Font.font(25));
BckMenu.setOnAction(event -> Controller.switchRoot(new MenuAccueil()));
ChooseLvl.setOnAction(event -> Controller.switchRoot(new MenuLevel(1)));
retry.setOnAction(event -> {
try {
lastlevel.resetPiecesPositions();
Controller.switchRoot(new GameUI(lastlevel));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
});
getChildren().addAll(BckMenu,ChooseLvl,CongraMess,retry);
setAlignment(retry,Pos.BOTTOM_CENTER);
setAlignment(BckMenu, Pos.CENTER_RIGHT);
setAlignment(ChooseLvl, Pos.CENTER_LEFT);
setAlignment(CongraMess, Pos.TOP_CENTER);
setMargin(BckMenu, new Insets(0,300,0,0 ));
setMargin(ChooseLvl,new Insets(0,0,0,300));
setMargin(CongraMess,new Insets(300,0,0,0));
setMargin(retry,new Insets(0,0,300,0));
getStyleClass().add("StackPane");
getStylesheets().add(String.valueOf(getClass().getResource("StyleMenuAcceuil.css")));
}
}

View File

@ -1,12 +1,17 @@
package school_project;
import school_project.Utils.Array;
import java.io.Serializable;
import java.util.ArrayList;
/**
* Base class for everything that is a shape kind, like map and pieces
* it contain a matrix of boolean where the shape is defined by the true's
*/
public class Shape {
public class Shape implements Serializable, Cloneable{
protected boolean[][] matrix;
protected int height, width;
@ -19,14 +24,52 @@ public class Shape {
}
public void setShape(boolean[][] matrix) throws IllegalArgumentException{
height = matrix.length;
width = matrix[0].length;
for (boolean[] row: matrix){
if(row.length != width){
if(row.length != matrix[0].length){
throw new IllegalArgumentException("The argument should be a square matrix");
}
}
for (int i = 0; i < matrix.length; i++) {
if(!Array.isRowOnlyFalse(matrix, i)) {
for (int j = 0; j < i; j++) {
matrix = Array.MatrixRemoveRow(matrix, 0);
}
break;
}
}
for (int i = matrix.length-1; i >= 0; i--) {
if(!Array.isRowOnlyFalse(matrix, i)) {
for (int j = matrix.length-1; j > i; j--) {
matrix = Array.MatrixRemoveRow(matrix, j);
}
break;
}
}
for (int i = 0; i < matrix[0].length; i++) {
if(!Array.isColumnOnlyFalse(matrix, i)) {
for (int j = 0; j < i; j++) {
matrix = Array.MatrixRemoveColumn(matrix, 0);
}
break;
}
}
for (int i = matrix[0].length-1; i >= 0; i--){
if(!Array.isColumnOnlyFalse(matrix, i)) {
for (int j = matrix[0].length-1; j > i; j--) {
matrix = Array.MatrixRemoveColumn(matrix, j);
}
break;
}
}
height = matrix.length;
width = matrix[0].length;
this.matrix = matrix;
}
@ -41,4 +84,33 @@ public class Shape {
public boolean[][] getShape() {
return matrix;
}
}
/**
* Get the list of all the open possition of the map
* @return ArrayList of vec2 of all the positions
*/
public ArrayList<Vec2> getPosList(){
ArrayList<Vec2> ret = new ArrayList<>();
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
if(matrix[x][y]){
ret.add(new Vec2(x, y));
}
}
}
return ret;
}
@Override
public String toString() {
String ret = "";
for (boolean[] row : matrix) {
for (boolean el : row) {
if(el) ret = ret.concat("");
else ret = ret.concat("");
}
ret = ret.concat("\n");
}
return ret;
}
}

View File

@ -0,0 +1,61 @@
package school_project.Utils;
import java.util.Arrays;
public class Array{
public static boolean[][] MatrixCopyOf(boolean[][] o){
boolean[][] ret = new boolean[o.length][];
for (int i = 0; i < o.length; i++){
ret[i] = Arrays.copyOf(o[i], o[i].length);
}
return ret;
}
public static boolean[][] MatrixRemoveRow(boolean[][] o, int row){
boolean[][] newMatrix = new boolean[o.length - 1][o[0].length];
int newRow = 0;
for (int i = 0; i < o.length; i++) {
if(i == row)
i++;
if(i >= o.length)
continue;
newMatrix[newRow] = o[i];
newRow++;
}
return newMatrix;
}
public static boolean[][] MatrixRemoveColumn(boolean[][] o, int col){
boolean[][] newMatrix = new boolean[o.length][o[0].length - 1];
for (int i = 0; i < o.length; i++) {
int newCol = 0;
for(int j = 0; j < o[0].length; j++){
if(j == col)
j++;
if(j >= o[0].length)
continue;
newMatrix[i][newCol] = o[i][j];
newCol++;
}
}
return newMatrix;
}
public static boolean isRowOnlyFalse(boolean[][] o, int row){
boolean mark = true;
for (int i = 0; i < o[row].length; i++) {
if(o[row][i])
mark = false;
}
return mark;
}
public static boolean isColumnOnlyFalse(boolean[][] o, int column){
boolean mark = true;
for (int i = 0; i < o.length; i++) {
if(o[i][column])
mark = false;
}
return mark;
}
}

View File

@ -0,0 +1,43 @@
package school_project.Utils;
import school_project.Vec2;
public class Bitwise {
/**
* Check if the bit at pos is 1 or 0
* @param b byte to test
* @param pos position in b to check
* @return true if the bit at pos is 1 or false if it is 0
*/
public static boolean IsBitSetAt(byte b, int pos){
pos = 7 - pos;
return (b & (1 << pos))!= 0;
}
/**
* Transform a byte (8 bit) to two Nible (4 bit) with a split in the middle
* Exemple:
* in = 01000101 (=69)
* out = { 00000100, 00000101 } (={4, 5})
*
* @param in the byte to split
* @return an arrya of 2 byte ret[0] = left part; ret[1] = right part
*/
public static Vec2 ByteToNible(byte in){
Vec2 ret = new Vec2();
ret.x = (byte) (in >> 4);
ret.y = (byte) (in & 15); // apply the mask '00001111'
return ret;
}
/**
* Transform 2 byte into 1 with a left part ( 4 bits ) and a right part ( 4 bits)
* @param left first 4 bits
* @param right last 4 bits
* @return concatenated byte
*/
public static byte NibbleToByte(byte left, byte right){
return (byte) ((left << 4) | right);
}
}

View File

@ -0,0 +1,65 @@
package school_project.Utils;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import school_project.*;
import school_project.Scenes.GameUI;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class MatrixShape extends GridPane {
public Shape shape;
public Vec2 boundary_size = new Vec2();
private Paint color;
public MatrixShape(Shape shape) {
super();
this.shape = shape;
if(shape instanceof Piece){
Piece p = (Piece) shape;
color = p.getColor();
}
update();
setHgap(GameUI.SPACE_SIZE);
setVgap(GameUI.SPACE_SIZE);
}
public void update(){
getChildren().clear();
boolean[][] shape_matrix = shape.getShape();
for (int i = 0; i < shape_matrix.length; i++) {
for (int j = 0; j < shape_matrix[i].length; j++) {
Node _cell;
if(shape_matrix[i][j]){
if(shape instanceof Piece){
Piece p = (Piece) shape;
_cell = new Rectangle(GameUI.SEGMENT_SIZE, GameUI.SEGMENT_SIZE);
((Rectangle) _cell).setFill(color);
}else{
try {
_cell = new ImageView(new Image(new FileInputStream(Controller.class.getResource("tile.png").getFile())));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
else{
_cell = new Pane();
((Pane) _cell).setPrefSize(GameUI.SEGMENT_SIZE, GameUI.SEGMENT_SIZE);
}
add(_cell, j, i);
}
}
boundary_size = new Vec2((GameUI.SEGMENT_SIZE + GameUI.SPACE_SIZE) * shape.getWidth(), (GameUI.SEGMENT_SIZE + GameUI.SPACE_SIZE) * shape.getHeight());
}
public void setColor(Paint p) {
color = p;
}
}

View File

@ -1,10 +1,12 @@
package school_project;
import java.io.Serializable;
/**
* This is used to represent a position/vector/... any ensemble of 2 elements that have to work together in
* a plan. This way we can use some basic operations over them.
*/
public class Vec2 {
public class Vec2 implements Serializable {
public int x, y;
public Vec2() {
@ -16,4 +18,22 @@ public class Vec2 {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Vec2) {
Vec2 vec = (Vec2) obj;
return this.x == vec.x && this.y == vec.y;
}
return false;
}
public Vec2 add(Vec2 o){
return new Vec2(x + o.x, y + o.y);
}
@Override
public String toString() {
return "("+x+","+y+")";
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

View File

@ -0,0 +1,11 @@
.BorderPane{
-fx-background-image: url("BackGround-menu.jpg");
-fx-background-position:center;
}
.GridPane{
-fx-background-image: url("Background-select-level.jpg");
-fx-background-position:right;
}
.StackPane{
-fx-background-image: url("BackGround-LvlFinish.jpg");
}

View File

@ -0,0 +1 @@
SMSààSME

View File

@ -0,0 +1 @@
SMS<04><>"<22>"<22>"p1<70>SME

View File

@ -0,0 +1 @@
SMSη<><CEB7>3<>€"π"°"p"°€SME

View File

@ -0,0 +1 @@
SMSÿÿÿ€"°1àà2ü"p3í€SME

View File

@ -0,0 +1 @@
SMS?ÿÿýðà"°3í€à"ð2ü3í€SME

View File

@ -0,0 +1 @@
SMSfÿÿŸ< 1à"°"p€&ÿð"ð"ð"°àSME

View File

@ -0,0 +1 @@
SMSÿÿð"°1à€"p#üÀ!ÀSME

View File

@ -0,0 +1 @@
SMS˙˙˙€ŕ€"p3í€3o€SME

View File

@ -0,0 +1 @@
SMSÿÿÿÿð3ÿ€3í€1à1à#ü#üSME

View File

@ -0,0 +1 @@
SMSó˙˙óŕŕ3ü€3o€4đ"°SME

View File

@ -0,0 +1 @@
SMSà1àSME

View File

@ -0,0 +1 @@
SMSÿÿÿ€À3í€"ð2ø3ü€SME

View File

@ -0,0 +1 @@
SMSÿÿÿ€"pàÀ"°#ü#è#èSME

View File

@ -0,0 +1 @@
SMSÿÿÿ€à"Ð#è#¼BSME

View File

@ -0,0 +1 @@
SMSv˙˙€€#ě#ĽBSME

View File

@ -0,0 +1 @@
SMSÿÿÿÿð#¼#|!À#\#ü2ô2äBSME

View File

@ -0,0 +1 @@
SMSÿÿÿÿð#ø#´!À!À#¼4ð3o€SME

View File

@ -0,0 +1 @@
SMS<07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<>B#|3?<3F>3<EFBFBD><33>#<23>&<26><>SME

View File

@ -0,0 +1 @@
SMSy<><79>y<EFBFBD>B<>!<21>B<EFBFBD>$<24>#<23>#<23>SME

View File

@ -0,0 +1 @@
SMS<03><>#<23><13>SME

View File

@ -0,0 +1 @@
SMS<07><><EFBFBD>}<7D>߀ $<24>3ۀ2<DB80><11><11>"<22>2x"p2<70>"<22>2<EFBFBD>SME

View File

@ -0,0 +1 @@
SMS<04><>#<23>#<23><11>1<EFBFBD>SME

View File

@ -0,0 +1 @@
SMS÷p€1à#ü#üSME

View File

@ -0,0 +1 @@
SMSÿ3ÿ€à1àSME

View File

@ -0,0 +1 @@
SMS3ÿà"°SME

View File

@ -0,0 +1 @@
SMSÿÿÿ€2ü"°"°"p1à€1à"pSME

View File

@ -0,0 +1 @@
SMSÿÿ߀1à1à3ÿ€#ü"°SME

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,26 @@
package school_project;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class MapGeneratorTest {
@Test
void generate() {
Map[] maps = new Map[] {
MapGenerator.generate(MapGenerator.Difficulty.Easy),
MapGenerator.generate(MapGenerator.Difficulty.Medium),
MapGenerator.generate(MapGenerator.Difficulty.Difficult),
};
for(Map m: maps){
System.out.println("==========");
System.out.println(m);
System.out.println("++++++++++++++++++++");
for (Piece p: m.getPieces()){
System.out.println(p);
}
}
}
}

View File

@ -0,0 +1,177 @@
package school_project.Parsers;
import org.junit.jupiter.api.Test;
import school_project.Map;
import school_project.Piece;
import school_project.Vec2;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
class BinaryParserTest {
static byte[] file_data = {
'S', 'M', 'S',
6, 5, (byte) 0x31, (byte) 0xEC, (byte) 0xF3, (byte) 0xFC,
4,
(byte) 0x22, (byte) 0x70,
(byte) 0x33, (byte) 0x99, (byte) 0x80,
(byte) 0x32, (byte) 0x7C,
(byte) 0x33, (byte) 0xDB, (byte) 0x80,
'S', 'M', 'E'
};
@Test
void getByteSizeForMap() {
boolean[][] map_shape = {
{ true, true, true },
{ true, false, true },
{ true, true, true },
};
boolean[][] piece1_shape = {
{ true, true },
{ true, false },
{ true, true },
};
boolean[][] piece2_shape = {
{ true },
{ true },
{ true },
};
Map map = new Map(map_shape);
Piece piece1 = new Piece(piece1_shape);
Piece piece2 = new Piece(piece2_shape);
map.addPiece(new Piece[]{piece1, piece2});
piece2.setPosition(new Vec2(0, 2));
assertEquals(15, BinaryParser.getByteSizeForMap(map, false));
assertEquals(19, BinaryParser.getByteSizeForMap(map, true));
}
@Test
void BuildByteFromMatrix(){
byte[] map_data = Arrays.copyOfRange(file_data, 5, 9);
boolean[][] map_shape = {
{false, false, true, true, false, false},
{false, true, true, true, true, false},
{true, true, false, false, true, true},
{true, true, false, false, true, true},
{true, true, true, true, true, true},
};
assertArrayEquals(map_data, BinaryParser.BuildByteFromMatrix(map_shape));
}
@Test
void BuildMatrixFromByte_map(){
byte[] map_data = Arrays.copyOfRange(file_data, 5, 9);
boolean[][] map_shape = {
{false, false, true, true, false, false},
{false, true, true, true, true, false},
{true, true, false, false, true, true},
{true, true, false, false, true, true},
{true, true, true, true, true, true},
};
assertArrayEquals(map_shape, BinaryParser.BuildMatrixFromBytes(6, 5, map_data));
}
@Test
void BuildMatrixFromByte_piece1(){
byte[] piece1_data = Arrays.copyOfRange(file_data, 11, 12);
boolean[][] piece1_shape = {
{false, true},
{true, true},
};
assertArrayEquals(piece1_shape, BinaryParser.BuildMatrixFromBytes(2, 2, piece1_data));
}
@Test
void BuildMatrixFromByte_piece2(){
byte[] piece2_data = Arrays.copyOfRange(file_data, 13, 15);
boolean[][] piece2_shape = {
{true, false, false},
{true, true, false},
{false, true, true},
};
assertArrayEquals(piece2_shape, BinaryParser.BuildMatrixFromBytes(3, 3, piece2_data));
}
@Test
void BuildMatrixFromByte_piece3(){
byte[] piece3_data = Arrays.copyOfRange(file_data, 16, 17);
boolean[][] piece3_shape = {
{false, true, true},
{true, true, true},
};
assertArrayEquals(piece3_shape, BinaryParser.BuildMatrixFromBytes(3, 2, piece3_data));
}
@Test
void BuildMatrixFromByte_piece4(){
byte[] piece4_data = Arrays.copyOfRange(file_data, 18, 20);
boolean[][] piece4_shape = {
{true, true, false},
{true, true, false},
{true, true, true},
};
assertArrayEquals(piece4_shape, BinaryParser.BuildMatrixFromBytes(3, 3, piece4_data));
}
@Test
void ExtractLevelData() throws IOException {
boolean[][] expected_map_shape = {
{false, false, true, true, false, false},
{false, true, true, true, true, false},
{true, true, false, false, true, true},
{true, true, false, false, true, true},
{true, true, true, true, true, true},
};
byte[] level_data = BinaryParser.ExtractLevelData(new ByteArrayInputStream(file_data));
boolean[][] map = BinaryParser.ExtractMapFromLevelData(level_data);
assertArrayEquals(expected_map_shape, map);
}
@Test
void ExtractPiecesFronLevelDataTest() throws IOException {
boolean[][] piece1_shape = {
{false, true},
{true, true},
};
boolean[][] piece2_shape = {
{true, false, false},
{true, true, false},
{false, true, true},
};
boolean[][] piece3_shape = {
{false, true, true},
{true, true, true},
};
boolean[][] piece4_shape = {
{true, true, false},
{true, true, false},
{true, true, true},
};
boolean[][][] pieces_shapes = {
piece1_shape,
piece2_shape,
piece3_shape,
piece4_shape
};
byte[] level_data = BinaryParser.ExtractLevelData(new ByteArrayInputStream(file_data));
Piece[] pieces = BinaryParser.ExtractPiecesFromLevelData(level_data, false);
for (int i = 0; i < pieces_shapes.length; i++) {
assertArrayEquals(pieces_shapes[i], pieces[i].getShape());
}
}
}

View File

@ -0,0 +1,103 @@
package school_project.Parsers;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import school_project.Map;
import school_project.Piece;
import school_project.Vec2;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static org.junit.jupiter.api.Assertions.*;
class FileParserFactoryTest {
static Map generateMapTest(){
boolean[][] map_shape = {
{false, false, true, true, false, false},
{false, true, true, true, true, false},
{true, true, false, false, true, true},
{true, true, false, false, true, true},
{true, true, true, true, true, true},
};
boolean[][] piece1_shape = {
{false, true},
{true, true},
};
boolean[][] piece2_shape = {
{true, false, false},
{true, true, false},
{false, true, true},
};
boolean[][] piece3_shape = {
{false, true, true},
{true, true, true},
};
boolean[][] piece4_shape = {
{true, true, false},
{true, true, false},
{true, true, true},
};
Piece[] pieces = { new Piece(piece1_shape), new Piece(piece2_shape), new Piece(piece3_shape), new Piece(piece4_shape) };
Map map = new Map(map_shape);
map.addPiece(pieces);
pieces[0].setPosition(new Vec2(1, 0));
pieces[1].setPosition(new Vec2(3, 0));
pieces[2].setPosition(new Vec2(3, 3));
pieces[3].setPosition(new Vec2(0, 2));
return map;
}
@Test
void saveLoadFileFromMap_Binary(@TempDir Path tmpFolder) throws IOException {
Map map = generateMapTest();
FileParserFactory.saveFileFromMap(tmpFolder.resolve("TestBinaryLevel.level").toFile(), map);
Map testMap = FileParserFactory.loadMapFromFile(tmpFolder.resolve("TestBinaryLevel.level").toFile());
assertArrayEquals(map.getCleanedMap().getShape(), testMap.getShape());
for (int i = 0; i < map.getPieces().size(); i++) {
assertArrayEquals(map.getPieces().get(i).getShape(), testMap.getPieces().get(i).getShape());
}
}
@Test
void saveLoadFileFromMap_save_Binary(@TempDir Path tmpFolder) throws IOException {
Map map = generateMapTest();
FileParserFactory.saveFileFromMap(tmpFolder.resolve("TestBinarySave.slevel").toFile(), map);
Map testMap = FileParserFactory.loadMapFromFile(tmpFolder.resolve("TestBinarySave.slevel").toFile());
assertArrayEquals(map.getShape(), testMap.getShape());
for (int i = 0; i < map.getPieces().size(); i++) {
assertArrayEquals(map.getPieces().get(i).getShape(), testMap.getPieces().get(i).getShape());
assertEquals(map.getPieces().get(i).getPosition(), testMap.getPieces().get(i).getPosition());
}
}
@Test
void saveLoadFileFromMap_Serialized(@TempDir Path tmpFolder) throws IOException {
Map map = generateMapTest();
FileParserFactory.saveFileFromMap( tmpFolder.resolve("TestSerializedLevel.serialized").toFile(), map);
Map testMap = FileParserFactory.loadMapFromFile( tmpFolder.resolve("TestSerializedLevel.serialized").toFile());
assertArrayEquals(map.getShape(), testMap.getShape());
for (int i = 0; i < map.getPieces().size(); i++) {
assertArrayEquals(map.getPieces().get(i).getShape(), testMap.getPieces().get(i).getShape());
}
}
@Test
void saveLoadFileFromMap_save_Serialized(@TempDir Path tmpFolder) throws IOException{
Map map = generateMapTest();
FileParserFactory.saveFileFromMap(tmpFolder.resolve("TestSerializedSave.sserialized").toFile(), map);
Map testMap = FileParserFactory.loadMapFromFile(tmpFolder.resolve("TestSerializedSave.sserialized").toFile());
assertArrayEquals(map.getShape(), testMap.getShape());
for (int i = 0; i < map.getPieces().size(); i++) {
assertArrayEquals(map.getPieces().get(i).getShape(), testMap.getPieces().get(i).getShape());
assertEquals(map.getPieces().get(i).getPosition(), testMap.getPieces().get(i).getPosition());
}
}
}

View File

@ -17,7 +17,6 @@ class PieceTest {
boolean[][] piece1_matrix_result = {
{true, false, true},
{true, true, false},
{false, false, false},
};
boolean[][] piece2_matrix = {
@ -31,12 +30,11 @@ class PieceTest {
};
boolean[][] piece3_matrix_result = {
{false, false, false},
{false, true, true},
{true, false, true},
};
Piece piece1 = new Piece();
Piece piece1 = new Piece(piece2_matrix);
piece1.setShape(piece1_matrix);
Piece piece2 = new Piece(piece2_matrix);

View File

@ -1,6 +1,9 @@
package school_project;
import org.junit.jupiter.api.Test;
import school_project.Utils.Array;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
@ -29,6 +32,30 @@ class ShapeTest {
{true}
};
boolean[][] matrix_shape5 = {
{false, false, false, false, false},
{false, false, false, false, false},
{false, true, true, true, false},
{false, true, false, true, false},
{false, false, false, false, false},
{false, false, false, false, false},
};
boolean[][] matrix_shape5_result = {
{true, true, true},
{true, false, true},
};
boolean[][] matrix_shape6 = {
{true, false},
{false, false}
};
boolean[][] matrix_shape6_result = {
{true},
};
System.out.println(Array.isRowOnlyFalse(matrix_shape1, 0));
Shape shape1 = new Shape();
shape1.setShape(matrix_shape1);
assertEquals(3, shape1.getHeight());
@ -44,5 +71,11 @@ class ShapeTest {
assertEquals(3, shape4.getHeight());
assertEquals(1, shape4.getWidth());
Shape shape5 = new Shape(matrix_shape5);
assertArrayEquals(matrix_shape5_result, shape5.getShape());
Shape shape6 = new Shape(matrix_shape6);
assertArrayEquals(matrix_shape6_result, shape6.getShape());
}
}

View File

@ -0,0 +1,81 @@
package school_project.Utils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ArrayTest {
@Test
void matrixCopyOf() {
boolean[][] a = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
boolean[][] b = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
boolean[][] c = Array.MatrixCopyOf(a);
assertArrayEquals(a, c);
a[1][1] = true;
assertArrayEquals(b, c);
}
@Test
void matrixRemoveRow() {
boolean[][] a = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
boolean[][] b = new boolean[][] {
{true, false, true},
{true, false, true},
};
boolean[][] result = Array.MatrixRemoveRow(a, 1);
assertArrayEquals(b, result);
}
@Test
void matrixRemoveColumn() {
boolean[][] a = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
boolean[][] b = new boolean[][] {
{true, true},
{false, false},
{true, true},
};
boolean[][] result = Array.MatrixRemoveColumn(a, 1);
assertArrayEquals(b, result);
}
@Test
void isRowOnlyFalse() {
boolean[][] a = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
assertTrue(Array.isRowOnlyFalse(a, 1));
assertFalse(Array.isRowOnlyFalse(a, 0));
}
@Test
void isColumnOnlyFalse() {
boolean[][] a = new boolean[][] {
{true, false, true},
{false, false, false},
{true, false, true},
};
assertTrue(Array.isColumnOnlyFalse(a, 1));
assertFalse(Array.isColumnOnlyFalse(a, 0));
}
}

View File

@ -1,42 +0,0 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@ -1,57 +0,0 @@
plugins {
id 'java'
id 'application'
id 'org.javamodularity.moduleplugin' version '1.8.12'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'org.beryx.jlink' version '2.25.0'
}
group 'com.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.9.1'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'com.example.demo'
mainClass = 'com.example.demo.HelloApplication'
}
javafx {
version = '17.0.2'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}

Binary file not shown.

View File

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -1 +0,0 @@
rootProject.name = "demo"

View File

@ -1,184 +0,0 @@
package com.example.demo;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Objects;
public class HelloApplication extends Application {
private Stage stage;
//set up scene one
private Scene Menu;
private BorderPane BdP;
private Label title;
private Button Play;
private Button Select_level;
private Button Trophy;
//set up scene 2
private Scene Level_menu;
private GridPane GdP;
private Button bck_menu;
//button for levele
private MenuButton select_day;
private Button _1;
private Button _2;
private Button _3;
private Button _4;
private Button _5;
private Button _6;
private Button _7;
private Button _8;
private Button _9;
private Button _10;
public void start(Stage primaryStage) {
//set up the page
stage = primaryStage;
stage.setTitle("ROAD TO MASTER YOU");
Menu = createMenu();
Level_menu = createLevel_menu();
stage.setScene(Menu);
stage.show();
}
private Scene createMenu(){
Play = new Button("Play");
Trophy = new Button("Trophy");
Select_level = new Button("Select Level");
Select_level.setOnAction(event -> switchScenes(Level_menu));
title = new Label("Welcome to road to master you");
title.setFont(Font.font(20));
title.setTextFill(Color.GOLD);
BdP = new BorderPane(null,title,Select_level,Trophy,Play);
Menu = new Scene(BdP,700,400);
BorderPane.setAlignment(title,Pos.CENTER);
BorderPane.setAlignment(Play,Pos.CENTER);
BorderPane.setAlignment(Select_level,Pos.CENTER);
BorderPane.setAlignment(Trophy,Pos.CENTER);
Menu.getStylesheets().add("style.css");
BdP.setPadding(new Insets(20,60,20,60));
return Menu;
}
private Scene createLevel_menu(){
bck_menu = new Button("Back to the menu");
bck_menu.setOnAction(event -> switchScenes(Menu));
GdP = new GridPane();
Level_menu = new Scene(GdP,700,400);
_1 = new Button("1");
_2 = new Button("2");
_3 = new Button("3");
_4 = new Button("4");
_5 = new Button("5");
_6 = new Button("6");
_7 = new Button("7");
_8 = new Button("8");
_9 = new Button("9");
_10 = new Button("10");
select_day = new MenuButton("Select day");
//set up of the button
GdP.add(select_day,1,0);
GdP.add(_1,0,1);
GdP.add(_2,1,1);
GdP.add(_3,2,1);
GdP.add(_4,0,2);
GdP.add(_5,1,2);
GdP.add(_6,2,2);
GdP.add(_7,0,3);
GdP.add(_8,1,3);
GdP.add(_9,2,3);
GdP.add(_10,1,4);
GdP.add(bck_menu,2,4);
//set up gap and padding and everything else
GdP.setHgap(20);
GdP.setVgap(20);
GdP.setPadding(new Insets(40,20,20,40));
ColumnConstraints col_1 = new ColumnConstraints();
col_1.setPercentWidth(33);
ColumnConstraints col_2 = new ColumnConstraints();
col_2.setPercentWidth(33);
ColumnConstraints col_3 = new ColumnConstraints();
col_3.setPercentWidth(34);
GdP.getColumnConstraints().addAll(col_1,col_2,col_3);
//GdP.setGridLinesVisible(true);
GridPane.setHalignment(_1, HPos.CENTER);
GridPane.setHalignment(_2, HPos.CENTER);
GridPane.setHalignment(_3, HPos.CENTER);
GridPane.setHalignment(_4, HPos.CENTER);
GridPane.setHalignment(_5, HPos.CENTER);
GridPane.setHalignment(_6, HPos.CENTER);
GridPane.setHalignment(_7, HPos.CENTER);
GridPane.setHalignment(_8, HPos.CENTER);
GridPane.setHalignment(_9, HPos.CENTER);
GridPane.setHalignment(_10, HPos.CENTER);
GridPane.setHalignment(select_day, HPos.CENTER);
GridPane.setHalignment(bck_menu, HPos.CENTER);
return Level_menu;
}
public void switchScenes(Scene scene){
stage.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
/***@Override
public void start(Stage primaryStage) {
//set up the page
primaryStage.setTitle("Road to Master You");
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,300);
primaryStage.setScene(scene);
primaryStage.show();
//set up all the object needed for the menu
Label title = new Label("Welcome to Road to Master You");
Button Play = new Button("Play");
Button Select_level = new Button("Select Level");
Button Trophy = new Button("Trophy");
//put all the object on the page
root.setTop(title);
root.setBottom(Trophy);
root.setRight(Select_level);
root.setLeft(Play);
//adjust everything as I want (position,color)
title.setTextFill(Color.GOLD);
BorderPane.setAlignment(title,Pos.CENTER);
BorderPane.setAlignment(Play,Pos.CENTER);
BorderPane.setAlignment(Select_level,Pos.CENTER);
BorderPane.setAlignment(Trophy,Pos.CENTER);
scene.getStylesheets().add("style.css"); //todo found why there is no link btw file
//Switch scene
Select_level.setOnAction(event -> {
SelectLevel secondWindow = new SelectLevel();
secondWindow.show();
});
}
}
*/

View File

@ -1,14 +0,0 @@
package com.example.demo;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
@FXML
private Label welcomeText;
@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
}

View File

@ -1,65 +0,0 @@
/***package com.example.demo;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import static javafx.application.Application.launch;
public class SelectLevel extends Stage {
private Stage stage;
//set up scene one
private Scene Menu;
private BorderPane BdP;
private Label title;
private Button Play;
private Button Select_level;
private Button Trophy;
//set up scene 2
private Scene Level_menu;
private GridPane GdP;
private Button bck_menu;
public void start(Stage primaryStage) {
//set up the page
primaryStage.setTitle("Select your Level");
Menu = createMenu();
Level_menu = createLevel_menu();
primaryStage.setScene(Menu);
primaryStage.show();
}
private Scene createMenu(){
Play = new Button("Play");
Trophy = new Button("Trophy");
Select_level = new Button("Select Level");
Select_level.setOnAction(event -> switchScenes(Level_menu));
title = new Label("Welcome to road to master you");
BdP = new BorderPane(null,title,Select_level,Trophy,Play);
Menu = new Scene(BdP,700,400);
return Menu;
}
private Scene createLevel_menu(){
bck_menu = new Button("Back to the menu");
bck_menu.setOnAction(event -> switchScenes(Menu));
GdP = new GridPane();
Level_menu = new Scene(GdP,700,400);
return Level_menu;
}
public void switchScenes(Scene scene){
stage.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
***/

View File

@ -1,8 +0,0 @@
module com.example.demo {
requires javafx.controls;
requires javafx.fxml;
opens com.example.demo to javafx.fxml;
exports com.example.demo;
}

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
fx:controller="com.example.demo.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/19">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label prefHeight="108.0" prefWidth="200.0" style="-fx-alignment: center;" text="Select Level" GridPane.columnIndex="2" />
<Button mnemonicParsing="false" text="1" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<Button mnemonicParsing="false" text="2" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<Button mnemonicParsing="false" text="3" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="2" />
<Button mnemonicParsing="false" text="5" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<Button mnemonicParsing="false" text="6" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<Button mnemonicParsing="false" text="7" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<Button mnemonicParsing="false" text="8" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<Button mnemonicParsing="false" text="4" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="3" />
<Button mnemonicParsing="false" stylesheets="@SelectLevel.css" text="9" GridPane.columnIndex="3" GridPane.halignment="CENTER" GridPane.rowIndex="4" />
<Button mnemonicParsing="false" text="10" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="5" />
<MenuButton mnemonicParsing="false" text="Select day " GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="1">
<items>
<MenuItem mnemonicParsing="false" text="Action 1" />
<MenuItem mnemonicParsing="false" text="Action 2" />
</items>
</MenuButton>
<Button mnemonicParsing="false" text="Back to menu" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.rowIndex="6" />
</children>
</GridPane>

View File

@ -1,7 +0,0 @@
.root {
-fx-background-image: url("Background-select-level.jpg");
-fx-background-position: center
}
.button{
-fx-alignment: center;
}

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>
<BorderPane centerShape="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1">
<top>
<Label prefHeight="116.0" prefWidth="600.0" style="-fx-alignment: center; -fx-padding: 10;" text="Road to MasterU" textAlignment="CENTER" textFill="GOLD" underline="true" wrapText="true" BorderPane.alignment="CENTER">
<font>
<Font size="26.0" />
</font>
</Label>
</top>
<bottom>
<Button mnemonicParsing="false" style="-fx-alignment: center;" text="Trophy" textAlignment="CENTER" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="100.0" />
</BorderPane.margin></Button>
</bottom>
<right>
<Button mnemonicParsing="false" prefHeight="0.0" prefWidth="153.0" style="-fx-alignment: center;" text="Select Level" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets right="100.0" />
</BorderPane.margin></Button>
</right>
<left>
<Button mnemonicParsing="false" prefHeight="10.0" prefWidth="90.0" style="-fx-alignment: center;" text="Play" textAlignment="CENTER" BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets left="110.0" />
</BorderPane.margin></Button>
</left>
</BorderPane>

View File

@ -1,12 +0,0 @@
.root{
-fx-background-image:url("BackGround-menu.jpg");
-fx-background-position:center;
}
.label{
-fx-font-size: 75;
}
.button {
-fx-start-margin: 20;
-fx-text-alignment: center;
-fx-padding: 10;
}