Pour ceux qui seraient tentés de continuer, une idée serait de transformer le jeu en course de voitures multi-joueurs dans un labyrinthe. La partie course est tirée du concours de l'ICFP 2003 (International Conference on Functional Programming). Site du concours.
En fait, cela combine labyrinthe et simulation de course. Pour la partie simulation, on part d'équation physique du mouvement qui permette de connaître la position à l'instant suivant en fonction de l'état précédent et d'une commande.
Les commandes possibles sont :
type action = Roll | Acc | Left | Right | Brake | AccLeft | AccRight
Par rapport à ce qu'on a vu jusqu'à maintenant, il est pratique d'utiliser des types structurés pour modéliser l'état d'un véhicule à un instant donné :
type state = {
x : t ; (* position *)
y : t ; (* position *)
v : t ; (* impulsion *)
d : t ; (* angle *)
t : t (* temps *)
}
Remarque : t est un type prédéfini, par exemple float. Dans le cas du concours, il fallait utiliser de l'arithmétique en point fixe, et c'est ce code qui est toujours utilisé (toutes les fonctions de calcul, similaires au float, sont définies dans fpa.ml). C'était plus une contrainte qu'autre chose (pour éviter que quelqu'un ne propose une solution analytique à leur problème : il s'agissait de trouver la séquence de commande la plus rapide sur divers circuits proposés), et il vaut mieux travailler en float.
Il existe deux modes de simulation : un normal, et un "rally" qui autorise les dérapages.
(** normal *)
let next s ac =
let v = s.v -. (f0 +. f1 *. s.v +. f2 *. (s.v *. s.v)) in
let v = max zero (match ac with
`Acc | `AccLeft | `AccRight -> v +. biga
| `Brk -> (v -. bigb)
| _ -> v) in
let d = match ac with
`Left | `AccLeft -> s.d -. (bigt /. (v *. v +. bigl))
| `Right | `AccRight -> s.d +. (bigt /. (v *. v +. bigl))
| _ -> s.d in
let d = bonmod d in
let x = s.x +. (v *. cos d)
and y = s.y +. (v *. sin d) in
{ v = v ; d = d ; t = d ; x = x ; y = y }
(** rally *)
let next_r s ac =
let v = ref s.v
and t = ref s.t
and d = ref s.d
and x = ref s.x
and y = ref s.y
and turn = ref zero
and diff = ref zero
and return = ref false
in
turn := (bigt /. ((!v *. !v) +. bigl)) ;
diff := anglediff !t !d ;
if abs !diff < !turn || !v = zero then t := !d ;
v := !v -. (f0 +. f1 *. !v +. f2 *. (!v *. !v)) ;
let skid =
if t <> d then true
else derape ac
in
if skid then (
turn := ((of_int 2) *: bigt) /. bigl ;
if not (accel ac) then v := !v -. bskid ;
if !v < zero then ( v := zero ; t := !d ; return := true)
else
if accel ac then
let vx = (!v *. cos !t) +. (askid *. cos !d)
and vy = (!v *. sin !t) +. (askid *. sin !d) in
v := sqrt ((vx *. vx) +. (vy *. vy)) ;
t := atan2 vy vx ;
if (anglediff !t !d) *. !diff < zero && abs !diff < pisur2 then t := !d
) else (
if accel ac then v := !v +. biga ;
if brake ac then v := !v -. bigb ;
if !v < zero then v := zero ;
turn := bigt /. ((!v *. !v) +. bigl)
) ;
if not !return then (
if left ac then d := !d -. !turn ;
if right ac then d := !d +. !turn ;
d := bonmod (!d) ;
x := !x +. (!v *. cos !t) ;
y := !y +. (!v *. sin !t)
) ;
if not skid then t := !d ;
{ x = !x ;
y = !y ;
v = !v ;
d = !d ;
t = !t
}
Vous pouvez télécharger le tout début. Pour l'instant, cela ne marche pas encore, c'est juste une base de départ pour vous permettre de démarrer plus rapidement.
Ce code utilise notamment quelques notions qui n'ont pas été abordées en cours :
let coul = function 1 -> `coeur | 2 -> `carreau | 3 -> `trèfle | 4 -> `pique