vendredi 22 février 2008

Galerie Cod'Art

Une très bonne initiative : des membres du Site du Zéro ont réalisé une galerie des "oeuvres" de l'Atelier Cod'Art, qui avait eu lieu l'été dernier sur ce site. Le but était de découvrir la programmation graphique, c'est à dire générer des images (ou animations) uniquement via du code et de les présenter avec leur source. Il y a eu beaucoup de fractales bien sûr, mais beaucoup de choses originales aussi. L'aspect visuel de certaines réalisations est vraiment superbe et plusieurs font de bons fonds d'écran.

Pour ma part, j'avais fait un peu original en présentant une petite version du jeu de la vie de Conway (gif ci-dessus) avec des couleurs plus ou moins aléatoires (! - c'est pas génial visuellement, mais c'était une des rares animations), en Ruby avec la gem RMagick (binding vers ImageMagick, lib de graphisme très utilisée et disponible pour de nombreux langages). A noter que mon code tournait (à l'époque du moins) sur la version Linux de RMagick, pas celle de Windows (dû à des différences d'avancement de RMagick).

Liens :

mardi 19 février 2008

Et maintenant, quel langage ?

Les habitués de forums de programmation pour débutants (SDZ ?) devraient avoir souri en lisant ce titre... (En effet, ce type de forum voit apparaître avec une fréquence de 2 à 10 par semaine des sujet portant un titre approché de ça : "Quel language choisire svp URGENT ?" le plus souvent).

Blague à part, la question n'est pas idiote. Loin de là.
Quel langage apprendre ?

Des langages !
Beaucoup !

Il y a beaucoup de langages. De plus en plus même (note : je vais parler ici des "vrais langages" de programmation, c'est à dire, à mon sens, ceux qui sont Turing-complet ; pas du HTML, LaTeX, XML ou autres...).

Lesquels sont généralistes ? La plupart.
Lesquels sont spécialisés ou orientés vers une utilisation précise ? La plupart aussi !
Je m'explique : Fortran permet de tout faire (à condition d'être courageux) mais n'a que peu d'intérêt en dehors du domaine scientifique. Ruby est généraliste, mais est surtout employé pour des applications web (Rails...). Python permet de faire de "vrais" programmes mais sera surtout utilisé (dans le monde pro) pour du scripting d'appoint. On cherche encore Ada ailleurs que dans de l'embarqué et le Javascript ailleurs que dans des applis web côté client... Et pourtant, dans l'absolu, tous permettent de faire la même chose.

Les généralistes et les familles

Cela dit, il existe quelques langages qui sont utilisés (utilisables ?) pour à peu près tout : le C++ et le Java. Pas de chance pour eux (ou pour moi !), je ne les apprécie pas outre mesure. Sans être allergique au C++ que j'ai déjà utilisé en milieu professionnel, je trouve qu'ils sont assez proches et assez lourds (j'ai déjà le Fortran à la maison, merci !) : je reconnais sans problème leurs qualités respectives, mais ils ne conviennent pas, à mon sens, pour un usage domestique/éducatif/récréatif. De plus il ne recèlent pas ou peu de concepts nouveaux pour moi (même si ça ne me ferait pas de mal de revoir la gestion des pointeurs et références en C++ et deux, trois petites choses...).

Dans le même ordre d'idée, je pourrais me mettre au Python. Mais comme il est très proche de Ruby, à quoi bon ? Me taper les différences de syntaxe et de convention pour faire les mêmes choses qu'en Ruby mais en Python ? Pas assez rentable à mon goût ! Je pense, ou plutôt espère, que connaître un langage dans une "catégorie" facilite et accélère l'apprentissage des langages proches, en cas de nécessité. Par exemple pour Ruby : Python, Perl, Groovy, Smalltalk...

Coder, pourquoi ?
Coder plus pour gagner plus...

Car si je code, ce n'est pas que pour le plaisir.

C'est vrai qu'après des débuts difficiles, je me suis mis à apprécier de plus en plus la programmation, pour pas mal de raisons. D'abord pour l'aspect mathématique assez fort que j'y retrouve. Ensuite pour le côté "Lego" : il y a un aspect "architectural" dans la construction d'un programme, des contraintes mais aussi une grande liberté devant son éditeur de texte (un peu comme face aux briques), et une fois terminé on peut "jouer avec" son programme. Enfin, c'est un monde riche en "concepts" liés à l'image que l'on (l'homme et/ou la machine) se fait d'un problème et de sa résolution.

Mais la programmation, c'est aussi une partie importante de mon métier (ingénieur modélisation - bon, ok, pas en ce moment, mais je vais trouver ^^). Et dans ce contexte, à mon niveau, il n'est pas question de choix. On travaille avec le(s) langage(s) qu'on nous donne. Et c'est là que ça se gatte... Dans le domaine de la simulation et analyse numérique, sont surtout utilisés le Fortran et le C++, que je maîtrise "relativement" bien. Les informations glanées sur le web, au cours d'entretiens, etc... ont mis en lumière d'autres "technologies" possibles : Matlab, VisualBasic, C et Ada principalement.
  • Je pourrais me mettre au Matlab mais c'est pas gratuit, même s'il existe SciLab dans le genre...
  • L'environnement VisualBasic, malgré tout le mal que j'en pense, a été installé sur ma bécane... moins d'une heure. Déjà, les IDE m'insupportent, alors quand on ajoute un helper autiste et des tutos qui commencent par "Comment insérer un copyright dans votre programme" (véridique : cherchez sur le web !) et enchaîne sur "Créer un menu dans une fenêtre", ça fait beaucoup. Sans rire, ce genre de truc est extrêmement dangereux pour le PC d'un gars comme moi... Dix minutes de plus et je transperçais l'écran à coup de tête. Dangereux je vous dis !
  • C après C++, connaissant le Fortran ? Mouais...
  • Ada serait sans doute le plus intéressant, mais il y a peu de chance qu'il me serve en milieu professionnel, vu qu'il est le plus souvent dédié au systèmes embarqués (domaine intéressant, mais un peu loin de ma branche).

L'utilisation éventuelle d'un langage en entreprise m'aide donc peu.

Concept ?
Aqui lo paradigme !

Il reste les "concepts".
Cela fait déjà un bon moment que le monde de la programmation fonctionnelle me fascine : attraction/répulsion.
Attraction car c'est une grande famille de langages, de LISP à Haskell en passant par Scheme et OCaml avec des méthodes intéressantes.
Répulsion car jusqu'ici, j'ai toujours été incapable de "décrypter" le moindre bout de code fonctionnel aperçu ici ou là : crispant.
Il y a aussi d'autres "concepts" (paradigmes en l'occurrence ici) : logique (PROLOG), concurrent (Ada, encore !), par contrainte...

