-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprojetoLP.pl
More file actions
380 lines (320 loc) · 13 KB
/
Copy pathprojetoLP.pl
File metadata and controls
380 lines (320 loc) · 13 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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
:-encoding(utf8).
% 118098 - Afonso Miguel Loureiro Sopa
:-style_check(-discontiguous).
:-set_prolog_flag(answer_write_options,[max_depth(0)]).
:-['codigoAuxiliar.pl'].
:-['bd_estudantes.pl'].
:-['listas_palavras.pl'].
/*--------------
PARTE 1
--------------*/
media([],0):- !. % Caso base: a média de uma lista vazia é 0
media(ListaValores, Media):-
% Somar todos os valores da lista
sum_list(ListaValores, Soma),
% Obter o comprimento da lista
length(ListaValores, Comprimento),
% Arredondar a média
arredonda(Soma/Comprimento, Res),
Media is Res. % Atribuir o valor arredondado à variável Media
mediaNotasPorIdade(IdadeMin, IdadeMax, Media):-
%Encontrar todas as notas dos estudantes que estão no intervalo de idades
findall(Nota,
%Associar o id do estudante à sua idade e à sua nota
(estudante(Id, Idade, _),
%Verificar se a idade está no intervalo
Idade > IdadeMin,
Idade =< IdadeMax,
%Obter a nota do estudante
exame(Id, Nota)),
ListaNotas),
%Calcular a média das notas
media(ListaNotas, Media).
freqPorGenero(Genero, MediaFreq):-
%Encontrar todas as frequências associadas ao género
findall(Freq,
%Associar o id do estudante ao seu género e à sua frequência
(estudante(Id, _, Genero),
atividade(Id, _, _, Freq)), ListaFreqs),
%Calcular a média das frequências
media(ListaFreqs, MediaFreq).
alertaSaude(HorasSono, Exercicio, SaudeMental, ListaAlunos):-
%Encontrar todos os id's que satisfaçam os critérios
findall(Id,
%Associar o id do estudante ao seu estado de saude
(estudante(Id, _, _),
saude(Id, Sono, QualAlimentacao, ExFisico, SMental),
%Condição1: A qualidade de alimentação é fraca
QualAlimentacao == fraca,
%Condição2: Dormem menos do que HorasSono
Sono < HorasSono,
%Condição3: Fazem menos exercício físico do que Exercicio
ExFisico < Exercicio,
%Condição4: Saúde Mental abaixo de SaudeMental
SMental < SaudeMental),
ListaAlerta),
%Ordenar a lista de alunos em estado de alerta
sort(ListaAlerta, ListaAlunos).
probEcraNotasAltas(HorasEcra, Nota, Probabilidade):-
%Encontrar todos os estudantes que passam mais de HorasEcra em frente ao ecrã
findall(Id,
(estudante(Id, _, _),
atividade(Id, _, TempoEcra, _),
%Condição1: Passar mais tempo em frente ao ecrã do que HorasEcra
TempoEcra > HorasEcra),
Ecra
),
%Encontrar todos os estudantes que têm nota superior a Nota e que passam mais de HorasEcra em frente ao ecrã
findall(Id,
(estudante(Id, _, _),
exame(Id, NotaExame),
%Condição1: Ter a nota do exame superior a Nota
NotaExame > Nota,
atividade(Id, _, TempoEcra, _),
%Condição2: Passar mais tempo em frente ao ecrã do que HorasEcra
TempoEcra > HorasEcra),
HorasEcraENotas
),
%Obter o comprimento das duas listas
length(HorasEcraENotas, ANB),
length(Ecra,B),
%Calcular a probabilidade
B > 0, %Denominador tem de ser maior que 0
P is ANB / B,
arredonda(P, Probabilidade).
subtraiValorDeLista([],_,[]):-!. % Caso base: a soma de uma lista vazia é 0
subtraiValorDeLista([Num|Resto], Valor, [NovoNum|RestoRes]):-
%Calcular o novo valor
NovoNum is Num - Valor,
%Chamar recursivamente a função para o resto da lista
subtraiValorDeLista(Resto, Valor, RestoRes).
somaQuadrados([], 0):-!.
somaQuadrados([Num|Resto], Resultado):-
%Obter o quadrado do numero "Num"
Quadrado is Num * Num,
somaQuadrados(Resto, SomaResto),
Resultado is Quadrado + SomaResto. %Atualizar o resultado final
produtoEscalar([], [], 0):-!.
produtoEscalar([Num1|Resto1], [Num2|Resto2], Resultado):-
%Multiplicar os Numeros correspondentes
Res is Num1 * Num2,
produtoEscalar(Resto1, Resto2, RestoRes),
Resultado is Res + RestoRes. %Atualizar o resultado final
correlacao([],[],0):-!. %Caso base
correlacao(Lista1, Lista2, Resultado):-
%Calcular as medias
media(Lista1, MediaX),
media(Lista2, MediaY),
%Calcular os Desvios
subtraiValorDeLista(Lista1, MediaX, DesvioX),
subtraiValorDeLista(Lista2, MediaY, DesvioY),
%Calcular o Numerador
produtoEscalar(DesvioX, DesvioY, Numerador),
%Soma do quadrado dos Desvios
somaQuadrados(DesvioX, SomaQuadradosX),
somaQuadrados(DesvioY, SomaQuadradosY),
%Calcular Denominador
Denominador is sqrt(SomaQuadradosX) * sqrt(SomaQuadradosY),
%Obter o resultado final
Res is Numerador/Denominador,
arredonda(Res, Resultado).
/*--------------
PARTE 2
--------------*/
%Predicado Principal
tamanho(Palavra, Tamanho):-
%Criar uma lista com todos os caracteres da Palavra
string_chars(Palavra, Lista),
tamanho_lista(Lista, Tamanho).
%Predicado Auxiliar
tamanho_lista([], 0). %Caso Base -> Lista Vazia
tamanho_lista([_|Resto], Tamanho):-
tamanho_lista(Resto, TamanhoResto),
Tamanho is TamanhoResto + 1.
verificaECalcula(Palavra1, Palavra2, CaracteresPalavra1, CaracteresPalavra2):-
%Obter o comprimento das palavras
tamanho(Palavra1, T1),
tamanho(Palavra2, T2),
%Verificar a condição: O comprimento das palavras tem de ser igual
T1 =:= T2,
%Converter as palavras para uma lista com todos os caracteres
string_chars(Palavra1, CaracteresPalavra1),
string_chars(Palavra2, CaracteresPalavra2).
quantasN(Id, N, Quantas):-
%Obter a lista correspondente ao Id
lista_palavras(Id, Lista),
quantasN_lista(Lista, N, Quantas).
%Predicado auxiliar para trabalhar com a lista
quantasN_lista([], _, 0). %Caso Base -> Lista Vazia
quantasN_lista([Palavra|Resto], N, Quantas):-
tamanho(Palavra, Tamanho),
(%Condição: Caso o tamanho da palavra seja igual a N
Tamanho =:= N ->
quantasN_lista(Resto, N, QuantasResto),
Quantas is QuantasResto + 1 % Somar 1 ocorrência
%Se o tamanho for diferente, o resultado mantém-se
;
quantasN_lista(Resto, N, Quantas)
).
quantasC(Id, C, Quantas):-
%Obter a lista correspondente ao Id
lista_palavras(Id, Lista),
quantasC_lista(Lista, C, Quantas).
quantasC_lista([], _, 0). %Caso Base -> Lista Vazia
quantasC_lista([Palavra|Resto], C, Quantas):-
%Colocar os caracteres da palavra numa lista
string_chars(Palavra, ListaPalavra),
%Isolar a inicial
ListaPalavra = [Inicial|_],
(%Condição: A inicial da palavra ser igual ao argumento C
Inicial == C ->
quantasC_lista(Resto, C, QuantasResto),
Quantas is QuantasResto + 1 %Somar 1 à ocorrência
%Se a inicial for diferente, o resultado mantém-se
;
quantasC_lista(Resto, C, Quantas)
).
apagaElemento(_, [], []):-!. %Caso Base -> Lista Vazia
%Caso o Elemento coresponda ao caracter da lista
apagaElemento(Elemento, Lista1, Lista2):-
Lista1 = [Elemento|Resto],
Lista2 = Resto, !.
%Caso o Elemento seja diferente do caracter da lista
apagaElemento(Elemento, Lista1, Lista2) :-
Lista1 = [E|Resto],
Lista2 = [E|RestoRes],
apagaElemento(Elemento, Resto, RestoRes).
posicoesPalavra(Palavra, Posicoes):-
%Converter a palavra para lista de caracteres
string_chars(Palavra, ListaLetras),
atribui_indices(ListaLetras, 1, ListaPosicao),
%Ordenar a lista (Letra, Posição)
sort(ListaPosicao, Posicoes).
%Predicado Auxiliar
atribui_indices([],_,[]). %Caso base -> Lista Vazia
atribui_indices([Letra|Resto], Indice, [(Letra,Indice)|RestoPares]):-
%Atualizar o indíce
NovoIndice is Indice + 1,
atribui_indices(Resto, NovoIndice, RestoPares).
pista1(Palavra1, Palavra2, Pista):-
%Verificar o comprimento das palavras e criar listas com os seus caracteres
verificaECalcula(Palavra1, Palavra2, L1, L2),
%A função maplist percorre as lista em paralelo e chama o predicado compara_letra
maplist(compara_letra1, L1, L2, Pista).
%Predicado auxiliar
compara_letra1(Letra1, Letra2, Res):-
%Compara os caracteres e atribuir pontuação
(Letra1 == Letra2 ->
Res = 2
;
Res = 0
).
pista2(Palavra1, Palavra2, Pista):-
%Verificar o comprimento das palavras e criar listas com os seus caracteres
verificaECalcula(Palavra1, Palavra2, L1, L2),
%A função maplist percorre as lista em paralelo e chama o predicado compara_letra2
maplist(compara_letra2(L1), L1, L2, Pista).
%Predicado Auxiliar
compara_letra2(Palavra, Letra1, Letra2, Res):-
(%Condição 1: Letras iguais no mesmo indíce
Letra1 == Letra2 ->
Res = 2
;
%Condição 2: Letra pertence à palavra mistério
member(Letra2, Palavra) ->
Res = 1
;
%Condição 3: Letra não pertence à palavra
Res = 0
).
pista3(Palavra1, Palavra2, Pista):-
%Verificar o comprimento das palavras e criar listas com os seus caracteres
verificaECalcula(Palavra1, Palavra2, L1, L2),
%Utilizar as funções atribuir, de modo a criar a lista Pista
atribui2(L1, L2, PistaTemporaria, LetrasDisponiveis),
atribui1(L2, PistaTemporaria, LetrasDisponiveis, Pista), !.
/*Predicado Auxiliar -> Responsável por atribuir 2 "pontos"
LetrasDisponiveis -> Lista com as letras da palavra mistério que nao foram pontuadas
*/
atribui2([], [], [], []):-!. %Caso base -> Lista Vazia
%Caso as letras sejam iguais atribuir 2 pontos
atribui2([Letra|Resto1], [Letra|Resto2], [2|RestoPista], LetrasDisponiveis):-
!,
atribui2(Resto1, Resto2, RestoPista, LetrasDisponiveis).
%Caso as letras sejam diferentes atribuir o valor de "empty"
atribui2([Letra1|Resto1], [_|Resto2], [empty|RestoPista], [Letra1|RestoDisp]) :-
atribui2(Resto1, Resto2, RestoPista, RestoDisp).
%Predicado Auxiliar -> Responsável por atribuir 0 ou 1 "pontos"
atribui1([],[], _,[]):-!. %Caso base -> Lista Vazia
%Caso a letra já tenha sido "pontuada"
atribui1([_|RestoPalavra], [2|RestoPistas], LetrasDisponiveis, [2|RestoRes]):-
atribui1(RestoPalavra, RestoPistas, LetrasDisponiveis, RestoRes).
%Caso a letra ainda não tenha sido "pontuada"
atribui1([Letra|RestoPalavra], [empty|RestoPistas], LetrasDisponiveis, [Res|RestoRes]):-
!,
(%Verificar se a letra pertence à palavra mistério
member(Letra, LetrasDisponiveis) ->
Res = 1, %Atribuir pista
%Retirar Letra das LetrasDisponiveis
apagaElemento(Letra, LetrasDisponiveis, LetrasAtualizadas)
;
Res = 0,
%Atualizar as LetrasDisponiveis
LetrasAtualizadas = LetrasDisponiveis
),
atribui1(RestoPalavra, RestoPistas, LetrasAtualizadas, RestoRes).
/*--------------
PARTE 3
--------------*/
maratonaFilmes(ListaFilmes, ListaRestricoes, Programacao):-
%Utilizar o "setof", de modo a eliminar duplicados e ordenar as soluções
(setof(Sequencia, geraSequencia(ListaFilmes, ListaRestricoes, Sequencia), Programacao) ->
true
;%Condição: Caso o "setof" falhe, devolve uma lista vazia
Programacao = []
).
geraSequencia(ListaFilmes, ListaRestricoes, Sequencia):-
%Garantir que foram introduzidos, no máximo, 7 Filmes
length(ListaFilmes, Comprimento),
NumEmpty is 7 - Comprimento,
%Criar uma lista de tamanho "NumEmpty"
length(ListaEmpties, NumEmpty),
maplist(=('empty'), ListaEmpties), %Preencher a lista com 'empty'
%Juntar ambas as listas
append(ListaFilmes, ListaEmpties, ListaAtualizada),
%Obter todas as combinações possíveis
permutation(ListaAtualizada, Sequencia),
%Verificar se alguma permutação cumpre todas as restrições
valida_restricoes(ListaRestricoes, Sequencia).
% Predicado Auxiliar: Validar as listas de filmes conforme as restrições
valida_restricoes([], _):-!. %Caso base -> Lista Vazia
valida_restricoes([Restricao|Resto], Sequencia):-
verifica(Restricao, Sequencia), % Intrepreta as restrições
valida_restricoes(Resto, Sequencia).
%Restrições
verifica(terror(Filme), Sequencia):-
%Filmes de terror apenas nas sessões: 3, 4 e 7
nth1(Pos, Sequencia, Filme), %Procurar a posição "Pos" do Filme "Filme"
member(Pos, [3,4,7]).
verifica(soPode(Filme, Sessao), Sequencia):-
%O filme tem de estar na posição exata "Sessao"
nth1(Sessao, Sequencia, Filme).
verifica(nunca(Filme, Sessao), Sequencia):-
%O filme não pode estar na posição "Sessao"
nth1(Sessao, Sequencia, FilmeNaSessao), %Procurar o filme da sessao "Sessao"
FilmeNaSessao \== Filme.
verifica(seguido(Filme1, Filme2), Sequencia):-
%Filme2 logo após Filme1, no mesmo dia.
nth1(Sessao1, Sequencia, Filme1),
nth1(Sessao2, Sequencia, Filme2),
Sessao2 =:= Sessao1 + 1,
member(Sessao1, [1,2,3,5,6]).
verifica(naoSeguido(Filme1, Filme2), Sequencia):-
%Os filmes "Filme1" e "Filme2" não podem estar seguidos
\+ nextto(Filme1, Filme2, Sequencia),
\+ nextto(Filme2, Filme1, Sequencia).
verifica(antes(Filme1, Filme2), Sequencia):-
%O "Filme1" tem de estar num sessão anterior à do "Filme2"
nth1(Sessao1, Sequencia, Filme1),
nth1(Sessao2, Sequencia, Filme2),
Sessao1 < Sessao2.