-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
### IntelliJ IDEA ### | ||
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 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<module type="JAVA_MODULE" version="4"> | ||
<component name="NewModuleRootManager" inherit-compiler-output="true"> | ||
<exclude-output /> | ||
<content url="file://$MODULE_DIR$"> | ||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" /> | ||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | ||
<sourceFolder url="file://$MODULE_DIR$/src/test/kotlin" isTestSource="true" /> | ||
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" /> | ||
</content> | ||
<orderEntry type="inheritedJdk" /> | ||
<orderEntry type="sourceFolder" forTests="false" /> | ||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" /> | ||
<orderEntry type="module-library" scope="TEST"> | ||
<library name="JUnit4"> | ||
<CLASSES> | ||
<root url="jar://$USER_HOME$/.m2/repository/junit/junit/4.13.1/junit-4.13.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" /> | ||
</CLASSES> | ||
<JAVADOC /> | ||
<SOURCES /> | ||
</library> | ||
</orderEntry> | ||
<orderEntry type="module-library" scope="TEST"> | ||
<library name="JUnit5.8.1"> | ||
<CLASSES> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/jupiter/junit-jupiter/5.8.1/junit-jupiter-5.8.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/jupiter/junit-jupiter-api/5.8.1/junit-jupiter-api-5.8.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/opentest4j/opentest4j/1.2.0/opentest4j-1.2.0.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/platform/junit-platform-commons/1.8.1/junit-platform-commons-1.8.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/jupiter/junit-jupiter-params/5.8.1/junit-jupiter-params-5.8.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/jupiter/junit-jupiter-engine/5.8.1/junit-jupiter-engine-5.8.1.jar!/" /> | ||
<root url="jar://$USER_HOME$/.m2/repository/org/junit/platform/junit-platform-engine/1.8.1/junit-platform-engine-1.8.1.jar!/" /> | ||
</CLASSES> | ||
<JAVADOC /> | ||
<SOURCES /> | ||
</library> | ||
</orderEntry> | ||
<orderEntry type="module-library" scope="TEST"> | ||
<library name="JUnit4"> | ||
<CLASSES> | ||
<root url="jar://$MODULE_DIR$/lib/junit-4.13.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/hamcrest-core-1.3.jar!/" /> | ||
</CLASSES> | ||
<JAVADOC /> | ||
<SOURCES /> | ||
</library> | ||
</orderEntry> | ||
<orderEntry type="module-library" scope="TEST"> | ||
<library name="JUnit5.8.1"> | ||
<CLASSES> | ||
<root url="jar://$MODULE_DIR$/lib/junit-jupiter-5.8.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/junit-jupiter-api-5.8.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/opentest4j-1.2.0.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/junit-platform-commons-1.8.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/apiguardian-api-1.1.2.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/junit-jupiter-params-5.8.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/junit-jupiter-engine-5.8.1.jar!/" /> | ||
<root url="jar://$MODULE_DIR$/lib/junit-platform-engine-1.8.1.jar!/" /> | ||
</CLASSES> | ||
<JAVADOC /> | ||
<SOURCES /> | ||
</library> | ||
</orderEntry> | ||
</component> | ||
</module> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Simulation d'un automate en Kotlin | ||
|
||
Ce projet Kotlin simule un automate fini simple. Il permet de définir des états, des transitions entre eux, et de vérifier si un mot donné est accepté par l'automate. | ||
|
||
## Comment lancer le projet ? | ||
|
||
Lancez [le .jar](automateDemo.jar) avec la commande `java -jar .\automateDemo.jar` | ||
|
||
## Automates par défauts | ||
(dans `Main.kt`) | ||
|
||
Voici les automates disponibles : | ||
|
||
- Automate acceptant les nombres de 01 à 57 | ||
[![Automate 01-57](src/main/resources/auto_exo7-01-57.jpg)](src/main/resources/auto_exo7-01-57.jpg) | ||
|
||
- Automate acceptant les dates (format JJ/MM/AAAA) | ||
[![Automate Date](src/main/resources/auto_exo7-Date.jpg)](src/main/resources/auto_exo7-Date.jpg) | ||
|
||
- Automate acceptant les heures (HH:MM) | ||
[![Automate Heure](src/main/resources/auto_exo7-Heure.jpg)](src/main/resources/auto_exo7-Heure.jpg) | ||
|
||
## Classes | ||
|
||
### `State` | ||
Cette classe représente un état dans l'automate. | ||
|
||
- **Attributs** : | ||
- `nom` : Nom de l'état. | ||
- `transitions` : Un dictionnaire de transitions où la clé est un caractère et la valeur est l'état suivant. | ||
|
||
- **Fonctions** : | ||
- `getNom()` : Retourne le nom de l'état. | ||
- `getTransition()` : Retourne la table des transitions de l'état. | ||
- `addTransition(c: Char, destination: State)` : Ajoute une transition de cet état vers un autre, basée sur le caractère `c`. | ||
|
||
- **Méthode statique** : | ||
- `createStates(word: String, start: Int, end: Int): MutableList<State>` : Crée une liste d'états avec des noms basés sur `word` et des indices allant de `start` à `end`. | ||
|
||
### `Automate` | ||
Cette classe représente l'automate lui-même. | ||
|
||
- **Attributs** : | ||
- `s0` : L'état de départ. | ||
- `sf` : Un ensemble d'états finaux (états d'acceptation). | ||
- `alpha` : Un ensemble de caractères (alphabet) reconnu par l'automate. | ||
- `etats` : Un ensemble de tous les états de l'automate. | ||
- `delta` : Un dictionnaire des transitions entre les états. | ||
|
||
- **Fonctions** : | ||
- `setStartingState(s0: State)` : Définit l'état de départ de l'automate. | ||
- `getStartingState()` : Retourne l'état de départ. | ||
- `addFinalState(s: State)` : Ajoute un état final (d'acceptation). | ||
- `getFinalStates()` : Retourne l'ensemble des états finaux. | ||
- `getDeltas()` : Retourne la table des transitions (fonction delta). | ||
- `addDelta(source: State, c: Char, destination: State)` : Ajoute une transition de `source` à `destination` basée sur le caractère `c`. | ||
- `addDeltaFromList(source: State, ls: List<Char>, destination: State)` : Ajoute plusieurs transitions de `source` à `destination` basées sur une liste de caractères `ls`. | ||
- `addDeltaFromString(source: State, exp: String, destination: State)` : Ajoute des transitions basées sur une expression sous forme de chaîne (supporte les intervalles comme `a..z` ou des caractères individuels comme `a | b`). | ||
- `getAlpha()` : Retourne l'ensemble des caractères de l'alphabet. | ||
- `getStates()` : Retourne l'ensemble de tous les états. | ||
- `getNom()` : Retourne le nom de l'automate. | ||
- `DoYouAccept(word: String, debug_Output: Boolean = true): Boolean` : Vérifie si l'automate accepte un mot donné et affiche les étapes de transition si `debug_Output` est défini à `true`. | ||
|
||
## Exemple | ||
|
||
L'exemple suivant montre comment créer un automate qui n'accepte que les nombre de 01 (inclus) à 57 (inclus), définir des transitions et vérifier si un mot est accepté. | ||
|
||
[![Automate 01-57](src/main/resources/auto_exo7-01-57.jpg)](src/main/resources/auto_exo7-01-57.jpg) | ||
|
||
```kotlin | ||
val Etats_0157 = State.createStates("A", 0, 7) | ||
val Auto_0157 = Automate("01-57") | ||
|
||
// Ajout des transitions | ||
Auto_0157.addDeltaFromString(Etats_0157[0], "0", Etats_0157[1]) | ||
Auto_0157.addDeltaFromString(Etats_0157[1], "1..9", Etats_0157[7]) | ||
Auto_0157.addDeltaFromString(Etats_0157[0], "1..4", Etats_0157[3]) | ||
Auto_0157.addDeltaFromString(Etats_0157[3], "0..9", Etats_0157[7]) | ||
Auto_0157.addDeltaFromString(Etats_0157[0], "5", Etats_0157[5]) | ||
Auto_0157.addDeltaFromString(Etats_0157[5], "0..7", Etats_0157[7]) | ||
|
||
// Définition de l'état de départ et de l'état final | ||
Auto_0157.setStartingState(Etats_0157[0]) | ||
Auto_0157.addFinalState(Etats_0157[7]) | ||
|
||
// Vérification si un mot est accepté | ||
var isAccepted = Auto_0157.DoYouAccept("111") | ||
println("Mot accepté : $isAccepted") //Mot accepté : false | ||
isAccepted = Auto_0157.DoYouAccept("24") | ||
println("Mot accepté : $isAccepted") //Mot accepté : true | ||
``` | ||
Dans cet exemple : | ||
- On crée 8 états (de A0 à A7). | ||
- On définit des transitions pour les caractères entre les états. | ||
- L'automate commence à l'état A0 et accepte le mot lorsqu'il atteint l'état A7. | ||
- Les mots 111 et 24 sont vérifiés pour être acceptés. | ||
|
||
## Conclusion | ||
|
||
Cet automate basé sur Kotlin permet de modéliser et simuler des systèmes à états avec des transitions entre les états selon des entrées de caractères. La fonction DoYouAccept() évalue si un mot est valide selon les règles de l'automate. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
class Automate(nom : String) { | ||
|
||
private lateinit var s0 : State | ||
private var sf : MutableSet<State> = mutableSetOf() | ||
private var nom : String = nom | ||
private var alpha : MutableSet<Char> = mutableSetOf() | ||
private var etats : MutableSet<State> = mutableSetOf() | ||
private var delta : HashMap<State,HashMap<Char,State>> = hashMapOf() /// E0 -> {'c' -> {"E1"}} | ||
///////////////////////////////////Starting State | where we start | ||
fun setStartingState(s0 : State) { | ||
this.s0 = s0 | ||
} | ||
|
||
fun getStartingState() = this.s0 | ||
///////////////////////////////////Final State | set of ending states | ||
fun addFinalState(s : State) { | ||
this.sf.add(s) | ||
} | ||
|
||
fun getFinalStates() = this.sf | ||
|
||
///////////////////////////////////Delta | all transition within | ||
fun getDeltas() = this.delta // | ||
|
||
fun addDelta(source : State, c : Char ,destination : State) { | ||
alpha.add(c) | ||
etats.add(source) | ||
etats.add(destination) | ||
|
||
val h : HashMap<Char,State> = hashMapOf() | ||
source.addTransition(c,destination) | ||
|
||
delta.put(source,source.getTransition()) | ||
} | ||
|
||
fun addDeltaFromList(source : State, ls : List<Char> ,destination : State) { | ||
ls.forEach{it -> ( | ||
addDelta(source,it,destination) | ||
)} | ||
} | ||
|
||
fun addDeltaFromString(source : State, exp : String, destination : State) { //from like "a | b..c" | ||
val orexp = exp.split(" | ") | ||
orexp.forEach { it -> ( | ||
if (it.contains("..")) { //is a..b | ||
val interexp = it.split("..") | ||
val a = interexp[0] | ||
val b = interexp[1] | ||
if (a.length==1 && b.length==1) { | ||
addDeltaFromList(source,(a.toCharArray()[0]..b.toCharArray()[0]).toList(),destination) | ||
} else { | ||
println("Impossible d'ajouté l'expression suivante : "+interexp) | ||
} | ||
|
||
} else { | ||
if (it.length==1) { //is just a char | ||
addDelta(source,it.toCharArray()[0],destination) | ||
} else { | ||
println("Impossible d'ajouté l'expression suivante : "+it) | ||
} | ||
} | ||
)} | ||
} | ||
///////////////////////////////////Alpha | all characters that can be checked | ||
fun getAlpha() = this.alpha | ||
|
||
///////////////////////////////////States | all states within | ||
fun getStates() = this.etats | ||
|
||
///////////////////////////////////Nom | ||
fun getNom() = this.nom | ||
|
||
///////////////////////////////////Acceptor | ||
fun DoYouAccept(word : String, debug_Output : Boolean = true) : Boolean { | ||
var finalsState = getFinalStates() | ||
if (finalsState.size==0) { | ||
error("Pas de point de fin déclaré") | ||
} | ||
|
||
var currentState = getStartingState() | ||
var currentWord = word | ||
|
||
while (currentWord.isNotEmpty() || !finalsState.contains(currentState)) { // while not at one of the end AND still has characters left to check | ||
try { | ||
val old = currentState //save the state we are on | ||
|
||
currentState = currentState.getTransition().get(currentWord[0]) ?: return false // if it found one state linked to the 1st letter then move to it, else return false (nothing linked, stuck) | ||
|
||
if (debug_Output) { | ||
println(old.getNom()+" ➜ "+currentState.getNom()) //told where we moved | ||
} | ||
|
||
currentWord = currentWord.drop(1) // edit word so that it remove the letter that was analysed | ||
} catch (e : Exception) { //In case of StringIndexesOutOfBound | ||
return false | ||
} | ||
} | ||
|
||
return true // no characters left AND reach one of the end | ||
} | ||
} |