Finalement...
Tout ça pour ça...

Finalement, c'est par hasard que je me suis mis... au Scheme.
Un article, chez RubyInside, décrivait un interpréteur pour Scheme, codé en Ruby, dans le bus. J'ai voulu tester. Du coup, il m'a fallu taper un peu de Scheme ; du coup, j'ai lu du Scheme ; du coup je me suis mis à comprendre un peu le Scheme ; du coup, j'apprends le Scheme.
Pour être tout à fait franc, ce langage faisait déjà parti de ceux qui me tentaient fortement, avec le LISP, l'OCaml, Io et Cobol (non, pour le Cobol, j'd3conne !).
Io a perdu car je voulais voir autre chose que de l'OO. Quite à se lancer dans le fonctionnel, autant prendre un langage "simple" : l'OCaml me semblait "trop riche" car multi-paradigme. Enfin, le LISP a eu un petit désavantage : cette citation de G. Chaitin sur la "pureté" d'un langage.
Scheme donc, avec l'interpréteur MzScheme (Bus-Scheme, celui en Ruby étant... peu utilisable ?).

Effectivement, Scheme est austère. Mais il semble reconnu pour son côté pédagogique et est (hormis pour les parenthèses) assez bref dans sa syntaxe : il y a une certaine élégance proche des maths je trouve. Il est vieux, mais a un certain charme... et j'avoue que je l'apprends avec un certain plaisir. Et pour ma bonne conscience professionnelle, Scheme est utilisé dans certains codes de calculs industriel, en appoint (bientôt un article sur "Quel(s) langage(s) dans tel programme ?").Que demander de plus ?

Références et Docs :

D'abord, deux textes pleins de sagesse (si si, il y a un rapport avec le reste...) :
L'article sur Bus-Scheme, l'implémentation en Ruby :
Commençons gentiment en Scheme (avec un interpréteur qui marche !) :
Pour tout le reste vu dans cet article, Wikipédia saura répondre... sinon demandez toujours !



lundi 18 février 2008

Ruby : Fiches mémoires

Comme quoi il existe encore des choses qui valent le coup d'être imprimées... La première est une fiche générale sur Ruby (disponible en PDF ou en PNG). La seconde répertorie les options de l'interpréteur en ligne de commande : le genre de trucs qui s'oublie facilement (mais peut se retrouver avec "$>ruby -h"...).

Iterative, recursive ou tail-recursive ?

Théoriquement, la récursion terminale est une forme optimisée de la récursivité : comme on ne s'enfonce que d'un cran dans la pile, on est sensé avoir des performances similaires à une méthode itérative équivalente.

Cependant, comme le montre le petit benchmark suivant, sur le cas simple de la fonction factorielle, Ruby n'optimise pas la récursion terminale, et c'est bien dommage. A noter que le langage fonctionnel Scheme (dont on va reparler très prochainement) a pour spécification de toujours optimiser la récursion terminale. Ruby 1.9 améliore-t-il les performances sur ce point ?

Code :
(testé sous Windows XP ; Ruby 1.8.6)

# Benchmark on factorial function
#Recursive, tail-recursive
#and iterative versions

# Naive recursive version
def fact_rec_naive num
if num == 0
1
else
fact_rec_naive(num-1)*num
end
end

# Tail recursive version
def fact_rec_tail num
def iterer n, acc
if n <= 1
acc
else
iterer(n-1, n*acc)
end
end
iterer(num,1)
end

# Iterative version
def fact_iter num
res = 1
(1..num).each do |i|
res *= i
end
res
end

# Benchmark
require 'benchmark'

Benchmark.bm(15) do |timer|
timer.report('Naive recursive') {
for i in (0...1000)
fact_rec_naive i
end
}
timer.report('Tail recursive') {
for i in (0...1000)
fact_rec_tail i
end
}
timer.report('Iterative') {
for i in (0...1000)
fact_iter i
end
}
end

#=>
# user system total real
#Naive recursive 4.281000 0.062000 4.343000 ( 4.344000)
#Tail recursive 4.735000 0.063000 4.798000 ( 4.812000)
#Iterative 3.640000 0.015000 3.655000 ( 3.672000)





Références :

MetaTricks : référence à une méthode

En Ruby, tout ou presque est objet. Les méthodes sont des objets comme les autres, sauf qu'il n'est pas forcément évident au premier abord d'y avoir accès. Pour cela, on utilise des références, manipulées comme dans le code suivant.

Code :
(Testé sous Windows XP ; Ruby 1.8.6)



class Canard
def initialize name
@nom = name
end

def coin
"Coin coin, I'm #{@nom} !"
end

def Canard.coin2
"Can Can !"
end
end

toto = Canard.new "Dude"

# L'accès à une méthode se fait via +method+
#prenant en argument la référence de la méthode
#(son nom sous forme de string ou de symbol).
hello = toto.method(:coin)
puts hello.call

#(bonus -> arity donne le nombre d'arguments d'une méthode)
puts "To create a new *Canard* needs " \
+ (toto.method(:initialize).arity).to_s \
+ " argument(s)."

# Une liste de références à des méthodes de +Canard+
meths = [:to_s, :to_something_else, :coin, "to_yaml"]

# L'accès se fait ensuite ici encore via +method+
#et l'appel via +call+
meths.each do |meth|
begin
puts "-----------------"
puts "Method #{meth}"
puts (toto.method(meth).call).to_s
rescue
puts "Problem with this method."
next
end
end


Note :

Les manipulations possibles sur les méthodes sont peu nombreuses, mais assez puissantes. Ici on a vu call et arity : unbind permet elle de "dissocier" la méthode référencée de son receveur (ce qui donne un objet de la classe UnboundMethod...)

Documentation :

vendredi 15 février 2008

Itératif ou récursif ? Analytique.

Dans la lignée de l'article de hier, un benchmark du même type sur la suite de Fibonacci. L'intérêt est ici de montrer que :

  • Ruby est lent en récursif : l'appel de fonction est très coûteux en temps cpu (la version 1.9 devrait améliorer ce point, c'est du moins ce qui avait été annoncé).
  • Plus que pour sur le cas de la fonction factorielle, on constate que la version itérative est moins claire (et élégante) que la récursive (certes, c'est en partie de ma faute...).
  • Lorsqu'on a à disposition une solution analytique, on est gentil : on l'utilise ! (d'autant qu'ici elle utilise le nombre d'or... Pourquoi se priver d'esthétisme ésotérique à la Phidias ?)
Le code :
(testé sous Windows, Ruby 1.8.6)



# Benchmark on Fibonacci

include Math
Sqrt5 = Math.sqrt(5.0)

# Recursive version
def fibo_rec n
if n < 3
1
else
fibo_rec(n-1) + fibo_rec(n-2)
end
end

# Analytic version
def fibo_analy n
((1/Sqrt5)*(((1+Sqrt5)/2)**n-((1-Sqrt5)/2)**n)).to_i
end

# Iterative version
def fibo_iter n
if n < 3
1
else
res1 = 1
res = 2
(n-3).times do
tmp = res
res += res1
res1 = tmp
end
res
end
end

# Benchmark
require 'benchmark'

Benchmark.bm(9) do |timer|
timer.report('Iterative'){
100.times do fibo_iter(20) end
}
timer.report('Analytic') {
100.times do fibo_analy(20) end
}
timer.report('Recursive') {
100.times do fibo_rec(20) end
}
end

#=>
# user system total real
#Iterative 0.016000 0.000000 0.016000 ( 0.016000)
#Analytic 0.000000 0.000000 0.000000 ( 0.000000)
#Recursive 1.375000 0.000000 1.375000 ( 1.375000)

mercredi 13 février 2008

Itératif ou récursif ?

Dans la série des questions que je me pose parfois sur la programmation, il y a celle de l'opposition entre méthode itérative et méthode récursive... Dans le cas général, y en a-t-il une de préférable ? Seulement dans certains cas ? Pourquoi ? Laquelle est la plus rapide ? La plus claire ? Etc... Comme ça fait un moment que j'ai envie de découvrir tranquillement le paradigme fonctionnel, ça me parait être des interrogations justifiées.

Pour le cas de Ruby, je peux déjà répondre à la question de la vitesse d'exécution sur le cas trivial de la fonction factorielle grâce à ce petit benchmark :



# Benchmark : recursive vs iterative
# on factorial function

# Recursive version
def factor_rec num
if num == 0
1
else
factor_rec(num-1)*num
end
end

# Iterative version
def factor_iter num
res = 1
(1..num).each do |i|
res *= i
end
res
end

# Benchmark
require 'benchmark'

Benchmark.bm(9) do |timer|
timer.report('Recursive') {
for i in (0...1000)
factor_rec i
end
}
timer.report('Iterative') {
for i in (0...1000)
factor_iter i
end
}
end

#=>
# user system total real
#Recursive 4.266000 0.062000 4.328000 ( 4.328000)
#Iterative 3.312000 0.016000 3.328000 ( 3.360000)

lundi 11 février 2008

Une gem originale : Zyps

Se balader sur RubyForge est souvent assez rigolo... Comme j'ai un peu de temps en ce moment, et que je ne voudrais pas trop "rouiller" des doigts, je cherche des petits projets libres à "étudier" ou même auxquels participer à ma modeste mesure. Du coup, c'est plus ou moins par hasard que je suis tombé sur la gem Zyps.

Présentation :

Il s'agit d'une gem 100% Ruby qui se présente comme étant une petite lib permettant de créer des "jeux" avec des "créatures" agissant d'elles-mêmes. Le lexique employé ici est plus à relier au jeu de la vie de Conway qu'à WoW : il s'agit en fait de petites simulations plutôt que de jeu au sens ludique du terme. Je dis "petites" simulations car je ne pense pas qu'il s'agisse d'un "véritable" outil scientifique au sens applicatif du terme (ce n'est que mon avis !). Cependant, cela peut être utile pour tester de petits algos d'IA (déplacements, traque...), éventuellement réviser un peu sa mécanique du point (voir première image ci dessous) et surtout, obtenir de jolies petites animations, parfois assez... artistiques. Chacun ses goûts ^^

La partie intéressante, à mon humble avis, réside dans le comportement des créatures : attraction, répulsion, chasse, fuite, etc... La lib est faite de manière à rendre relativement simple l'implémentation d'un nouveau comportement.

Pour ceux qui veulent tester, une petite application est incluse pour un petit aperçu (pour rappel : "gem install zyps" ou "sudo gem install zyps" sous 'nix pour l'installation) : "ruby zyps-0.7.4/bin/zyps" pour lancer.

En images :

Les 3 créatures grises sont en orbite autour de la bleue (immobile).


Tandis que la créature violette est en rotation,
la jaune l'a prise en chasse, adaptant sa trajectoire à celle de sa proie.


D'un point de vue plus technique, la lib est très OO, se base, pour la GUI, sur WxRuby 2 et utilise également DRb.

A noter que le projet est actuellement à la recherche de développeurs, ne comptant pour l'instant que Jay McGraven dans ses rangs.

Liens :

dimanche 3 février 2008

Programmation poétique - Chapitre V : Drunk Terminal


Welcome into this drunk terminal !
Enter your silly commands, homie !
$>pwd
You mean "pwnd" ain't you ?
Who do you think you're talking to bro' ?
$>cd
$>cd P
Dude, auto-completion is for noobs.
Try to type your repertory name without me...
You lazy nerd !
$>cd Personal
$>ls -lahtr
Can't remember what's on your own "Personal" mess ?
Damn, it suxxx !
$>whoami
LooL !
You need a shrink dude !
Stop wating my time: you got a phone call to do !
$>exit
Was waiting for this !
I'm gonna drink some beer...
See you next time, bro.
$>_

samedi 2 février 2008

Geekeries diverses

Des trucs de geek quoi...

Les Chuck Norris Facts sont des aphorismes à la gloire du tout puissant Chuck Norris. Les plus geekesques :


  • Chuck Norris compile ses codes sources à la main.
  • Chuck Norris a plus de droits que root sous linux.
  • Chuck Norris joue à DNF avec un clavier OLED sous linux.
  • Quand Chuck Norris utilise Windows, il ne plante pas.
  • Chuck Norris a une touche Windows sur son Mac.
  • Chuck Norris a lu la base de registre Windows en entier. Deux fois.
  • Il n'y a pas de touche "control" sur l'ordinateur de Chuck Norris. Chuck Norris a TOUJOURS le controle.
  • Chuck Norris a déjà compté jusqu'à l'infini. Deux fois.
  • Chuck Norris peut diviser par zéro.
  • ...
En faisant une petite recherche sur le pixel art (on en reparlera), je suis tombé sur un article sur Space Invaders chez fluctuat.net avec ça ! Bon reflet d'une autre époque... Est-ce que bientôt on aura un remake en Barbarian Terrorists Form the Hood ? Pas sûr... quoi que.


Grosse actu en ce moment chez Motion Twin (dont on a déjà parlé ici et ) :
  • Sortie de Carapass : le jeu qui prend le moins de temps au monde... Dérivé de Marbil's sur CaféJeu (que j'aime beaucoup).
  • Début de la béta de Conquisla en traître.
  • Arrivée prochaine (annoncée depuis un peu longtemps maintenant !) de Hordes. A noter que ce sera le premier jeu de la MT réservé aux adultes, avec des zombis et des tondeuses à gazon... Petite image en exclu (ou pas !) :

Un bon petit MMORPG par navigateur, entre Harry Potter, Zelda et Pokémon : Adelian. En V2, s'il vous plaît ! Développé par Studio-Gamboo, des ptits jeunes qui n'en veulent. Si vous testez, passez voir le prof d'histoire de l'académie... Vous me direz si quelque chose vous saute aux yeux ou pas.


En passant, une BD, pas toute neuve, que je classe dans la catégorie des mangas qui m'empèchent de dire qu'en général les mangas c'est débile (aux cotés d'Akira, Gon, Apple Seed, Ghost in the Shell, Fleur de Pierre et d'autres...) : Quartier Lointain. Mélancolique et très... délicat ? fin ? Le dessin réaliste est très net et riche à la fois et l'histoire à la fois touchante et profonde sans être vraiment larmoyante. Excellent donc.


Les images de cet articles appartiennent à leur propriétaires respectifs (aucune n'est de moi). Etonnant non ?