IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Un mastermind en Prolog

Publié le 9 juillet 2012


III. Le serveur de jeu
III-A. Le code du serveur
III-B. Un client XPCE


III. Le serveur de jeu


III-A. Le code du serveur

Il utilise les sockets. Le code est très simple.
Lors de la première connexion au serveur pour débuter une partie, celui-ci envoie les paramètres de jeu.
Fichier 'mastermind-server.pl'

:- use_module(library(lambda)).
:- use_module(library(clpfd)).

:- use_module(library(socket)).

% numéro de partie
:- dynamic partie/1, solution/2.

% Parametres du moteur de creation / evaluation des propositions
% parametre(Combinaison, Lettres, Doubles)
:- dynamic parametres/3.

/******************************************************
% exemple
%
% parametres(4, 7, non)
%
% longueur des combinaisons : 4 lettres
%
% 7 lettres autorisées a ==> g
%
% Pas de double dans la combinaison à trouver
%
*******************************************************/

% serveur_mastermind(+, +, +)
serveur_mastermind(Combinaison, Chiffres, Doubles) :-
	% creation des paramètres du serveur
	retractall(parametres(_, _, _)),
	assert(parametres(Combinaison, Chiffres, Doubles)),

	% lancement du serveur
	create_server(5000).

% create_server(+)
create_server(Port) :-
	% la boucle infernale
	tcp_socket(Socket),
	tcp_bind(Socket,Port),
	tcp_listen(Socket,5),
	tcp_open_socket(Socket,AcceptFd,_),
	server_loop(AcceptFd).


% server_loop(+)
server_loop(AcceptFd) :-
	retractall(partie(_)),
	assert(partie(0)),
	retractall(solution(_,_)),
	repeat,
	    tcp_accept(AcceptFd,Socket2,_),
	    tcp_open_socket(Socket2,In,Out),
            read_line_to_codes(In, Codes),
            close(In),
	    catch(analyse_entree(Codes, A),
	          A,
	          format('Erreur de saisie ~w~n', [A])),
            format(Out, '~w~n', [A]),
	    close(Out),
	Codes = [].


% analyse_entree(+, -)
analyse_entree(In, Out) :-
	atom_codes(Atom, In),
	analyse(Atom, Out).

%analyse(+, -)
% a l'initialisation, le serveur renvoie
% un numero de connecté
% Les paramètres du jeu
analyse(init_connexion, Out) :-
	% calcul du numéro de partie
	retract(partie(Num)),
	Num1 is Num+1,
	assert(partie(Num1)),

	parametres(Len_Proposition, Lettres, Doubles),
	% choix de la solution
	choose(Len_Proposition, Lettres, Doubles, Combinaison),
	% mémorisation de la Combinaison de la partie
	assert(solution(Num, Combinaison)),

	Out = [Num, [Len_Proposition, Lettres, Doubles]],
	format('Entree du connecté ~w, Combinaison ~w~n', [Num, Combinaison]).

%analyse(+, -)
% etude d'une requete de jeu
% Out est de la forme [Code, XX_depend_du_code]
%
% Code = -1 proposition correcte,
% XX_depend_du_code est [Nombre de bien placées, nombre de mal placées]
%
% Code = -2 proposition incorrecte vis à vis des paramètres
% XX_depend_du_code est un message d'erreur
analyse(In, Out) :-
        term_to_atom(Term, In),
	Term = [Num, Guess],
	solution(Num, Solution),
	format('partie ~w  ~w  ~w~n', [Num, Solution,Guess]),
	(   study(Solution, Guess, Bulls, Cows)
	->  Out = [-1, [Bulls, Cows]]
	;   sformat(Str, '\'La proposition **~w** est incorrecte.\'', [Guess]),
	    Out = [-2, Str]).


% sélection d'une combinaison en fonction des paramètres du moteur
% choose(+, +, -)
choose(Len_Proposition, Lettres, Doubles, Combinaison) :-
	length(Lst, Len_Proposition),
	Max is Lettres ,
	repeat,
	maplist(\X^(X is random(Max)), Lst),
	(   Doubles = non -> all_distinct(Lst); true),
	maplist(\X^Y^(Y is X + 97), Lst, Codes),
	string_to_list(Combinaison, Codes),
	!.

% study(+, +, -, -)
% analyse de la proposition
study(Solution, Guess, Bulls, Cows) :-
	% chargement des paramètres du serveur
	parametres(Proposition, Lettres, _),

	% effectue la  transformation abcd => [97,98,99,100]
	atom_codes(Guess,Ms),
	% effectue la  transformation "abcd" => [97,98,99,100]
	string_to_list(Solution, Sol1),

	%vérification de la correction de la proposition
	length(Ms, Proposition),
	maplist(\X^(X >= 0'a, X < Lettres + 0'a), Ms),

	% calcul du nombres de lettres bien placées
	foldl(\X^Y^V0^V1^((X = Y->V1 is V0+1; V1 = V0)),Sol1, Ms, 0, Bulls),

	%  calcul du nombres de lettres mal placées
	foldl(\Y1^V2^V3^(foldl(\X2^Z2^Z3^(X2 = Y1 -> Z3 is Z2+1; Z3 = Z2), Ms, 0, TT1),
			 V3 is V2+ TT1),
	      Sol1, 0, TT),
	Cows is TT - Bulls.
La librairie lambda.pl a été écrite par Ulrich Neumerkel et est accessible à cette adresse.
foldl est un prédicat de SWI-Prolog 6.1.8.



III-B. Un client XPCE

C'est une simple petit boîte de dialogue.


Le code :
Fichier 'xpce-mastermind.pl'
% memorise le numéro de partie
:- dynamic numero/1.

% mémorise les données de la partie
:- dynamic parametres/3.

xpce_mastermind :-
	retractall(numero(_)),
	retractall(parametres(_,_,_)),
    make_dialog(D, 'Mastermind XPCE'),
	get(D, member, resultat, Name),
    init_connexion(Name) ,
    send(D,open).

dialog('Mastermind XPCE',
       [ object        :=
	   Client_d,
	 parts         :=
	   [ Client_d  := dialog('Client de mastermind'),
	     Mastermind_Item := text_item(text_item),
	     Resultat  := label(resultat, ''),
	     Liste :=  browser(resultats),
	     Button1   := button('Envoi'),
	     Button2   := button('Encore'),
	     Button3   := button('Terminé')
	   ],
	 modifications :=
	   [ Button1 := [default_button := true],
	     Mastermind_Item := [ label := 'Tapez votre proposition : '
			  ]
	   ],
	 layout        :=
	   [ area(Mastermind_Item,
		  area(12, 18, 400, 24)),
	     area(Resultat,
		  area(12, 67, 184, 18)),
	     area(Button1,
		  area(420, 16, 80, 24)),
	     area(Button2,
		  area(420, 62, 80, 24)),
	     area(Button3,
		  area(420, 108, 80, 24)),
	     area(Liste,
		  area(12, 95, 400, 200))
	   ],
	 behaviour     :=
	   [ Button1 := [ message := message(@prolog, lance_calcul, Mastermind_Item?selection, Resultat, Liste)
		       ],
	     Button2 := [message := and(message(@prolog, init_connexion, Resultat), 
		 		        message(Mastermind_Item, clear), 
		 		        message(Liste, clear))
			],
	     Button3 := [message := message(Client_d, destroy)
		       ]
	   ]
]).


% init_connexion(+)
init_connexion(Label) :-

	% connexion au serveur
	tcp_socket(Socket),
	Host='localhost', Port=5000,
	tcp_connect(Socket, Host:Port),
	tcp_open_socket(Socket, ReadFd, WriteFd),

	% envoi d'une donnée initialisant une partie
	format(WriteFd, '~w~n', [init_connexion]),
	flush_output(WriteFd),
	
	% lecture du résultat
	read_line_to_codes(ReadFd, Lst),
	close(ReadFd),
	close(WriteFd),
    
	% tranformation en terme Prolog
	atom_codes(Atom, Lst),
	term_to_atom(Term, Atom),
	Term = [Num, [Len_Proposition, Lettres, Doubles]],
	
	% memorisation des paramètres du jeu
	assert(parametres(Len_Proposition, Lettres, Doubles)),
	assert(numero(Num)),
	
	% envoi d'un message expliquant les paramètres de la partie
	Max is 0'a +Lettres - 1,
	atom_codes(A, [Max]),
	(   Doubles = non
	->  sformat(Str, '\'La proposition est composée de ~w lettres de a à ~w, sans doublons.\'',
		[Len_Proposition, A])
	;   sformat(Str, '\'La proposition est composée de ~w lettres de a à ~w, avec doublons.\'',
		[Len_Proposition, A])),

	send(Label, selection, Str).

% lance_calcul(+, +, +) 
lance_calcul(Expr, Resultat, Liste) :-

	% récupération du numéro de partie
	numero(Num),
	
	% connexion au serveur
	tcp_socket(Socket),
	Host='localhost', Port=5000,
	tcp_connect(Socket, Host:Port),
	tcp_open_socket(Socket, ReadFd, WriteFd),
    
	% envoi des données
	format(WriteFd, '[~w,~w]~n', [Num, Expr]),
	flush_output(WriteFd),
	
	% récupétation des résultats
	read_line_to_codes(ReadFd, Lst),
	close(ReadFd),
	close(WriteFd),
    
	% tranformation en terme Prolog
	atom_codes(Atom, Lst),
	term_to_atom(Term, Atom),
	
	% etude des résultats
	etudie_resultat(Expr, Term, Resultat, Liste).


% etudie_resultat(+, +, +, +)
% On a gagné !
etudie_resultat(Expr, [-1, [Len_Proposition, Cows]], Resultat, List) :-
	parametres(Len_Proposition, _, _),
	sformat(Atom, '~w : Bulls ~w Cows ~w', [Expr, Len_Proposition, Cows]),
	send(List, append, Atom),
	send(Resultat, selection, 'Bravo !!!').

% cas général
etudie_resultat(Expr, [-1, [Bulls, Cows]], _Resultat, List) :-
	sformat(Atom, '~w : Bulls ~w Cows ~w', [Expr, Bulls, Cows]),
	send(List, append, Atom).

% ici c'est une erreur dans la proposition
etudie_resultat(_Expr, [-2, Mess], Resultat, _List) :-
	send(Resultat, selection, Mess).
 

Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2012 Joël Foutelet. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.