-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmyFrontend.wl
More file actions
235 lines (186 loc) · 10.6 KB
/
myFrontend.wl
File metadata and controls
235 lines (186 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
(* ::Package:: *)
(* ::Section:: *)
(*myFrontend*)
(* ::Text:: *)
(*Pacchetto dedicato alla costruzione del men\[UGrave] utilizzabile nel notebook, con annessa implementazione delle funzionalit\[AGrave] dei pulsanti. *)
(* ::Section:: *)
(*Implementazione*)
(* :Title: myFrontend*)
(* :Context: myFrontend`*)
(* :Author: Michele Bianco, Chiara Mengoli, Akira Petrolini, Christian Preti, Riccardo Scotti *)
(* :Summary: Pacchetto dedicato alla costruzione del men\[UGrave] utilizzabile nel notebook, con annessa implementazione delle funzionalit\[AGrave] dei pulsanti. *)
(* :Copyright: MB/CM/AP/CP/RS 2023 *)
(* :Package Version: 1 *)
(* :Mathematica Version: 13 *)
(* :History: last modified 25/05/2023 *)
BeginPackage["myFrontend`"]
showFrontend::usage = "Ritorna una struttura grafica utilizzata per interagire con il software.";
Begin["Private`"]
Needs["GeneralOracleBack`"]; (*Inserisco le dipendenze per richiamare funzioni definite in altri pacchetti come GetDataset[], GenerateGraph[], ...*)
Needs["ItalianActorPreprocessing`"];
Needs["CheckForm`"];
(*
ShowFrontend si occupa di disegnare il Frontend del software.
Al suo interno \[EGrave] presente un pannello (Panel), contenente in "modalit\[AGrave] griglia" (Grid) una sequenza di componenti.
Alla prima riga troviamo quattro InputField, ovvero:
- Attore1;
- Attore2;
- Tentativo per "Indovina", dovr\[AGrave] necessariamente contenere un valore numerico;
- Seed per la generazione casuale, dovr\[AGrave] necessariamente contenere un valore numerico.
Alla seconda riga troviamo invece i pulsanti per chiamare i relativi metodi, tra cui:
- Calcola, per generare lo ShortestPath tra la coppia di attori;
- Reset, per ripulire gli eventuali input inseriti dall'utente;
- Indovina, per provare ad indovinare la distanza tra la coppia di attori;
- Casuale, per estrarre in modo semi-casuale, partendo da un seed, una coppia di attori.
*)
showFrontend[] :=
DynamicModule[
{inputActor1, inputActor2, answer, seed, cfOutput, sp, re, outputMessage, italianFilms,
gr, buttonX, buttonY, labelX, labelY, panelX, panelY, owX, owY, outputWindow},
italianFilms = GetDataset[]; (* Utilizziamo il metodo GetDataset, definito in GeneralOracleBack, per estrarre e salvare in una variabile il dataset ottenuto a partire dall'unione dei due file .csv *)
gr = GenerateGraph[italianFilms, "Actor", "OriginalTitle"];
(* Variabili hardcoded utilizzate per definire la dimensione dei vari componenti del frontend. *)
(*
Utilizziamo il metodo GenerateGraph, definito in GeneralOracleBack, per creare il grafo a partire dal dataset appena calcolato.
"Actor" rappresenta la colonna del dataset su cui verranno definiti i nodi del grafo.
"OriginalTitle" rappresenta la colonna del dataset attraverso cui verranno congiunti i nodi, ovvero gli archi del grafo.
*)
gr = GenerateGraph[italianFilms, "Actor", "OriginalTitle"];
(* Dimensione dei pulsanti *)
buttonX = 100;
buttonY = 50;
(* Dimensioni delle label *)
labelX = 300;
labelY = 90;
(* Dimensioni dei pannelli *)
panelX = 900;
panelY = 200;
(*Dimensioni finestra di output per "Calcola"*)
owX = 550;
owY = 1100;
(*Variabile che verifica o meno la presenza della finestra di output*)
outputWindow = Null;
Panel[
Grid[{
{
(* Prima riga del Grid, contenente i quattro InputField in cui l'utente pu\[OGrave] inserire i relativi valori. *)
InputField[Dynamic[inputActor1], String, FieldHint -> "Inserisci il primo attore..."], (* Primo attore *)
InputField[Dynamic[inputActor2], String, FieldHint -> "Inserisci il secondo attore..."], (* Secondo attore *)
InputField[Dynamic[answer], Number, FieldHint -> "Indovina la distanza..."], (* Tentativo di "Indovina" *)
InputField[Dynamic[seed], Number, FieldHint -> "Scegli un seed..."] (* Seed per la generazione casuale *)
},
(* Seconda riga del Grid *)
{
(* Pulsante che calcola la distanza tra due attori forniti in input. *)
Button[Style["Calcola", Medium], (
(* Controlla che l'utente abbia inserito valori in entrambe le InputField. *)
If[StringQ[inputActor1] == False || StringQ[inputActor2] == False,
CreateDialog[{TextCell["\[CapitalEGrave] necessario inserire entrambi gli attori."]}],
(
(* Correzione nomi attori attraverso il metodo InputCorrection, definito in GeneralOracleBack. *)
inputActor1 = InputCorrection[inputActor1];
inputActor2 = InputCorrection[inputActor2];
(* Vari controlli sui valori immessi dall'utente, attraverso il metodo CheckForm definito in GeneralOracleBack. *)
cfOutput = CheckForm[gr, inputActor1, inputActor2];
(*
Viene controllato il valore contenuto in "cfOutput".
Se esso \[EGrave] una stringa, sar\[AGrave] uno dei vari messaggi di errore, da inserire quindi in un Dialog.
Altrimenti, il valore contenuto sar\[AGrave] "True", ottenuto dalla condizione di default, e verr\[AGrave] quindi calcolato lo shortest path.
*)
If[StringQ[cfOutput],
(CreateDialog[{TextCell[cfOutput], DefaultButton[]}, WindowSize -> {labelX, labelY}]),
sp = CalcShortestPath[gr, inputActor1, inputActor2]; (* Utilizzo del metodo CalcShortestPath, contenuto in GeneralOracleBack. *)
(* Chiude la finestra di output precedente, se presente *)
NotebookClose[outputWindow];
(*
Controlla se la coppia di attori presenta un collegamento, altrimenti stampa un messaggio all'utente.
N.B. -1 indica che gli attori non presentano un collegamento tra loro.
*)
If[Length[sp[["entityPath"]]] - 1 == -1,
outputMessage = "Gli attori non hanno nessun collegamento.",
outputMessage = "Il grado di separazione tra gli attori \[EGrave] " <> ToString[Length[sp[["entityPath"]]] - 1]
];
(*
Crea una nuova finestra, essa pu\[OGrave] contenere:
- Distanza e relativo grafo, se nell'If precedente il percorso \[EGrave] stato trovato.
- Messaggio di errore (inserito sopra), altrimenti.
*)
outputWindow = CreateDocument[
{
TextCell[outputMessage, Magnification->2],
displaySolution[sp]
}, WindowSize -> {owX, owY}]])
]), ImageSize -> {buttonX, buttonY}],
(* Pulsante di reset, per ripulire gli InputField dagli eventuali valori inseriti. *)
Button[Style["Reset", Medium], (
(* Resetto i valori eventualmente contenuti all'interno dei quattro InputField. *)
inputActor1 = inputActor2 = Null;
answer = Null;
seed = Null;
), ImageSize -> {buttonX, buttonY}],
(* Pulsante per fornire all'utente la possibilit\[AGrave] di indovinare il risultato della distanza. *)
Button[Style["Indovina", Medium],(
(* Vengono effettuati vari controlli sull'input inserito dall'utente. *)
Which[
(* Controllo che l'utente abbia inserito un valore. *)
Not[NumberQ[answer]],
(CreateDialog[{TextCell["\[CapitalEGrave] necessario inserire un numero per provare ad indovinare."],
DefaultButton[]}, WindowSize -> {labelX, labelY}];),
(* Controllo che l'utente non abbia inserito valori negativi, eccezion fatta per -1, ad indicare un percorso non trovato. *)
answer < 0 && answer != -1,
(CreateDialog[{TextCell["Non \[EGrave] possibile inserire valori negativi, eccezion fatta per -1."],
DefaultButton[]}, WindowSize -> {labelX, labelY}];),
(* Controllo che l'utente abbia inserito una coppia di attori. *)
StringQ[inputActor1] == False || StringQ[inputActor2] == False,
(CreateDialog[{TextCell["\[CapitalEGrave] necessario inserire entrambi gli attori."],
DefaultButton[]}, WindowSize -> {labelX, labelY}];),
(* Campo default, in caso l'input sia corretto *)
True, (
(* Correzione nomi attori *)
inputActor1 = InputCorrection[inputActor1];
inputActor2 = InputCorrection[inputActor2];
cfOutput = CheckForm[gr, inputActor1, inputActor2];
If[StringQ[cfOutput],
(CreateDialog[{TextCell[cfOutput], DefaultButton[]}, WindowSize -> {labelX, labelY}]),
(sp = CalcShortestPath[gr, inputActor1, inputActor2];
(*
answer \[EGrave] il Dynamic collegato all'InputField di "Indovina".
Se il tentativo inserito dall'utente \[EGrave] uguale alla risposta corretta, viene stampato un messaggio di "successo".
Altrimenti, verr\[AGrave] invitato l'utente a fare un altro tentativo.
*)
If[answer == Length[sp[["entityPath"]]]-1,
(CreateDialog[{TextCell["Complimenti, hai indovinato!"], DefaultButton[]},
WindowSize -> {labelX, labelY}];),
(CreateDialog[{TextCell["Peccato, risposta errata!"], DefaultButton[]},
WindowSize -> {labelX, labelY}];)
]
)
];
)
];
), ImageSize->{buttonX, buttonY}],
(* Attraverso il seguente pulsante, \[EGrave] possibile estrarre due attori casuali dal dataset, i cui "Nome Cognome" verranno inseriti nei relativi InputField. *)
Button[Style["Casuale", Medium], (
(*
Viene controllato che l'InputField non sia vuoto.
Se vuoto, viene stampato un messaggio di errore.
Altrimenti, viene utilizzato il metodo RandomExtract, definito in GeneralOracleBack, per estrarre una coppia di attori dal dataset.
*)
If[NumberQ[seed] == False,
(CreateDialog[{TextCell["\[CapitalEGrave] necessario inserire un seed per generare risultati casuali."],
DefaultButton[]}, WindowSize -> {labelX, labelY}];),
(*
RandomExtract prende come parametri due argomenti:
- gr: il grafo da cui estrarre la coppia di attori.
- seed: Il seed a partire da cui vengono scelti gli attori.
*)
(re = RandomExtract[gr, seed]; inputActor1 = re[[1]]; inputActor2 = re[[2]];)
]
), ImageSize -> {buttonX, buttonY}]
}
},Spacings -> {4, 1}
],ImageSize -> {panelX, panelY}
]
]
End[]
EndPackage[]