Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 18 sur 18
  1. #1
    Rédacteur/Modérateur

    Avatar de millie
    Profil pro
    Inscrit en
    juin 2006
    Messages
    6 945
    Détails du profil
    Informations personnelles :
    Localisation : Luxembourg

    Informations forums :
    Inscription : juin 2006
    Messages : 6 945
    Points : 8 774
    Points
    8 774

    Par défaut La rubrique a besoin de vous

    Vous avez des codes sources Prolog ?
    Vous pensez que ces codes sources peuvent aider d'autres personnes ?
    Vous souhaitez partager vos codes avec des internautes ?

    Dans ce cas, participez à l'enrichissement des pages de codes sources de developpez.com et postez à la suite

    Pour chaque proposition, merci d'expliquer en quelques mots ce que fait le code, s'il nécessite des bibliothèques ou des options ou une version particulière de prolog. Si le code est trop volumineux, envoyez-moi un MP avec l'archive zippée.

    Je ne répondrai à aucune question technique en privé

  2. #2
    Rédacteur
    Avatar de pcaboche
    Homme Profil pro Pierre Caboche
    Inscrit en
    octobre 2005
    Messages
    2 505
    Détails du profil
    Informations personnelles :
    Nom : Homme Pierre Caboche
    Âge : 34
    Localisation : Singapour

    Informations forums :
    Inscription : octobre 2005
    Messages : 2 505
    Points : 7 667
    Points
    7 667

    Par défaut

    Je dirais même plus :


  3. #3
    Responsable Portail

    Avatar de khayyam90
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    janvier 2004
    Messages
    10 097
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : janvier 2004
    Messages : 10 097
    Points : 40 495
    Points
    40 495

    Par défaut

    Nous recherchons des codes écrits par les membres de developpez.com, libres de droits.

    Si vous avez écrit des codes et souhaitez les partager, ça nous intéresse.
    Responsable du Portail Developpez.
    Mes tutoriels Algo, Web, C++, PHP - Mon CV

  4. #4
    Membre émérite
    Avatar de SnakemaN
    Profil pro
    Bidouille-tout Android
    Inscrit en
    juillet 2006
    Messages
    871
    Détails du profil
    Informations personnelles :
    Âge : 30
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Bidouille-tout Android

    Informations forums :
    Inscription : juillet 2006
    Messages : 871
    Points : 965
    Points
    965

    Par défaut

    Ok je chercherai ce que j'ai et je vous le posterai

    [edit] :
    Bon je me souviens de truc assez marrant sur le crible d'Eratosthene, suite de Fibonacci et autres

    j'ai également un IDE tres sympa : PologII+
    Permettant de créer des fichier .pl, pratique pour mettre plein de predicats & co, puis de les charger dans le prompt il est compatible (Unix-Mac-Windows) avec son manuel complet fr-eng
    Je me renseigne sur sa licence pour vous poster un lien
    C'est le signe d'un fou, qu'avoir honte d'apprendre
    Ubuntu 10.04 Lucid Lynx @home
    LE guide libre Linux & Ubuntu pour tous : Simple comme Ubuntu

  5. #5
    Membre actif Avatar de je®ome
    Inscrit en
    octobre 2005
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : octobre 2005
    Messages : 285
    Points : 183
    Points
    183

    Par défaut

    Bonjour,

    J'ai débuté avec prolog il y a 8 jours, donc je ne sais pas si
    mon code source est un bon exemple de programmation en prolog.

    Il s'agit d'un générateur de labyrinthe et de recherche à l'intérieur de celui-ci.

    Le plus court chemin est trouvé avec l'algorithme de dijkstra que j'ai trouvé sur DVP et que j'ai très lègerement modifier pour l'adapter à mon problème.

    L' interface est faite avec de XPCE.
    J' admet ne pas m'être donné de la peine pour l' esthétique de celle-ci, mais elle est fonctionnelle.

    Le parcours à la main est également possible avec l'aide des flèches du clavier.
    Il faut seulement cliquer sur le labyrinthe lui-même avec le curseur pour qu'il les prenne en compte.


    C' est implanté pour du SWI-PROLOG.
    Et il ne faut rien d'autre que le code source.

    Je suis ouvert à tout commentaire.
    Fichiers attachés Fichiers attachés
    Wer nicht probiert, verliert !!

  6. #6
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut

    La programmation par contraintes.

    J'ai eu l'occasion de faire récemment un petit programme de calculs des carrés magiques d'ordre n utilisant tous les nombres de 1 à n, avec la technologie de programmation par contraintes.
    Je livre le code, toute remarque sera la bienvenue. J'ai essayé de commenter le code au mieux.

    Code :
    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
    % chargement de la bibliothèque de résolution
    % sur les entiers
    :- use_module(library('clp/bounds')).
    
    carre_magique(Vars, N) :-
    	
        % Calcul de constantes utlisées dans le prog
        Max is N*N,
        Total is N * (N * N + 1) / 2, 
        
        % declaration du tableau des variables
        % Le carré est formé de N lignes de N nombres
        length(Vars, Max),
        
        % Valeurs possibles des variables
        Vars in 1..Max,
     
      % Tous les nombres sont differents
      all_different(Vars),
    
      % Les contraintes
      
      % de lignes
      testLignes(Vars, N, Total),
      
      % de colonnes
      testColonnes(Vars, N, Total),
      
      % de diagonales
      getDiagonale1(Vars, N, Diagonale1),
      sum(Diagonale1,#=,Total),
    
      getDiagonale2(Vars, N, Diagonale2),
      sum(Diagonale2,#=,Total),
      
      % la résolution
      label(Vars),
      
      % affichage de la solution
      printVars(Vars, N).
    
    % test des lignes
    % On teste ligne par ligne
    % On débute à la ligne numérotée 1
    testLignes(Vars, N, Total) :-
    	testLigne(Vars, 1, N, Total).
    
    
    testLigne(Vars, N, Max, Total) :-
    	N =< Max, !,
    	getLigne(Vars, N, Max, Ligne),
    
            % le test proprement dit
    	sum(Ligne,#=,Total),
    
    	N1 is N + 1,
    	testLigne(Vars, N1, Max, Total).
    
    % on est arrivé au bout des lignes : succès
    testLigne(_, _, _, _).
    
    % obtention des lignes du carré magique
    % NumL est le numéro de ligne à partir de 1
    getLigne(V, NumL, MaxL, Ligne) :-
    	getLigne(V, 0, NumL, MaxL, [], Ligne).
    
    getLigne(V, N, NumL, MaxL, L1, L2) :-
    	N < MaxL, !,
    	Ind is (NumL - 1) * MaxL + N,
    	nth0(Ind, V, Num),
    	N1 is N+1,
    	getLigne(V, N1, NumL, MaxL, [Num | L1], L2).
    
    getLigne(_V, _N, _NumL, _MaxL, L, L).
    
    % test des colonnes
    % On teste colonne par colonne
    % On débute à la colonne numérotée 1
    testColonnes(Vars, N, Total) :-
    	testColonne(Vars, 1, N, Total).
    
    % testColonne(_Vars, Max, Max, _) :- !.
    
    testColonne(Vars, N, Max, Total) :-
    	N =< Max, !, 
    	getColonne(Vars, N, Max, Ligne),
    
            % le test proprement dit
    	sum(Ligne,#=,Total),
    
    	N1 is N + 1,
    	testColonne(Vars, N1, Max, Total).
    
    % on est arrivé au bout des colonnes : succès
    testColonne(_, _, _, _).
    
    % obtention de la colonne numerotée Numc
    % numérotation à partir de 1
    getColonne(V, NumC, MaxC, Colonne) :-
    	NumC1 is NumC - 1,
    	getColonne(V, 0, NumC1, MaxC, [], Colonne).
    	
    
    getColonne(V, N, NumC, MaxC, L, Colonne) :-
    	Ind is N * MaxC + NumC,
    	Ind < MaxC * MaxC,
    	!,
    	nth0(Ind, V, Num),
    	N1 is N + 1,
    	getColonne(V, N1, NumC, MaxC, [Num | L], Colonne).
    
    getColonne(_V, N, NumC, MaxC, Colonne, Colonne) :-
    	Ind is N * MaxC + NumC,
    	Ind >= MaxC * MaxC,
    	!.
    
    % C'est la diagonale "NO-SE"
    getDiagonale1(V, N, Diagonale1) :-
    	getDiagonale1(V, 0, N, [], Diagonale1).
    
    getDiagonale1(V, N, MaxL, L1, L2) :-
    	N < MaxL,
    	!,
    	Ind is N * MaxL + N,
    	nth0(Ind, V, Num),
    	N1 is N+1,
    	getDiagonale1(V, N1, MaxL, [Num | L1], L2).
    
    getDiagonale1(_V, _N, _MaxL, L, L).
    
    % C'est la diagonale "SO-NE"
    getDiagonale2(V, N, Diagonale2) :-
    	getDiagonale2(V, 0, N, [], Diagonale2).
    
    getDiagonale2(V, N, MaxL, L1, L2) :-
    	N < MaxL,
    	!,
    	Ind is (N+1) * (MaxL - 1),
    	nth0(Ind, V, Num),
    	N1 is N+1,
    	getDiagonale2(V, N1, MaxL, [Num | L1], L2).
    
    getDiagonale2(_V, _N, _MaxL, L, L).
    
    % Affichage du carré
    printVars(G, Max) :- 
    	printVars(G, 1, Max).
    
    printVars(G, N, Max) :-
    	N =< Max, !,
    	getLigne(G, N, Max, Ligne),
            % Génération de la liste des positions d'affichage
    	genereAffi(Affi, 1, Max),
    	maplist(imprimeRes ,Ligne, Affi), nl,
    	N1 is N + 1,
    	printVars(G, N1, Max).
    
    printVars(_G, _N, _Max):- nl.
    
    % pour avoir un alignement à droite des nombres :
    %    le ~*| permet un formatage sur Y caractères du nombre
    %    le ~t placé avant le ~a permet l'alignement à droite. 
    imprimeRes(X, Y) :-
    	format('~t~a~*|', [X,Y]).
    
    % Il faut générer les positions de tabulation pour l'affichage 4, 8 12, 16 ...
    genereAffi([A | Affi], N, Max) :-
    	N =< Max, !,
    	A is 4 * N,
    	N1 is N+1,
    	genereAffi(Affi, N1, Max).
    	
    genereAffi([], _, _).
    Le programme se lance par carre_magique(Vars, 4). si on veut les carrés magiques d'ordre 4.
    (Pour les avoir tous il suffit d'appuyer sur ';' au lieu de Entrée.)

    Un exemple de sortie :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    1 ?- carre_magique(Vars, 4).
      16  15   2   1
       5   3  14  12
       4  10   7  13
       9   6  11   8
    
    
    Vars = [1, 2, 15, 16, 12, 14, 3, 5, 13|...] ;
      16  15   2   1
       4   3  14  13
       5  10   7  12
       9   6  11   8
    
    
    Vars = [1, 2, 15, 16, 13, 14, 3, 4, 12|...]
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

  7. #7
    Alp
    Alp est déconnecté
    Expert Confirmé Sénior
    Avatar de Alp
    Homme Profil pro
    Inscrit en
    juin 2005
    Messages
    8 584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : juin 2005
    Messages : 8 584
    Points : 10 421
    Points
    10 421

    Par défaut

    J'ai écrit un code qui donne la longueur d'une liste... Il vaut ce qu'il vaut, et je crois que cela existe déjà, mais bon si ça peut en aider certains à comprendre. (il est peut-être moyennement juste d'ailleurs, contactez moi si c'est le cas pour que je corrige)

    Nombre d'éléments d'une liste

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    % Une liste vide a 0 éléments
    size([],L) :-
    	L is 0,!.
    
    % La taille d'une liste quelconque est 1 + la taille de cette même liste à laquelle 
    % on a retiré le premier élément
    size([_H|Q],L) :-
    	size(Q,L1),
    	L is 1 + L1,!.
    Utilisation :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1 ?- size([],L).
    L = 0.
    
    2 ?- size([1],L).
    L = 1.
    
    3 ?- size([2,2,3],L).
    L = 3.
    
    4 ?- size([2,2,3,3,4,5,6],L).
    L = 7.

  8. #8
    Alp
    Alp est déconnecté
    Expert Confirmé Sénior
    Avatar de Alp
    Homme Profil pro
    Inscrit en
    juin 2005
    Messages
    8 584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : juin 2005
    Messages : 8 584
    Points : 10 421
    Points
    10 421

    Par défaut

    Calculer la somme des éléments d'une liste de nombres

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    % La somme des élément d'une liste vide est 0
    list_sum([],Sum) :-
    	Sum is 0,!.
    	
    % La somme des éléments d'une liste est le premier élément auquel on additionne
    % la somme des éléments de la même liste sans le premier élément
    list_sum([H|Q],Sum) :-
    	list_sum(Q, Sum1),
    	Sum is H+Sum1,!.
    Utilisation :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    1 ?- list_sum([],S).
    S = 0.
    
    2 ?- list_sum([1],S).
    S = 1.
    
    3 ?- list_sum([2],S).
    S = 2.
    
    4 ?- list_sum([1,2],S).
    S = 3.
    
    5 ?- list_sum([10,20],S).
    S = 30.
    
    6 ?- list_sum([1,2,3,4,5,6,7,8,9,10],S).
    S = 55.

  9. #9
    Alp
    Alp est déconnecté
    Expert Confirmé Sénior
    Avatar de Alp
    Homme Profil pro
    Inscrit en
    juin 2005
    Messages
    8 584
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 25
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : juin 2005
    Messages : 8 584
    Points : 10 421
    Points
    10 421

    Par défaut

    Trouver l'index d'un élément dans une liste

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    % T : the element we search
    % I : the index of the element
    
    index_of(E, L, I) :-
      index_of(E, L, 0, I).
    
    index_of(E,[E|_], N, N) :- !.
    index_of(E,[_|Q], N, I) :- 
      !,
      N1 is N+1,
      index_of(E, Q, N1, I).
    index_of(_, [] , _, -1) :- !.
    (merci pcaboche pour la petit correction)

  10. #10
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut Un mini serveur de calcul en Prolog et ses clients

    Suite à une discussion avec Alp, je me suis amusé à écrire un mini serveur de calcul en Prolog, c'est en fait un évaluateur d'expressions arithmétiques !

    Le serveur : le code est fortement inspiré de celui proposé par Alp ici. J'ai rajouté le prédicat calcul, un log sur la fenêtre du serveur et une petite gestion d'erreur à l'aide du prédicat catch/3.
    Code :
    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
    :- use_module(library(socket)).
    init :-
    	create_server(5000).
     
    create_server(Port) :-
    	tcp_socket(Socket),
    	tcp_bind(Socket,Port),
    	tcp_listen(Socket,5),
    	tcp_open_socket(Socket,AcceptFd,_),
    	server_loop(AcceptFd).
    
    
    server_loop(AcceptFd) :-
    	repeat,
    	tcp_accept(AcceptFd,Socket2,_),
    	tcp_open_socket(Socket2,In,Out),
            read_line_to_codes(In, Codes),
            close(In),
    	catch(calcule(Codes, A),
    	      A, 
    	      format('Erreur de saisie ~w~n', [A])),
            format(Out, '~w~n', [A]),
    	close(Out),
    	Codes = [].
    
    
    calcule(Codes, A) :-
    	atom_codes(Atom, Codes),
            term_to_atom(Expr, Atom),
    	B is Expr,
    	format('Calcul demandé : ~s = ~w~n', [Codes, B]),
    	sformat(A, '~w~n', [ B ]).
    Un client "en mode console" :
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    create_client(Host, Port) :-
    	% boucle de connexion
    	repeat,
            tcp_socket(Socket),
            tcp_connect(Socket, Host:Port),
            tcp_open_socket(Socket, ReadFd, WriteFd),
    	write('Tapez quelque chose, (0 pour cesser) '),
    	read_line_to_codes(user_input, X),
    	format(WriteFd, '~s~n', [X]),
    	flush_output(WriteFd),
    	read_line_to_codes(ReadFd, Lst),
    	string_to_list(Command, Lst),
    	writeln(Command),
            close(ReadFd),
            close(WriteFd),
    	string_to_list("0", X).
    
    calcul :-
    	create_client('localhost', 5000).
    et un client en mode graphique avec XPCE :
    Code :
    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
    dialog(client_d,
           [ object        :=
    	   Client_d,
    	 parts         :=
    	   [ Client_d  := dialog('Client du serveur de calcul'),
    	     Calcul_Item := text_item(text_item),
    	     Resultat  := label(name, ''),
    	     Button1   := button('Calcul'),
    	     Button2   := button('Terminé')
    	   ],
    	 modifications :=
    	   [ Calcul_Item := [ label := 'Tapez votre calcul : '
    			  ]
    	   ],
    	 layout        :=
    	   [ area(Calcul_Item,
    		  area(12, 18, 319, 24)),
    	     area(Resultat,
    		  area(18, 67, 184, 18)),
    	     area(Button1,
    		  area(364, 16, 80, 24)),
    	     area(Button2,
    		  area(367, 62, 80, 24))
    	   ],
    	 behaviour     :=
    	   [ Button1 := [ message := message(@prolog,
    					    lance_calcul,
    					    Calcul_Item?selection,
    					    Resultat)
    		       ],
    	     Button2 := [
    			message := message(Client_d, destroy)
    		       ]
    	     
    	   ]
    	 
           ]).
    
    
    
    lance_calcul(Expr, Resultat) :-
            tcp_socket(Socket),
    	Host='localhost', Port=5000,
            tcp_connect(Socket, Host:Port),
            tcp_open_socket(Socket, ReadFd, WriteFd),
    	format(WriteFd, '~w~n', [Expr]),
    	flush_output(WriteFd),
    	read_line_to_codes(ReadFd, Lst),
    	string_to_list(Res, Lst),
            close(ReadFd),
            close(WriteFd),
    	sformat(Str, '~w = ~s', [Expr, Res]),
    	send(Resultat, selection, Str).
    	
    
    xpce_calcul :-
           make_dialog(D, 'client_d'),
           send(D,open).
    Des renseignements et des détails sur les diffférents prédicats de gestion des sockets peuvent être trouvés ici.

    Ce que ça donne :
    Réussite :



    echec :

    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

  11. #11
    Rédacteur
    Avatar de SpiceGuid
    Homme Profil pro Damien Guichard
    Inscrit en
    juin 2007
    Messages
    1 574
    Détails du profil
    Informations personnelles :
    Nom : Homme Damien Guichard
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : juin 2007
    Messages : 1 574
    Points : 2 449
    Points
    2 449

    Par défaut

    Le programme se lance par carre_magique(Vars, 4). si on veut les carrés magiques d'ordre 4.
    et je peux avoir les cubes magiques de côté 4 avec somme magique sur les 2 diagonales des 6 faces ainsi que sur les 4 diagonales du cube ?
    Du même auteur: le cours OCaml, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

  12. #12
    Invité de passage
    Inscrit en
    février 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : février 2008
    Messages : 8
    Points : 2
    Points
    2

    Par défaut rubick cube

    et je peux avoir les cubes magiques de côté 4 avec somme magique sur les 2 diagonales des 6 faces ainsi que sur les 4 diagonales du cube ?
    Un cube magique de cote 3 c'est pas un rubick cube

  13. #13
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut Les chaînes de caractères en Prolog

    Les chaînes de caractères en Prolog sont toujours difficiles à traiter pour un débutant, le comportement de Prolog est déconcertant au premier abord.

    Une chaîne de caractères en Prolog est tranformée en interne en une liste de codes ASCI.
    20 ?- L = "Hello World !".
    L = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33] ;
    false.
    .

    L'affichage de cette chaine de caractères sous une forme lisible s'obtient à l'aide du prédicat string_to_list/2:
    Code :
    1
    2
    3
    4
    5
    test :-
    	L = "Hello World !",
    	string_to_list(L1, L),
    	writeln(L),
    	writeln(L1).
    Sortie
    22 ?- test.
    [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]
    Hello World !
    true.
    On peut aussi transformer cette chaîne en un atome à l'aide de atom_codes/2.
    Code :
    1
    2
    3
    4
    5
    test1 :-
    	L = "Hello World !",
    	atom_codes(L1, L),
    	writeln(L),
    	writeln(L1).
    Sortie :
    23 ?- test1.
    [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]
    Hello World !
    true.
    On croirait obtenir la même chose, mais non !
    La différence est visible en ligne de commande :
    24 ?- string_to_list(L, [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]).
    L = "Hello World !" ;
    false.

    25 ?- atom_codes(L, [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]).
    L = 'Hello World !' ;
    false
    C'est le prédicat writeln/1 qui les affiche sous la même forme.

    Le type string représente les chaînes de caractères en Prolog.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    test2 :-
    	L = "Hello World !",
    	string_to_list(S, L),
    	atom_codes(A, L),
    	write('L = '), writeln(L),
    	(   string(L) -> writeln('L est une string'); writeln('L n''est pas une string')), nl,
    	write('S = '), writeln(LS),
    	(   string(S) -> writeln('S est une string'); writeln('S n''est pas une string')), nl,
    	write('A = '), writeln(A),
    	(   string(A) -> writeln('A est une string'); writeln('A n''est pas une string')), nl.
    Sortie :
    35 ?- test2.
    L = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 32, 33]
    L n'est pas une string

    S = Hello World !
    S est une string

    A = Hello World !
    A n'est pas une string

    true.
    La lecture au clavier.

    Prolog utilise un prédicat standart de lecture de l'entrée au clavier read/1. La variable X est transformée en atom.
    Code :
    1
    2
    3
    4
    5
    test3 :-
    	read(X),
    	writeln(X),
    	(   string(X) -> writeln('X est une string'); writeln('X n''est pas une string')), nl,
    	(   atom(X) -> writeln('X est un atom'); writeln('X n''est pas une atom')), nl.
    Sortie :
    44 ?- test3.
    |: salut.
    salut
    X n'est pas une string

    X est un atom

    true.
    Le problème de ce prédicat est qu'il est limité à la saisie d'un seul mot.
    Pour saisir une phrase complète, il faut utiliser le prédicat read_line_to_codes/2, qui comme son nom l'indique fournit une liste de codes ASCII. Pour tranformer cette liste en un objet imprimable, il suffit d'utiliser soit le prédicat atom_codes/2 soit le prédicat string_to_list/2.
    A noter qu'on n'est plus obligé de terminer la saisie par un point !

    Code :
    1
    2
    3
    4
    5
    test4 :-
    	read_line_to_codes(user_input, X),
    	writeln(X),
    	string_to_list(S, X),
    	writeln(S).
    Sortie :
    47 ?- test4.
    |: Bonjour tout le monde !
    [66, 111, 110, 106, 111, 117, 114, 32, 116, 111, 117, 116, 32, 108, 101, 32, 109, 111, 110, 100, 101, 32, 33]
    Bonjour tout le monde !
    true.
    Pour terminer, je vous propose ce petit code qui permet de parser une chaîne saisie au clavier pour en extraire les mots sous forme d'atomes.
    Le code
    Code :
    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
    % split(+Liste_des_Separateur, Code, +Liste_a_separer, -Liste_resultat)
    % Prédicat de fractionnement d'une liste en sous listes
    % Ces sous_listes sont séparées dans la liste initiale
    % par des séparateurs fournis en argument
    % L'argument Code permet de savoir si le caractère précédent
    % celui étudié était un séparateur ou pas.
    % la liste résultat est construite en retour de la récursion
    % il faut d'abord parcourir toute la liste
    
    % On atteint la fin de la liste
    % On fait le retour de récursion avec le code 0
    split(_V, 0, [], []).
    
    % ici on lit le séparateur
    % on le saute simplement en signalant
    % qu'on vient de le lire (Code = 0)
    split(LSep, 0, [V | T],L) :-
    	member(V, LSep),
    	!,
    	split(LSep,  _C, T, L).
    
    % ici on lit un caractère valide
    % la consuite a tenir dépend du code C
    split(LSep, 1, [H | T], L1) :-
    	split(LSep, C, T, L),
    	etudie_code(C, H, L, L1).
    
    
    % Le code est 0 ce qui signfie
    % qu'on doit commencerer une nouvelle liste
    etudie_code(0, H, L, [[H]|L]) :- !.
    
    % Le code est 1 ce qui signfie
    % qu'on doit continuer une liste en construction
    etudie_code(1, H, [T|L], [[H|T]|L]).
     
    
    parser :- 
    	read_line_to_codes(user_input, L0),
    	split(" ;.,?!-", _, L0, L),
    	maplist(atom_codes, L1, L),
    	maplist(writeln, L1).
    Sortie :
    48 ?- parser.
    |: Bonjour tout le monde. Comment allez-vous ? Moi, ça va bien !
    Bonjour
    tout
    le
    monde
    Comment
    allez
    vous
    Moi
    ça
    va
    bien
    true.
    Complément.

    J'ai codé un split_dl utilisant le principe des différences de listes, plus besoin de parcourir toute la liste, le résultat est construit au parcours de gauche à droite.

    Code :
    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
    split_dl([H|T], Sep, MotEnCours, ListeEnCours, ListeFinale) :-
    	\+member(H, Sep) ->
    	append_dl(MotEnCours, [H|R]-R, Mot1), 
    	split_dl(T, Sep, Mot1, ListeEnCours, ListeFinale);
    	(  
           % Extraction de la liste classique à partir de la D.L. 
    	MotEnCours = M - [], 
    	    (	M \= [] ->
    	append_dl(ListeEnCours, [M|S]-S, Liste1),
    	split_dl(T, Sep, U-U, Liste1, ListeFinale); 
    	split_dl(T, Sep, U-U, ListeEnCours, ListeFinale))).
    
    
    split_dl([], _Sep, MotEnCours, ListeEnCours, ListeFinale) :-
    	MotEnCours = M - [], 
    	(M \= [] -> append_dl(ListeEnCours, [M|S]-S, ListeFinale); 
    	ListeFinale = ListeEnCours).
    
    % La concaténation en temps constant (1 inférence)
    % un des principaux avantages des D.L.
    append_dl(X1-X2, X2-X3, X1-X3).
    
    % lancement du programme
    test :-
        % la liste vide est initialisée par la D.L. "X-X"
        % L1-[] pour obtenir directement la liste résultat
        split_dl(L, "!:;,?. -", T-T, H-H, L1-[]).
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

  14. #14
    Membre actif
    Étudiant
    Inscrit en
    février 2005
    Messages
    263
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : février 2005
    Messages : 263
    Points : 197
    Points
    197

    Par défaut

    Voici une série de prédicat permettant de représenter des expressions mathématique. De plus amples informations sont disponible en début de chaque prédicat



    Code :
    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
    %Une expression est représentée comme un arbre. Le noeud contient l'opérateur
    %et les branches sont les opérandes
    %Les arbres sont représentés de la manière suivante:
    %[noeud, Liste-Sous-arbre] et une feuille est un nombre ou une variable, les
    % variables étant représentée grâce à des chaines de caractères
    
    %le predicat operator(Op) est vrai si Op est un opérateur dont on peut
    %calculer le résultat via evaluateExpression
    operator('*').
    operator('/').
    operator('-').
    operator('+').
    operator('sin').
    operator('cos').
    operator('sqrt').
    operator('ln').
    operator('log').
    operator('power').
    
    %le prédicat findValue(X,Val,Y) est vrai si dans la liste des binôme Val, il
    %existe un binôme [X,Y]
    findValue(X,[[X,Y]|_],Y):-!.
    findValue(X,[[Z,_]|Vals],Y):- Z\=X, findValue(X,Vals,Y).
    
    %le prédicat createExpression(Op,Or,Expr) est vrai si Expr est l'expression
    %ayant pour opérateur principal Op et Or soit la liste des opérandes.
    createExpression(Operator,Operand,[Operator,Operand]):-
    	operator(Operator),
    	isList(Operand).
    
    
    %Grâce au prédicat suivant, il est possible de faire une composition
    %d'expression. En effet, il suffit de remplacer les variables d'une expression
    %par une autre expression.
    %Exemple:
    %?- F = ['+', ['x','x']], G = ['*', ['x','x']], changeExpr(G,'x',F,B).
    %
    %F = [+, [x, x]],
    %G = [*, [x, x]],
    %B = [*, [[+, [x, x]], [+, [x, x]]]]
    
    
    %le prédicat changeExpr(+Expr1, +A, +B, -Expr2) est vrai si l'expression 2
    %est l'expression 1 dont on a changé les éléménts A par B.
    changeExpr([],_,_,[]).
    changeExpr([X|Xs],X,Y,[Y|Zs]):- !, changeExpr(Xs,X,Y,Zs).
    changeExpr([X|Xs],A,B,[Z|Zs]):- is_list(X),!,
    	changeExpr(X,A,B,Z), changeExpr(Xs,A,B,Zs).
    changeExpr([X|Xs],A,B,[X|Zs]):- changeExpr(Xs,A,B,Zs).
    
    
    %le prédicat evaluateExpression(Expr,Values,Result) est vrai si Expr est une
    %expression, values soit une liste de binomes (A,B) ou A représente une
    %variable et B la valeur associée à cette variable et Result, le résultat
    %de l'expression en ayant substitué les variables par leurs valeurs
    %
    %il est possible de donner pour valeur d'une variable une autre expression,
    %mais il faut faire attention, car si l'expression 1 et 2 dépendent toutes
    %deux d'une variable portant le même nom, il sera impossible de trouver
    %la valeur pour cette expression
    evaluateExpression(X,_,X):-number(X),!.
    evaluateExpression('pi',_,X):-!, X is pi.
    evaluateExpression(X,Val,Y):-
    	\+ is_list(X), findValue(X,Val,Tmp),
    	evaluateExpression(Tmp,Val,Y).
    evaluateExpression(['*',[X]],Val,Res):-!,
    	evaluateExpression(X,Val,Res).
    evaluateExpression(['*',[X|Xs]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	evaluateExpression(['*',Xs],Val,T2),
    	Res is T1*T2.
    evaluateExpression(['/',[A,B]],Val,Res):-
    	evaluateExpression(A,Val,T1),
    	evaluateExpression(B,Val,T2),
    	Res is T1/T2.
    evaluateExpression(['+',[X]],Val,Res):-!,
    	evaluateExpression(X,Val,Res).
    evaluateExpression(['+',[X|Xs]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	evaluateExpression(['+',Xs],Val,T2),
    	Res is T1+T2.
    evaluateExpression(['-',[X,Y]],Val,Res):-!,
    	evaluateExpression(X,Val,T1),
    	evaluateExpression(Y,Val,T2),
    	Res is T1-T2.
    evaluateExpression(['-',[X|Xs]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	evaluateExpression(['-',Xs],Val,T2),
    	Res is T1-T2.
    evaluateExpression(['sin',[X]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	Res is sin(T1).
    evaluateExpression(['cos',[X]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	Res is cos(T1).
    evaluateExpression(['sqrt',[X]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	Res is sqrt(T1).
    evaluateExpression(['ln',[X]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	Res is log(T1).
    evaluateExpression(['log',[X]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	Res is log10(T1).
    evaluateExpression(['power',[X,Y]],Val,Res):-
    	evaluateExpression(X,Val,T1),
    	evaluateExpression(Y,Val,T2),
    	Res is T1**T2.
    
    %le prédicat printExpression(+Expression) est vrai si Expression est une
    %expression et qu'elle soit imprimée sur la sortie standard
    printExpression(X):- \+ is_list(X),!,write(X).
    printExpression(['*',[X,Y]]):-!,
    	write('('), printExpression(X), write('*'),
    	printExpression(Y), write(')').
    printExpression(['/',[A,B]]):-!,
    	write('('), printExpression(A),
    	write('/'),printExpression(B),write(')').
    printExpression(['+',[X,Xs]]):-!,
    	write('('), printExpression(X), write('+'),
    	printExpression(Xs), write(')').	
    printExpression(['-',[X,Y]]):- !,
    	write('('), printExpression(X), write('-'),
    	printExpression(Y), write(')').
    printExpression(['sin',[X]]):-!,
    	write('sin('),
    	printExpression(X),
    	write(')').
    printExpression(['cos',[X]]):-!,
    	write('cos('),
    	printExpression(X),
    	write(')').
    printExpression(['sqrt',[X]]):-!,
    	write('sqrt('),
    	printExpression(X),
    	write(')').
    printExpression(['ln',[X]]):-!,
    	write('log('),
    	printExpression(X),
    	write(')').
    printExpression(['log',[X]]):-!,
    	write('(log('),
    	printExpression(X),
    	write(')/log(10))').
    printExpression(['power',[X,Y]]):-!,
    	write('('),
    	printExpression(X),
    	write('**'),
    	printExpression(Y),
    	write(')').

  15. #15
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut

    Suite a une discussion dans le forum algo sur le parours du cavalier, je livre deux codes , l'un en Prolog "pur", l'autre utilisant la programmation par contraintes.
    Le code en Prolog pur :
    Code :
    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
    % N est le nombre de lignes de l'échiquier
    test(N) :-
    	% max est le nombre de cases
    	Max is N * N,
    	% on crée l'échiquier, une simple liste 
    	% dont les éléments ne sont pas initialisés
    	length(L, Max),
    	% on lance la recherche
    	cavalier(N, 0, Max, 0, 0, L),
    	affiche(N, 0, L).
    
    % cavalier(NbCol, Coup, Max, Lig, Col, L),
    % NbCol est le nombre de colonnes par ligne
    % Coup est le numéro du déplacement en cours d'étude
    % Max est le noimbre maximum de déplacements
    % Lig/ Col : la position courant du cavalier
    % L est la liste "échiquier"
    
    % ici on est arrive 
    cavalier(_, Max, Max, _, _, _) :- !.
    
    cavalier(NbCol, N, MaxN, Lg, Cl, L) :-
    	% On s'assure d'abord que la position est valide
    	Lg >= 0, Cl >= 0, Lg < NbCol, Cl < NbCol,
    	% On calcule la position de la case sur l'échiquer
    	Pos is Lg * NbCol + Cl,
    	% on calcule le numéro du coup
    	N1 is N+1,
    	% on met dans la case le numéro du coup
    	% spécificité Prolog, si la case est déjà occupée il y a echec
    	% donc backtrack ici
    	nth0(Pos, L, N1),
    	% on calcule les différentes cases accessibles
    	LgM1 is Lg - 1, LgM2 is Lg - 2, LgP1 is Lg + 1, LgP2 is Lg + 2,
    	ClM1 is Cl - 1, ClM2 is Cl - 2, ClP1 is Cl + 1, ClP2 is Cl + 2,
    	% et on essaye les cases suivantes
    	% le ; permet, s'il y a echec d'une recherche, 
    	% de continuer avec la suivante
    	(
    	cavalier(NbCol, N1, MaxN, LgP1, ClM2, L);
    	cavalier(NbCol, N1, MaxN, LgP2, ClM1, L);
    	cavalier(NbCol, N1, MaxN, LgP2, ClP1, L);
    	cavalier(NbCol, N1, MaxN, LgP1, ClP2, L);
    	cavalier(NbCol, N1, MaxN, LgM1, ClM2, L);
    	cavalier(NbCol, N1, MaxN, LgM2, ClM1, L);
    	cavalier(NbCol, N1, MaxN, LgM2, ClP1, L);
    	cavalier(NbCol, N1, MaxN, LgM1, ClP2, L)
    	).
    
    % affichage de l'échiquier
    affiche(_, _, []).
    affiche(N, N, L) :-
    	nl,
    	affiche(N, 0, L).
    
    affiche(N, M, [H | T]) :-
    	writef('%3r', [H]),
    	M1 is M + 1,
    	affiche(N, M1, T).
    Il est relativement lent, 11 minutes pour trouver un chemin sur l'échiquier 8X8 !

    Le code en PLC du parcours "de l'escargot" plutôt étant donné sa lenteur, 40 minutes pour un échiquier 6 X 6 !
    Code :
    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
    :- use_module(library(clpfd)).
    
    cavalier(N) :-
    	% l'echiquier est carre
    	Max is N * N,
    	% l'échiquier est représenté par une liste de cases
    	length(L, Max),
    	% la numérotation des coups
    	numlist(1, Max, NL),
    	N1 is N - 1,
    	% initialisation l'échiquier
    	% LC contient la liste des positions des cases
    	maplist(init(N1), NL, L, LC),
    
    	% toutes les cases sont différentes
    	all_different(LC),
    
    	% Initialisation des contraintes de mouvement
    	init_list(L),
    
    	% on lance la recherche de solution
    	time(my_labeling([ff], LC)),
    
    	% on trie la liste pour permettre l'affichage en mode console
    	msort(L, LS),
    	affiche(LS, N, 0).
    
    
    my_labeling(Options, LV) :-
    	labeling(Options, LV).
    
    
    % initialisation des contraintes du mouvement du cavalier
    init_list([(_,_,_)]).
    
    % un mouvement du cavalier est un déplacement entre deux cases
    init_list([(L1, C1, _), (L2, C2, _) | T]) :-
    	% séparées par 1 ligne et deux colonnes
    	(   	abs(L1-L2) #= 1 #/\ abs(C1-C2) #= 2)
    	#\/
    	% ou séparées par 2 lignes et 1 colonne
    	(   	abs(L1-L2) #= 2 #/\ abs(C1-C2) #= 1),
    
    	init_list([(L2, C2, _) | T]).
    
    % initialisation de l'échiquier : tuple (Ligne, Colonne, Num_Coup)
    % c'est sur la liste des positions R qu'aura lieu le "labeling"
    init(N, Val, (L, C, Val), R) :-
    	L in 0..N,
    	C in 0..N,
    	R #= L * (N+1) + C.
    
    % affichage de la solution en mode console
    affiche([], _ , _).
    
    affiche(L, N, N) :-
    	nl,
    	affiche(L, N, 0).
    
    affiche([(_, _, V) | T], N, N1) :-
    	N1 < N,
    	writef('%3r', [V]),
    	N2 is N1+1,
    	affiche(T, N, N2).
    Je vais essayer de l'améliorer quand même !

    [EDIT] Le programme est amélioré même s'il y a encore beaucoup à faire, on passe de 40 minutes à moins de 12 minutes !
    Code :
    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
    cavalier(N, Options) :-
    	cavalier_contraintes(N, Options, L),
    	% on trie la liste pour permettre l'affichage en mode console
    	msort(L, LS),
    	affiche(LS, N, 0).
    
    % N nombres de cases d'un coté de l'échiquier
    % Options, les options pour le labeling
    % L la liste des cases de l'échiquier avec le numéro du coup
    cavalier_contraintes(N, Options, L) :-
    	% l'echiquier est carre
    	Max is N * N,
    	% l'échiquier est représenté par une liste de cases
    	length(L, Max),
    	% la numérotation des coups
    	numlist(1, Max, NL),
    	N1 is N - 1,
    	% initialisation l'échiquier
    	% LC contient la liste des positions des cases
    	maplist(init(N1), NL, L, LC),
    
    	% toutes les cases sont différentes
    	all_different(LC),
    
    	% Il ne sert à rien de "labeller" la liste LC
    	% il faut simplement s'assurer que tous les nombres sont différents
    
    	% Initialisation des contraintes de mouvement
    	init_list(Options, L).
    
    
    
    % initialisation des contraintes du mouvement du cavalier
    init_list(_, [(_,_,_)]).
    
    % un mouvement du cavalier est un déplacement entre deux cases
    init_list(Options, [(L1, C1, _), (L2, C2, _) | T]) :-
    	% séparées par 1 ligne et deux colonnes
    	(   	abs(L1-L2) #= 1 #/\ abs(C1-C2) #= 2)
    	#\/
    	% ou séparées par 2 lignes et 1 colonne
    	(   	abs(L1-L2) #= 2 #/\ abs(C1-C2) #= 1),
    
    	% cette ligne est nouvelle
    	labeling(Options, [L1, C1, L2, C2]),
    	init_list(Options, [(L2, C2, _) | T]).
    
    % initialisation de l'échiquier : tuple (Ligne, Colonne, Num_Coup)
    % pour s'assurer que toutes les cases seront occupées
    init(N, Val, (L, C, Val), R) :-
    	[L, C] ins 0..N,
    	R #= L * (N+1) + C.
    On le lance avec les options de labeling [enum].
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

  16. #16
    Invité régulier
    Inscrit en
    mars 2004
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : mars 2004
    Messages : 7
    Points : 6
    Points
    6

    Par défaut Le Compte est bon en swi-prolog

    Pour le fun: un petit programme pour le jeu "le compte est bon":

    Code :
    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
    % Auteur:  Thierry Bertrand
    % Date: 02/06/2011
    %
    %
    % lancement : resoud([a,b,c,d,e,f], But).
    % exemple:    resoud([3,75,2,4,1,1],888).
    %                  [[75,-,2,=,73],[1,+,73,=,74],[3,*,74,=,222],[4,*,222,=,888]]
    % NB: une autre solution: 6 * 100 = 600,
    %      8 * 10 = 80,
    %     600 + 80 = 680,
    %     680 + 3 = 683
    %
    /*
     6 ?- resoud([3,100,8,8,10,6],683).
    [[6,+,10,=,16],[100,-,16,=,84],[8,*,84,=,672],[3,+,672,=,675],[8,+,675,=,683]]
    true.
    
    7 ?- resoud([3,100,8,5,10,6],683).
    [[100,+,3,=,103],[10,+,103,=,113],[6,*,113,=,678],[5,+,678,=,683]]
    true.
    
    8 ?- resoud([3,100,8,1,10,6],683).
    [[10,-,1,=,9],[6,+,9,=,15],[100,-,15,=,85],[8,*,85,=,680],[3,+,680,=,683]]
    true.
    
    */
    
    :- dynamic(soluce/2).   %  pour stocker la meilleure : total, liste
    
    meilleure(But, Solution, Detail) :- soluce(S, _),
                                        Diff1 is abs(S - But),
                                        Diff2 is abs(Solution - But),
                                        meilleure(Diff1, Diff2, Solution, Detail).
    meilleure(Ref, New, Sol, Detail) :- New < Ref,
                                        retractall(soluce(_,_)),
                                        assert(soluce(Sol, Detail)).
    meilleure(_, _, _, _).
    
    renardeau([Total | _], But, Z, Z) :- Total = But, !.
    renardeau(L, But, Z, R) :- testPlus(L, But, Z, R), !.
    renardeau(L, But, Z, R) :- testMoins(L, But, Z, R), !.
    renardeau(L, But, Z, R) :- testMult(L, But, Z, R), !.
    renardeau(L, But, Z, R) :- testDiv(L, But, Z, R), !.
    renardeau(_,_,_,_,_) :- !, fail .
    
    
    testPlus([A, B | Qs], But, Z, Res) :- Calcul is A + B,
                                   meilleure(But, Calcul, [[B , '+' , A  , '=' , Calcul] | Z]),
                                   renardeau([Calcul | Qs ] , But, [[B , '+' , A  , '=' , Calcul] | Z], Res).
    
    
    testMoins([A, B | Qs ],  But, Z, Res) :- B > A,
                                   Calcul is B - A,
                                   meilleure(But, Calcul, [[B , '-' , A  , '=' , Calcul] | Z]),
                                   renardeau([ Calcul | Qs ] , But, [[ B , '-' , A, '=', Calcul] | Z], Res).
    testMoins([A, B | Qs ],  But, Z, Res) :- A > B,
                                   Calcul is A - B,
                                   meilleure(But, Calcul, [[A , '-' , B  , '=' , Calcul] | Z]),
                                   renardeau([ Calcul | Qs ] , But, [[ A , '-' , B, '=', Calcul] | Z], Res).
    
    
    testMult([A, B | Qs], But, Z, Res) :- Calcul is B * A,
                                   meilleure(But, Calcul, [[B , '*' , A  , '=' , Calcul] | Z]),
                                   renardeau([Calcul | Qs ] , But, [[B , '*' , A, '=', Calcul] | Z], Res).
    
    
    testDiv([A, B | Qs ], But, Z, Res) :- A \= 0, B >= A, Calcul is B / A,
                                   integer(Calcul),
                                   meilleure(But, Calcul, [[B , '/' , A  , '=' , Calcul] | Z]),
                                   renardeau([ Calcul |  Qs  ] , But, [[B , '/' , A, '=', Calcul] | Z], Res).
    testDiv([A, B | Qs ], But, Z, Res) :- B \= 0, A >= B, Calcul is A / B,
                                   integer(Calcul),
                                   meilleure(But, Calcul, [[A , '/' , B  , '=' , Calcul] | Z]),
                                   renardeau([ Calcul |  Qs  ] , But, [[A , '/' , B, '=', Calcul] | Z], Res).
    
    resoud(L, But) :- retractall(soluce(_,_)),
                      assert(soluce(9999, [])),
                      select(A, L, L1),
                      select(B, L1, L2),
                      select(C, L2, L3),
                      select(D, L3, L4),
                      select(E, L4, L5),
                      select(F, L5, _),
                      renardeau([A, B, C, D, E, F, 0], But, [], Tempo),!,
                      reverse(Tempo, Resultat),
                      writeln('le compte est bon ...'),
                      edite(Resultat).
    resoud(_ , _) :- soluce(Total, Sol),
                     write('meilleur total possible:'),
                     writeln(Total),
                     reverse(Sol, Resultat),
                     edite(Resultat).
    
    edite([]).
    edite([Calcul | Reste]) :- editeOp(Calcul), edite(Reste).
    editeOp([ A , Operateur , B , _, Resultat]) :- write(A),
                                                   write(' '),
                                                   write(Operateur),
                                                   write(' '),
                                                   write(B),
                                                   write(' = '),
                                                   writeln(Resultat).
    l'essentiel dans les lignes 38 à 92, le reste c'est pour faire beau ...

  17. #17
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut

    Petit retour sur le probleme du cavalier.
    J'ai utilisé l'algo de Warnsdorff et l'amélioration est spectaculaire : 0,026 s pour l'échiquier de 64 cases, 0,25s pour un echiquier 20 X 20 !!!

    Code :
    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
    % N est le nombre de lignes de l'échiquier
    test(N) :-
    	% max est le nombre de cases
    	Max is N * N,
    	% on crée l'échiquier, une simple liste 
    	% dont les éléments ne sont pas initialisés
    	length(L, Max),
    	% on lance la recherche
    	cavalier(N, 0, Max, 0, 0, L),
    	affiche(N, 0, L).
    
    % cavalier(NbCol, Coup, Max, Lig, Col, L),
    % NbCol est le nombre de colonnes par ligne
    % Coup est le numéro du déplacement en cours d'étude
    % Max est le noimbre maximum de déplacements
    % Lig/ Col : la position courant du cavalier
    % L est la liste "échiquier"
    
    % ici on est arrive 
    cavalier(_, Max, Max, _, _, _) :- !.
    
    cavalier(NbCol, N, MaxN, Lg, Cl, L) :-
    	% On s'assure d'abord que la position est valide
    	Lg >= 0, Cl >= 0, Lg < NbCol, Cl < NbCol,
    	% On calcule la position de la case sur l'échiquer
    	Pos is Lg * NbCol + Cl,
    	% on calcule le numéro du coup
    	N1 is N+1,
    	% on met dans la case le numéro du coup
    	% spécificité Prolog, si la case est déjà occupée il y a echec
    	% donc backtrack ici
    	nth0(Pos, L, N1),
    	% on calcule les différentes cases accessibles
    	LgM1 is Lg - 1, LgM2 is Lg - 2, LgP1 is Lg + 1, LgP2 is Lg + 2,
    	ClM1 is Cl - 1, ClM2 is Cl - 2, ClP1 is Cl + 1, ClP2 is Cl + 2,
    
    	% on selectionne le meilleur coup possible
    	% celui qui offre le moins de possibilités au coup suivant
    	maplist(best_move(NbCol, L),
    		[(LgP1, ClM2), (LgP2, ClM1), (LgP2, ClP1),(LgP1, ClP2),
    		 (LgM1, ClM2), (LgM2, ClM1), (LgM2, ClP1),(LgM1, ClP2)],
    		R),
    	sort(R, RS),
    	pairs_values(RS, Moves),
    
    	move(NbCol, N1, MaxN, Moves, L).
    
    move(NbCol, N1, MaxN, [(Lg, Cl) | R], L) :-
    	knight(NbCol, N1, MaxN, Lg, Cl, L);
    	move(NbCol, N1, MaxN,  R, L).
    
    %% Un coup impossible est note 1000
    best_move(NbCol, _L, (Lg, Cl), 1000-(Lg, Cl)) :-
    	(   Lg < 0 ; Cl < 0; Lg >= NbCol; Cl >= NbCol), !.
    
    best_move(NbCol, L, (Lg, Cl), 1000-(Lg, Cl)) :-
    	Pos is Lg*NbCol+Cl,
    	nth0(Pos, L, V),
    	\+var(V), !.
    
    % un coup légal est noté avec le nombre de coups
    % possibles qu'il engendre
    best_move(NbCol, L, (Lg, Cl), R-(Lg, Cl)) :-
    	LgM1 is Lg - 1, LgM2 is Lg - 2, LgP1 is Lg + 1, LgP2 is Lg + 2,
    	ClM1 is Cl - 1, ClM2 is Cl - 2, ClP1 is Cl + 1, ClP2 is Cl + 2,
    	include(possible_move(NbCol, L),
    		[(LgP1, ClM2), (LgP2, ClM1), (LgP2, ClP1),(LgP1, ClP2),
    		 (LgM1, ClM2), (LgM2, ClM1), (LgM2, ClP1),(LgM1, ClP2)],
    		Res),
    	length(Res, Len),
    	(   Len = 0 -> R = 1000; R = Len).
    
    % On teste s la place est libre
    possible_move(NbCol, L, (Lg, Cl)) :-
    	% la position doit être légale
    	Lg >= 0, Cl >= 0, Lg < NbCol, Cl < NbCol,
    	Pos is Lg * NbCol + Cl,
    	% la place doit être libre
    	nth0(Pos, L, V),
    	var(V).
    
    % affichage de l'échiquier
    affiche(_, _, []).
    affiche(N, N, L) :-
    	nl,
    	affiche(N, 0, L).
    
    affiche(N, M, [H | T]) :-
    	writef('%3r', [H]),
    	M1 is M + 1,
    	affiche(N, M1, T).
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

  18. #18
    Rédacteur/Modérateur
    Avatar de Trap D
    Inscrit en
    septembre 2003
    Messages
    4 560
    Détails du profil
    Informations forums :
    Inscription : septembre 2003
    Messages : 4 560
    Points : 5 488
    Points
    5 488

    Par défaut

    Suite à une discussion dans ce forum, voici un exemple montrant comment créer un "tableau" avec des cases cliquables.
    Les cases sont remplies avec une image prédéfinie de XPCE.
    Dans cet exemple, un clic affiche les corrdonnées de la case :
    Code :
    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
    tableau_cliquable:-
    	new(D, dialog('Cliquez moi !')),
    	send(D,size, size(300, 300)),
    	send(D,open),
    	affiche(D,1,5,5).
    
    affiche(_D, _C, _, 0) :-!.
    affiche(D, C, Largeur, L) :-
    	forall(between(1, Largeur, I),
    	       ( sformat(Name, 'Coordonnees ~w ~w', [L, I]),
    	         new(B, my_label(Name,'happy.bm')),
    		 X is 50 * (I-1) + 10,
    		 Y is 50 * (L-1) + 10,
    		 send(D, display, B, point(X,Y)))),
    	L1 is L-1,
    	affiche(D, C, Largeur, L1).
    
    
    
    :- pce_begin_class(my_label, label, "Graphical window with text").
    
    variable(name, any, both, "texte a afficher").
    
    initialise(P, Name, Img) :->
    	send(P, send_super, initialise, Name, image(Img)),
    	send(P, slot, name, Name),
    	WS = 50, HS = 50,
    	send(P, size, size(WS,HS)),
    	send(P, recogniser,
    	     handler_group(new(click_gesture(left,
    					     '',
    					     single,
    					     message(@receiver, my_click))))).
    
    % saisie du texte lors d'un click
    my_click(B) :->
    	get(B, slot, name, Name),
    	send(@display, inform, Name).
    
    :- pce_end_class.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : Intérieur avec jeune femme de Vilhelm Hammershoi

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •