une lambda objet ?

Une lambda, c'est quoi ? C'est une fonction anonyme. Ca a l'air assez etrange dit comme ca, pourtant, on ne peut pas le presenter autrement, ces fonctions peuvent-etre passees en parametre a d'autres fonctions, on peut les mettre comme "valeurs" a des variables, bref, ces fonctions sont des valeurs comme les autres.

Dans les langages de programmation fonctionnels, on peut creer des lambdas tres facilement : exemple en ocaml

(fun x -> x+1)(2);;

Ca donne 3

En javascript, la syntaxe est la suivante :

function(x){ return x+1; }

La syntaxe est plus lourde, mais c'est pour ce genre de bout de code, que javascript EST un langage fonctionnel (en plus d'etre imperatif)

Ces fonctions sont meme la caracteristique des langages fonctionnels, d'ailleur, le premier langage de programmation etait fonctionnel, et n'integrait QUE le principe des lambdas.

Un exemple d'application de ces fonctions :

List.map (fun x -> x+1) [1; 2; 3; 4; 5; 6; 7];;

ca donne [2; 3; 4; 5; 6; 7; 8]

Ces choses semblent vraiment propres aux langages de programmations fonctionnels, cependant, il parait que microsoft l'a implemente a C#.

Le langage php ne possede pas de closures, ni de type "function", ce qui limite ce genre de choses, cependant, on peut faire des choses comme :

$foo = 'function_name';
$result=$foo($param1, $param2);

et la fonction est appellee, sur le meme principe, on peut creer une fonction anonyme, grace a create_function, mais le typage est mauvais : ca renvoie un string...

En java, j'aurais bien voulu pouvoir en faire, pour pouvoir creer un "filtre d'iterateurs", qui serait parametrable, bien sur, j'aurais pu faire une classe abstraite : filtred_iterator<E> implements Iterator<E> et ensuite faire :

Iterator it = new FiltredIterator(malistechainee.iterator()){
private boolean filtre(Truc t){ return truc.isValide(); }
};

Ca aurait parfaitement fonctionne, sauf que le fait de pouvoir composer deux fonctions offre parfois un avantage majeur (pour filtre, pas forcement, mais pour map, l'avantage est evident), et donc, j'ai pense pousser le vice beaucoup plus loin : offrir a java des fausses lambdas, avec un type, et une vraie vie. Une lambda, c'est juste une fonction qui prend un parametre pour renvoyer une valeur. En pratique, on a jamais besoin de plusieurs parametres : on utilise la currification si on veut plusieurs parametres.

interface lambda{
    E a(F p);
}

la lambda incrementer peut s'ecrire comme ceci :

        lambda increment = new lambda(){
            public Integer a(Integer i){
                return new Integer(i.intValue()+1);
            }
        };
        System.out.println(increment.a(new Integer(5)));

La syntaxe est tres lourde, on est oblige d'utiliser la methode "a" pour appliquer la fonction, mais ca fonctionne tres bien. Pour aller plus loin, voici un exemple de currification : une lambda qui renvoie une lambda :

         lambda> increment = new lambda>(){
            public lambda a(final Integer i){
                return new lambda(){
                    public Integer a(Integer j){
                        return j.intValue()+i.intValue();
                    }
                };
            }
        };
        System.out.println(increment.a(new Integer(5)).a(new Integer(9)));

Pour la lambda de composition, elle se doit d'etre generique, on doit donc faire une classe pour elle :

class composer implements lambda{
     private lambda f;
     private lambda g;
    public composer( lambda f, lambda g){
        this.f = f; this.g=g;
    }
    public E a(F p){
        return f.a(g.a(p));
    }
}

et voici un exemple d'utilisation de la composition :

        lambda f =new composer(
                new lambda(){ public Integer a(Integer i){ return new Integer(i.intValue()+1); } },
                new lambda(){ public Integer a(Integer i){ return new Integer(i.intValue() * 2); } }
                );
        System.out.println(f.a(new Integer(5)));

C'est tres particulier, mais tres interessant (et euh... a eviter dans des projets serieux, c'est tres marrant a taper, mais je doute que ca soit tres politiquement correct...)

programmez en brainfuck grace a ocaml

Le brainfuck

Le brainfuck est un langage de programmation (oui oui !) qui est _vraiment_ minimaliste. Ce langage ne comporte que huit instructions. Elles permettent chacune de faire une operation tres limitee. Le nombre d'instruction etait peu eleve, il est normal que les instructions soient de bas niveau pour qu'on puisse quand meme realiser plein de choses avec.

Ce langage est turing complet, c'est donc un langage de programmation qui permet de tout faire (ce qui n'est pas evident quand on regarde la tete du langage.)

Notre langage est constitue des 8 instructions suivantes :
< > + - [ ] . ,

ces instructions agissent sur la memoire ou sur le flot d'instructions. la memoire est un immense ruban infini, et deroulable dans les deux sens.

    --|----|----|----|----|----|----|----|----|----|--
      | -4 | -3 | -2 | -1 | 0  | 1  | 2  | 3  | 4  |
    --|----|----|----|----|----|----|----|----|----|--
                                 ^

ici, la memoire avec les indices (puisqu'on deroule dans les deux sens, ils peuvent etre negatifs.)

dans chaque case, on a une valeur comprise entre 0 et 255

on a aussi un "pointeur" vers une case, nous nommerons alors cette case, la case courrante. Dans l'exemple, le pointeur etait sur le 1.

Les instructions "<" et ">" permettent de pointer sur la case suivante ou precedente.
Les instructions "+" et "-" permettent d'incrementer ou de decrementer la valeur d'une case. Les valeurs. Comme les valeurs vont de 0 a 255, lorsque l'on tente d'incrementer 255, on retombe sur 0 ; inversement, decrementer 0 nous donne 255.

les deux instructions "[" et "]" marquent une boucle : tant que la ou on pointe est non null, effectuer les operations contenues dans la boucle.

Il nous reste deux instructions : "." et ",", qui sont toutes deux les operations d'entrees sorties elementaires. "." affiche le caractere ascii qui correspond a la valeur de la case courrante. "," demande un caractere au clavier, et inscrit son code ascii dans la case courrante.

Vous remarquerez qu'il est tres difficile d'effectuer un programme ave aussi peu d'instructions, c'est pourquoi, si des humains ont du mal a ecrire du brainfuck, on peut se poser la question suivante :

Comment faire un programme qui ecrit un code brainfuck ?

En ocaml, on peut representer un code brainfuck sous forme d'une liste de "brainfuck", avec "brainfuck" defini comme ci dessous :

type brainfuck =
  Inc | Dec |
  Next | Prev |
  While of brainfuck list |
  Input | Print;;

On peut alors faire un brainfuck etendu pour "compresser" certaines instructions. C'est juste une question de facilite d'ecriture, ce nouveau type ne permet rien d'extra-ordinaire.

type extendedBrainfuck =
  W of extendedBrainfuck list |
  Bf of brainfuck |
  Add of int |
  Sub of int |
  Jmp of int;;

Ce nouveau type nous permet de compresser : [Next;Next;Next;Next] en [Jmp(4)], ce qui est deja plus pratique a ecrire. W permet de faire une boucle. Bien evidement, cette structure ne suffit pas pour effectuer des operations interessantes, je vous propose celle-ci :

type lang =
  WhileVar of string * (lang list) |
  AddVar of string * int |
  SubVar of string * int |
  PrintVar of string|
  InputVar of string|
  Call of fonction * string list
and fonction = string list * string list * lang list;;


En fait, on devrait dire procedure et pas fonction, mais c'est un detail. Le systeme de variables est simple : on affecte un nom par "case memoire". Nous verrons plus loin la distribution des variables.
  •   Pour ajouter un nombre (pour l'exemple, ajoutons 42) a une variable, que nous nommerons "foo", on fait : AddVar("foo", 42)
  •   Pour soustraire un nombre a une variable, on fait : SubVar("foo", 42)
  •   Pour afficher le contenu du variable "foo", on fait : PrintVar("foo")
  •   Pour l'input sur la variable "foo" : InputVar("foo")
  •   Pour faire une boucle : tant que la variable "foo" est non nulle, on execute le code : "code" : While ("foo", code)
  •   Pour appeller une fonction, on fait Call (fonction, parametres)

Les fonctions sont en fait "inlinees" dans le code (comme des macros en C.), ce qui veut dire qu'on ne peut pas faire de fonctions recursives.

Pour definir une variable a 0 en brainfuck, on fait :
[-]

Notre premiere macro sera celle qui definit un nombre a 0 :

let zerofunc = ( ["x"], [], (*x=0*)
  (WhileVar ("x", [SubVar ("x", 1)] ))::[]);;

le ["x"], correspond a la liste des parametres que l'on peut passer a la fonction zerofunc. Bien evidement, ces parametres sont passes par reference. le [] correspond a la liste des variables locales. le reste, c'est le code de la fonction zerofunc : (WhileVar ("x", [SubVar ("x", 1)] ))::[])

Comme vous pouvez l'appercevoir, en ocaml, zerofunc n'est en fait pas une fonction, c'est une valeur comme les autres... de type : string list * string list * lang list

De la meme facon, on peut definir les fonctions suivantes :
let plusEgalZero = ( ["x";"y"], [], (* x+=y; y=0*) ...
let copy = ( ["x";"y"], ["z"], (*y=x*) ...
let plus = ( ["x";"y"], ["z"], (*x=x+y*) ...
let switch = ( ["x";"y"], ["z"], (*x=x+y*) ...
let affChiffre = (["x"], [], ...

Pour commencer, nous nous arreterons la pour les fonctions "simples"

Comme je le disais plus haut, pour ocaml, ce ne sont pas des fonctions, mais des valeurs, il semble donc "possible", voir meme interessant de faire des fonctions qui renverraient ce type de valeur (un tout petit semblant de curyfication) Un exemple simple : j'aimerais bien pouvoir effectuer l'operation : Call ( afficher_char '\n', []) qui m'afficherait un retour a la ligne.

pour faire ca, on fait une fonction qui prend en parametre "c", et qui renvoie une macro qui ne prend aucun parametre, qui utilise "x" comme variable temporaire, ensuite, le code consiste a mettre x a : int_of_char c, et a afficher x.

let printchar c = ([], ["x"],
  (Call (zerofunc, ["x"]))::(AddVar("x", int_of_char c))::(PrintVar "x")::[]
);;

de la meme facon, on peut faire un "set"

let setVal v = (["x"], [],
  (Call (zerofunc, ["x"]))::(AddVar("x", v))::[]
);;

Bon, on commence a pouvoir faire generer du brainfuck :)

Exemple : le code suivant nous renvoie une fonction qui calcule les 5 premiers nombres de la suite de fibonaci.

let funcmain = ( [], ["n";"a";"b"],
  (AddVar("n", 5))
  ::(AddVar("b", 1))
  ::(WhileVar ("n",
    SubVar ("n", 1)
    ::(Call (plus, ["a";"b"]) )
    ::(Call (switch, ["a";"b"]) )
    ::(Call (affChiffre, ["a"]))
    ::(Call (printchar '\n', []))
    ::[] ))
  ::[]
);;

Autre Exemple : le code suivant nous renvoie une fonction qui calcule les 4 premiers nombres triangulaires.

let funcmain = ( [], ["n";"a";"b"],
  AddVar("n", 4)
  ::AddVar("b", 1)
  ::WhileVar ("n",
    SubVar ("n", 1)
    ::AddVar ("b", 1)
    ::Call (plus, ["a";"b"])
    ::Call (affChiffre, ["a"])
    ::Call (printchar '\n', [])
    ::[] )
  ::[]
);;

Dans les deux exemples precedents, on se limite a 4 ou 5 nombres, parce-que si on cherche plus loin, alors les resultats font plus de deux chiffres, et gerer des nombres a plusieurs chiffres, c'est pas un probleme trivial en brainfuck.

On va tenter de faire une fonction pour faire un "if variable=constante then ... else ...", notre fonction prendra trois parametres : la constante, le code a executer "si egal", et le code a executer "si different". On appellera ces variables : valeur, statement_if, statement_else. Ensuite, la macro prendra la variable en parametre, elle verifiera si la variable est egal a la valeur, et executera les statement, selon les choix.

Le principe est simple : on prend trois variables temporaires : "tmp", "e", et "ne". Au debut, on definit tmp=x, ensuite, on soustrait valeur a tmp. Si x = valeur, alors a ce moment la, on obtient : tmp=0, sinon, on a tmp != 0. Au debut, on doit alors faire ceci : ne = 1, e=0, lancer une boucle sur tmp n'exexute le contenu de la boucle que si x = valeur. on effectue alors la boucle suivante :
WhileVar("tmp",
  Call(zerofunc, ["tmp"])
  ::AddVar("e", 1)
  ::SubVar("ne", 0)
  ::[]
)

le zerofunc permet de ne faire "qu'un tour" de boucle. Ensuite, mes definitions de "e" et "ne" permettent d'avoir :
Si x = valeur
 e = 1
 ne = 0
Sinon
 e = 0
 ne = 1
FinSi

ce qui permet de faire une boucle sur la variable "e", et executer dedans : SubVar("e", 1) et statement_if, puis une boucle sur la variable "ne", et effectuer dedans SubVar("ne", 1) et statement_else.

C'est le principe simplifie de la fonction que j'ai dans mon code. Au final, on a des parametres a passer a statement_if, et statement_else.

au final, ca donne ca :

let ifEqual valeur params statement_if statement_else = ("x"::params, ["tmp";"e";"ne"],
  Call (copy, ["x";"tmp"])
  ::SubVar("tmp", valeur)
  ::Call( setVal 1, ["e"])
  ::Call( setVal 0, ["ne"])
  ::WhileVar ("tmp", (* not egal *)
    Call (zerofunc, ["tmp"])
    ::SubVar("e", 1)
    ::AddVar("ne", 1)
    ::[] )
  ::WhileVar ("e",
    SubVar("e", 1) :: statement_if )
  ::WhileVar ("ne",
    SubVar("ne", 1) :: statement_else )
  ::[]
);;

Bon... Pour continuer on peut tenter de faire des operations sur plusieurs octets. Pour ca, on balade des listes en parametres.

implementer une gestion des listes, c'est malheureusement trop complique, heureusement, ocaml a deja ses listes, alors contentons nous d'appeller nos variables avec un prefixe et un indice.
le nom du n-eme element d'une liste sera donne ainsi :

let input prefix n = prefix^(string_of_int n);;

voici la fonction qui nous donne la liste :

let liste_input prefix i =
  let rec f li n =
    if n = i then li
    else f ((input prefix (i-n-1)) :: li) (n+1)
  in f [] 0;;

parfois, on voudra passer un, deux, trois, etc... gros nombres a une fonction, et on aura donc besoin d'une fonction qui nous renvoie :
["a_0";"a_1";..."a_5"..."b_0"..."c_0"..."d_5"]

la voici :

let paramListe i li = List.flatten (List.map (fun x -> liste_input x i) li );;

vous pouvez la tester avec le code suivant :
paramListe 4 ["a_";"b_"];;

On a plusieurs fonctions a faire du meme type : tout mettre a 0 ou afficher un gros nombre, ce sont deux operations du meme type : on effectue une operation simple sur chaque chiffre ; switch et copy aussi sont du meme type : on effectue une operation simple (Call(switch, ["a";"b"]) ou bien Call(zerofunc, ["a"])) sur chaque couple de chiffre (en formant les couples ainsi : le premier chiffre de a, avec le premier chiffre de b, etc...)

On definit ces fonctions assez facilement :

type 'a transfo = ('a -> lang) -> ('a list) -> lang list;;
let multi_param_each_ (map:(string transfo)) f i =
  let liste = liste_input "a_" i
  in ( liste, [], map f liste );;

let multi_param_each_rev = multi_param_each_ List.rev_map;;
let multi_param_each = multi_param_each_ List.map;;

let deux_multi_param_each_ (map:((string*string) transfo)) f i =
  let lista = liste_input "a_" i and listb = liste_input "b_" i
  in ( (List.append lista listb), [], map f (List.combine lista listb) );;

let deux_multi_param_each_rev = deux_multi_param_each_ List.rev_map;;
let deux_multi_param_each = deux_multi_param_each_ List.map;;

let big_int_switch = deux_multi_param_each (fun (a, b) -> Call (switch, [a;b]) );; (* a <=> b*)
let big_int_copy = deux_multi_param_each (fun (a, b) -> Call (copy, [a;b]) );; (* b = a *)
let big_int_aff = multi_param_each_rev (fun (a) -> Call (affChiffre, Angel) );; (* aff a *)
let big_int_zero = multi_param_each (fun (a) -> Call (zerofunc, Angel) );; (* a = 0 *)


Pour la suite, on ajoutera une fonction big_int_plus_un, et une fonction big_int_plus, je vais les detailler plus bas. Nos nombres ont une taille fixee a la compilation. voici cette taille :

let size_big_int = 15;;

pour plus de simplicite, on applique nos fonctions, on peut ensuite coder plus facilement.

let big_int_switch = big_int_switch size_big_int;;
let paramListe = paramListe size_big_int;;
let big_num_plus_un = big_num_plus_un size_big_int;;
let big_num_plus = big_num_plus size_big_int;;
let big_int_aff = big_int_aff size_big_int;;

En brainfuck, ajouter un est une operation non triviale sur un nombre a plusieurs chiffres. Le principe est le suivant : on ajoute 1 au dernier chiffre ; si le dernier chiffre est egal a 10, alors on le met a 0, et on appelle +1 sur une sous-partie du nombre. Notre fonction est donc recursive, mais il est quand meme possible de l'inliner (paradoxallement) c'est comme si on definissait : "big_num_plus_un_taillenombre=4", puis "big_num_plus_un_taillenombre=3", puis "big_num_plus_un_taillenombre=2" puis "big_num_plus_un_taillenombre=1", puis "big_num_plus_un_taillenombre=0"

voici le code de la fonction +1

(* a = a + 1 *)
let rec big_num_plus_un i =
  if i=0 then ( [], [], [] ) else
  let liste = liste_input "a_" i
  in let code =
  AddVar("a_0", 1)
  ::Call (ifEqual 10 liste (
    SubVar("a_0", 10)
    :: Call (big_num_plus_un (i-1), List.tl liste)
    ::[]
    ) [], "a_0"::liste)
  ::[]
  in ( liste, [], code );;


et un exemple d'application : compter jusqu'a 15
let funcmain = ( [], "n"::(paramListe ["a_"]),
  (AddVar("n", 15))
  ::(WhileVar ("n",
    SubVar ("n", 1)
    ::(Call (big_num_plus_un , paramListe ["a_"]) )
    ::(Call (big_int_aff, paramListe ["a_"]))
    ::(Call (printchar '\n', []))
    ::[] ))
  ::[]
);;

la fonction plus repose sur le meme principe, je ne la detaillerais pas.

let rec big_num_plus i = (* a = a+b*)
  if i=0 then ( [], [], [] ) else
  let lista = liste_input "a_" i and listb = liste_input "b_" i and listc = liste_input "c_" i
  in let code =
  Call (big_int_copy i, List.append listb listc)
  ::WhileVar ("c_0",
    SubVar("c_0", 1)
    ::Call (big_num_plus_un i, lista)
    ::[] )
  ::Call (big_num_plus (i-1), List.append (List.tl lista) (List.tl listb))
  ::[]
  in ( List.append lista listb, listc, code );;



voici un fibonaci.

let funcmain = ( [], "n"::(paramListe ["a_";"b_"]),
  (AddVar("n", 100))
  ::(AddVar("b_0", 1))
  ::(WhileVar ("n",
    SubVar ("n", 1)
    ::(Call (big_num_plus, paramListe ["a_";"b_"]) )
    ::(Call (big_int_switch, paramListe ["a_";"b_"]) )
    ::(Call (big_int_aff, paramListe ["a_"]))
    ::(Call (printchar '\n', []))
    ::[] ))
  ::[]
);;

avec des nombres de 15 chiffres, on arrive a 1.2 mo de code brainfuck, pour 3700 lignes de code... En modifiant legerement le "compilateur" pour qu'il allege le code brainfuck, on arrive a 200 ko de code, et toujours 3700 lignes. Le temps de compilation se trouve par contre largement augmente.

max@max-laptop:~$ time OCAMLRUNPARAM="b" ./a.out > fibonaci.bf

real    3m51.838s
user    1m54.143s
sys     0m0.620s
ca commence a faire beaucoup pour un simple fibonaci.

Classé sous , , , ,
Attachment(s): brainfuck.txt

la fin d'une "longue" aventure ?

Voila maintenant un an et 10 mois que mon laptop et moi vivons une aventure folle, pleine de rebondissements, de sensations fortes, et de passion.

Je vous le presente :

  • nom : Delphine
  • sa race : acer aspire 5100
  • age : un an et dix mois
  • note en calcul mental : 2ghz
  • memoire : morte : 60go vive : 3 go (0.5go de serie, le reste est du a son evolution)
  • carte graphique : mauvaise.
  • ecran 15 pouces

Nous partageons presque toutes nos nuits depuis ce octobre 2006, jours ou il eclot de sa boite. Nous avons vecu des moments forts, j'ai souvent fouille ses entrailles, parfois simplement pour une batterie, parfois pour une barette de ram, parfois par plaisir ou par curiosite.

On a meme fait des LANs pour nous sortir de la routine (sorte de partouses geantes ou d'autres geeks viennent avec leurs compagnons : fixes ou portables, pour se relier sur un switch et jouer plusieurs nuits.), c'etait super, on passait d'exellents moments...

et puis il y a eu cet accident... un jours ou je traversais Paris probablement... j'imagine qu'il a alors subbit un choc dans le metro, il en a souffert jusqu'a aujourd'hui... Ca a ete tres difficile pour moi, son ecran avait un faux contact (sorte d'entorse dans un cable), parfois, je devais le cageoler, le tourner, appuyer un peu la ou il avait mal (entre les deux charnieres) pour qu'il se remette a fonctionner "normalement", et parfois ca ne suffisait pas...

Cet apres midi, je l'ai ampute de l'ecran.






il fonctionne toujours, mais m'en voudra-t'il ?


Classé sous , ,

concours google

pour ceux qui comme moi font le concours :

22222222220000000000000000000000000000000000000000
21112211122222200000000000000000000000000000000000
21112211122111222200000000000000000000000000000000
21112211122111221222000000000000000000000000000000
22222222222222222222220000000000000000000000000000
22222222222222222222222200000000000000000000000000
21112211122111221112211122000000000000000000000000
21112211122111221112211122220000000000000000000000
21112211122111221112211122122000000000000000000000
22222222222222222222222222222220000000000000000000
22222222222222222222222222222222000000000000000000
21112211122111221112211122111222200000000000000000
21112211122111221112211122111221120000000000000000
21112211122111221112211122111221112000000000000000
22222222222222222222222222222222222200000000000000
22222222222222222222222222222222222220000000000000
21112211122111221112211122111221112212000000000000
21112211122111221112211122111221112211200000000000
21112211122111221112211122111221112211220000000000
22222222222222222222222222222222222222222000000000
22222222222222222222222222222222222222222000000000
21112211122111221112211122111221112211122200000000
21112211122111221112211122111221112211122220000000
21112211122111221112211122111221112211122120000000
22222222222222222222222222222222222222222222000000
22222222222222222222222222222222222222222222000000
21112211122111221112211122111221112211122111200000
21112211122111221112211122111221112211122111200000
21112211122111221112211122111221112211122111220000
22222222222222222222222222222222222222222222220000
22222222222222222222222222222222222222222222222000
21112211122111221112211122111221112211122111222000
21112211122111221112211122111221112211122111222200
21112211122111221112211122111221112211122111221200
22222222222222222222222222222222222222222222222200
22222222222222222222222222222222222222222222222220
21112211122111221112211122111221112211122111221120
21112211122111221112211122111221112211122111221120
21112211122111221112211122111221112211122111221120
22222222222222222222222222222222222222222222222220
22222222222222222222222222222222222222222222222222
21112211122111221112211122111221112211122111221112
21112211122111221112211122111221112211122111221112
21112211122111221112211122111221112211122111221112
22222222222222222222222222222222222222222222222222
22222222222222222222222222222222222222222222222222
21112211122111221112211122111221112211122111221112
21112211122111221112211122111221112211122111221112
21112211122111221112211122111221112211122111221112
22222222222222222222222222222222222222222222222222


Classé sous , , , ,

des generateurs python en java (yield)

Apres avoir lu :
http://fr.wikipedia.org/wiki/Python_(programming_language)#G.C3.A9n.C3.A9rateurs

on y trouve un exemple tres interessant :
for n in gen_fibonacci(1000):
print n
cet exemple permet en gros de renvoyer un iterateur. Ce qui est marrant, c'est la syntaxe de l'iterateur... Plutot que de faire un objet, en python, ils ont une instruction qui sert a faire "plusieurs returns values"
def gen_fibonacci(max=sys.maxint):
a=0
b=1
while a<max:
yield a
a,b = b,a+b
c'est marrant comme syntaxe, si on pouvait avoir ca dans d'autres langages, ca serait le pied ;)

le principe est simple : yield sauve le contexte d'execution, et renvoie la valeur. quand on rappelle la fonction, le contexte est concerve.

en java, j'ai fait une classe du meme genre.
public class fibogen extends generator<Integer>{
protected void generateur(){
int d;
int a=0;
int b=1;
while(a<100){
yield(new Integer(a));
d=b;
b+=a;
a=d;
}
}
}
On la lance comme ceci :
fibogen foo = new fibogen();
Integer n;
while (foo.hasNext()){
n = foo.next();
System.out.println(n.toString());
}
bref, je vous presente ma classe, c'est porc, mais c'est marrant

abstract public class generator<T> implements java.util.Iterator<T>, java.lang.Runnable {
Thread t;
T foo;
enum Fin{
Debut, Dernier, Fini
}
Fin next = Fin.Debut;
enum State{
WaitValue, Valued;
}
State state;
public generator(){
t = new Thread(this);
t.start();
getnext();
}
public boolean hasNext(){
return next != Fin.Fini;
}
public T next(){
T n = foo;
if (next != Fin.Dernier) getnext();
else{
next = Fin.Fini;
}
return n;
}
public void getnext(){
state = State.WaitValue;
while (state != State.Valued){
if (next != Fin.Debut){
next = Fin.Fini;
return;
}
Thread.yield();
}
}

public void run(){
generateur();
next = Fin.Dernier;
t.interrupt();
}
protected void yield(T bar){
while (state != State.WaitValue){ Thread.yield(); }
foo = bar;
state = State.Valued;
Thread.yield();
}
abstract protected void generateur();
final public void remove(){}
}
c'est le genre de code que je trouve marrant, mais plutot inutiles dans un vrai projet ;)

Classé sous , , , , , ,

champion 2008

prologin s'acheve sur une dure bataille de pommes :)

je vous passe mon "champion"
 * _   _                     _            _
*| | | | __ _ _ __ ___ ___| |_ ___ _ __( )___ __ ____ _ _ __
*| |_| |/ _` | '_ ` _ \/ __| __/ _ \ '__|// __| \ \ /\ / / _` | '__|
*| _ | (_| | | | | | \__ \ || __/ | \__ \ \ V V / (_| | |
*|_| |_|\__,_|_| |_| |_|___/\__\___|_| |___/ \_/\_/ \__,_|_|
ouais, bon, jme suis fait plaisir sur l'ascii art :)

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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
/*
* Champion (ou pas) prologin 2008 (rendu le 10 mai 2008)
*
* Style de programmation
* les fonctions devront faire une seule chose, une chose precise, et la faire bien.
* J'ai choisi quelques variables globales pour stoquer mes donnees
*
*
* Strategie envisagees (en resume...) :
* - aller chercher et ramener des pommes dans ma zone
* - tirer sur quelques ennemis (quand ca a l'air interessant
* - sauver quelques hamsters lorsqu'ils tombent dans une fosse
* - tenter de traverser quelques ravins

On gere le moteur general par une liste d'etats,
et des pointeurs sur fonctions pour gerer les operations de facon assez abstraite.

Tirer
seulement lorsque c'est notre tour de jouer en premier, histoire de ne pas
gaspiller nos precieux trognons.
Je n'envoie aussi des trognons dans la gueule de nos ennemis,
que quand ils sont en face, histoire de ne pas perdre trop de temps.
Si notre enemie ne tombe pas dans une fosse,
alors il est inutile d'envoyer un trognon.

Se deplacer
On se deplace vers la pomme la plus proche qui n'est pas occupee par nos mecs.
Ensuite, on ramene les pommes dans notre zone pour recommencer.

Quand un hamster tombe dans la fosse, c'est chiant,
faut qu'un autre aille tenter de le sauver, mais je sais pas trop si ca fonctionne bien...

Quand on n'a rien a faire (pommes innaccessibles par exemple) on devrait chercher a aller
de l'autre cote des fosses (fonction bouge_ton_cul) mais en pratique,
c'est tres difficile de gerer correctement le grapin, et donc...

Les sauver (tentative morbide a base de "je te pousse")

Les points forts de mon IA : sa recuperation de points, son cote safe, et son attaque.

*/


#include "prologin.h"
#include <stdlib.h>
#include <stdio.h>


//! Notre structure de donnees copeaux de bois.
typedef struct {
//int pomme;
int sol; //! peut-etre normal, un obstacle ou un trou
int x, y; //! ses coordonnees
} copBois;

struct hamstruct;
//! notre type de pointeurs sur fonctions
// ces fonctions sont des fonctions d'actions
typedef void (*HamAction)(struct hamstruct *h, int toD);

struct hamstruct {
int id; // son id
int x, y; // la position de notre hamestere
int toD[3]; // les parametres des actions de notre hamstere (to Direction)
HamAction actions[3]; // les trois actions de notre jambon (ou hamster, je sais plus)

int used_ordres; // le nombre d'ordres qu'il utilise

int traverse; // si il a droit de traverser un fosse ou pas

int Ntrognons; // le nombre de trognons qu'il lui reste a prendre
int Hpomme; // ca aurait pu etre utile, mais en fait non...
int mission;

int utile; // dit si sa mission est vraiemnt importante ou pas;

int mtx, mty; // mission target x. y

int s; // quand on a besoin de suivre qqn

int m; // l'etat du grapin
int timefreeze, opx, opy;
};

typedef struct hamstruct ham;

#define GR if (r!=SUCCESS) printf("747---bad argument hamster %d ligne %d erreur %d\n\n", h->id, __LINE__, r);
#define HAMSTER_NOMBRE 3
#define NTROGNONS 2

#define CHERCHER_POMMES 0
#define TOMBER_POMMES 1
#define RAMASSER_POMMES 2
#define POMMES_SAVEHOME 3
#define PROTEGER_POMMES 4
#define SUIVRE 5
#define GRAPPINER 6

//! ma valeur absolue
int mabs(int a){
if (a<0) return -a; return a;
}

void decider(ham *h); //! prototype de la fonction de decision.

//! les fonctions de type HamAction.

//! fonction de deplacement
void aller(ham *h, int toD){
//printf("747---deplacement du hamster %d, vers %d\n",
//   h->id, toD );
int r = deplacer(h->id, toD); GR
}
//! fonction qui lache une pomme
void lacher(ham *h, int toD){
printf("747---le hamster %d, lache une pomme en %d, %d\n",
h->id, h->x, h->y );
int r = lacher_pomme(h->id, toD); GR
}
//! fonction de ramassage de pomme
void ramasser(ham *h, int toD){
printf("747---le hamster %d, ramasse une pomme en %d, %d\n",
h->id, h->x, h->y );
int r = ramasser_pomme(h->id); GR
}
//! fonction qui sert a poser le grapin sur un ham
void grappiner(ham *h, int toD){
printf("747---le hamster %d, grappine en %d\n",
h->id, toD );
int r = grappin(h->id, toD); GR
}
//! fonction qui envoie un trognon sur un ham
void trogner(ham *h, int toD){
printf("747---le hamster %d, trogne en %d\n",
h->id, toD );
int r = trognon(h->id, toD); GR
}
//! fonction de repos d'un hamstere
void patienter(ham *h, int toD){
//printf("747--- Le hamster %d ne fout rien\n", h->id);
int r=attendre(h->id); GR
}
/*
Ces fonction auraient pu etres utilisees, je les ai codees quand j'etais
+
*/


/*
int getX(int pos){
return pos & 0xFFFF;
}
int getY(int pos){
return (pos & 0xFFFF0000 ) >> 16;
}
int pos(int x, int y){
return x + ( y << 16) ;
}
*/



//! dit si c'est ta zone
int macase(int x, int y){
return y==0 || y==1;
}


// VAR globales

copBois *cases, **map; // la map
int sx, sy, tmap, /* size x, y, taille map*/
end; /* nombre de tours */

ham hamster[HAMSTER_NOMBRE]; // les hamsters

int haswhite; // dit si on a les blancs ce tour la ou pas.

//int strategie; // soit on met 1, soit 3

// dit si la position est valide ou non
int isValidPos(int x, int y){
return x>=0 && x < sx && y < sy && y >=0;
}

//! met a jours l'etat de la case *o au niveau des pommes
//void updatePomme(copBois *o){
// o->pomme = pomme(o->x, o->y);
//}
//! dit ou un gars est
void tayou(ham *h){
int x, y;
x=pos_x(h->id);
y=pos_y(h->id);
h->Hpomme= porte_pomme(h->id);

if (x==h->opx && y==h->opy){
h->timefreeze++;
}else{
h->timefreeze=0;
}
h->opx=x; h->opy=y;

h->x=x;
h->y=y;
}
//! fait bouger un gars
void agir(ham *h){
int i;

printf("747---HAMSTER %d -- %d-- mission : %d, (%d, %d) %d\n",
   h->id, h->traverse, h->mission, h->mtx, h->mty, h->utile);

for (i=0;i<h->used_ordres;i++){
h->actions[i](h, h->toD[i]);
}
}
//! dit si un hamster veut deja aller en cette position
int people_has(int x, int y){
int i;
for(i=0;i<HAMSTER_NOMBRE; i++ ){
if (hamster[i].mtx ==x && hamster[i].mty == y) return 1;
}
return 0;
}


//! fonction qui trouve une pomme interessante a ramenner
int findPomme(ham *h){
int x, y, bx=-1, by=-1, minT=9999, d;
for (x=0;x<sx; x++){
for (y=0;y<sy;y++){
if ((!macase(x, y)) && NORMAL == map[x][y].sol && pomme(x, y)){
if (people_has(x, y)) continue; // si qqn s'occupe deja de cette pomme
  d=distance(x, y, h->x, h->y, h->traverse);
if (d < minT){
   bx=x; by=y; minT=d;
  }
}
}
}
//printf("747---pomme interessante en %d, %d (%d, %d, t=%d)\n",
// bx, by, h->x, h->y, minT);
h->mtx = bx;
h->mty = by;
if (h->mtx == -1 && h->mty == -1){
h->mtx=0; h->mty=0;
// on a deja toutes les pommes
return 0;
}else{
return 1;
}
}
//! applique une direction a une position
void applyDir(int x, int y, int d, int *dx, int *dy){
switch(d){
case HAUT:
*dy=y-1; *dx=x;
break;
case GAUCHE:
*dy=y; *dx=x-1;
break;
case BAS:
*dy=y+1; *dx=x;
break;
case DROITE:
*dy=y; *dx=x+1;
break;
default:
printf("747---ERREUR DE PARAMETRE %d\n\n", __LINE__);
break;
}
}
//! dit si un hamster est en x, y (donc si on le pousserait en y allant)
int jepousse(int x, int y){
int i;
for (i=0;i<3;i++){
if (hamster[i].x==x && hamster[i].y==y){
return 1;
}
}
return 0;
}
//! cherche la direction pour aller a h
int allera(ham *h){
int i, p=ICI, x, y, dmin=-1, d;

if (h->x==h->mtx && h->y==h->mty)
return ICI;
for (i=0;i<4;i++){
applyDir(h->x, h->y, i, &x, &y);
if (jepousse(x, y)) continue; // on interdit de pousser son partenaire
if (isValidPos(x, y)){
// fake pour eviter les cases tranchees
d= distance(x, y, h->mtx, h->mty, h->traverse)*2 + (map[x][y].sol!=NORMAL);
if (dmin==-1 || d < dmin){
  //printf("747---d = %d %d\n", d, i);
  dmin=d;
  p=i;
}
}
}
return p;
}

// organise le retour a la maison d'une pomme
void retour_maison(ham *h){
int d;

if (!porte_pomme(h->id)){
//h->mission = CHERCHER_POMMES;
//decider(h);
//return;
}

//printf("747--- Retour maison\n");
// on definit la nouvelle destination
h->mtx=0; h->mty=0;
while (pomme(h->mtx, h->mty) || NORMAL != map[h->mtx][h->mty].sol ){
h->mtx++;
if (h->mtx==sx){
h->mty++; h->mtx=0;
}
//printf("747--- CASE NOT EMPTY !!! %d %d\n", h->mtx, h->mty);
}
d=allera(h);
if (d==ICI){ // si tu deposes la pomme
//printf("747--- Bienvenu a la maison !\n");
h->actions[h->used_ordres]=lacher;
h->toD[h->used_ordres]=d;
h->used_ordres++;
h->mission=CHERCHER_POMMES;
}else{ // deplacement vers la maison
//printf("747--- On va en %d %d\n", h->mtx, h->mty);
h->actions[h->used_ordres]=aller;
h->toD[h->used_ordres]=d;
h->used_ordres++;
applyDir(h->x, h->y, d, &h->x, &h->y);
}
}

//! protege les pommes
void blinde_home(ham *h){
//printf("747---On blinde nos pommes\n");
int d;

while (NORMAL != map[h->mtx][h->mty].sol ){
h->mtx++;
if (h->mtx==sx){
h->mty++; h->mtx=0;
}
}
// printf("747---On sait ou on va\n");
d=allera(h);
if (d==ICI){ // si tu dois changer de mission
h->actions[h->used_ordres]=patienter;
h->toD[h->used_ordres]=d;
h->used_ordres++;
h->mission=CHERCHER_POMMES;
}else{ // deplacement vers la maison
h->actions[h->used_ordres]=aller;
h->toD[h->used_ordres]=d;
h->used_ordres++;
applyDir(h->x, h->y, d, &h->x, &h->y);
}
}

//! dit si les cases sont a cote ou non
int isnear(ham *h1, ham *h2){
int ax=mabs(h1->x - h2->x);
int ay=mabs(h1->y - h2->y);
return (ax==0 && ay==1 ) || (ax==1 && ay==0);
}
//! donne la direction pour aller d'un point a un autre
int directionde(int x1, int y1, int x2, int y2){
if (y1<y2) return BAS;
if (x1<x2) return DROITE;
if (y1>y2) return HAUT;
return GAUCHE;
}
//! pose un grapin
void ograppiner(ham *h1, ham *h2){
printf("747--- grappin %d ----) %d\n", h1->id, h2->id);
h1->actions[h1->used_ordres]=grappiner;
h1->toD[h1->used_ordres]=directionde(h2->x, h2->y, h1->x, h1->y);
printf("747--- On grapine en %d\n", h1->toD[h2->used_ordres]);
h1->used_ordres++;
}
//! renvoie la direction opposee
int oltherd(int d){
switch (d){
case HAUT: return BAS;
case BAS: return HAUT;
case DROITE: return GAUCHE;
case GAUCHE: return DROITE;
default: return ICI;
}
}
//! fonction principale de suivit d'une unitee
void suivre_p(ham *h1, ham *h2){
printf("747---Suivre\n");
int d;
h1->traverse=1;
h1->mtx = h2->x;
h1->mty = h2->y;
if (isnear(h1, h2)){
if (map[h2->x][h2->y].sol!=NORMAL){
d=directionde(h1->x, h1->y, h2->x, h2->y);
  h1->mission=GRAPPINER;
  h1->s=h2->id;
  h1->m=0;
return;
}else{
d=ICI;
}
}else{
d=allera(h1);
}

if (d==ICI){
printf("747--- t'es sur le mec que tu suis...\n");
h1->actions[h1->used_ordres]=patienter;
h1->toD[h1->used_ordres]=ICI;
h1->used_ordres++;
}else{
h1->actions[h1->used_ordres]=aller;
h1->toD[h1->used_ordres]=d;
h1->used_ordres++;
applyDir(h1->x, h1-&