\documentclass[a4paper]{article}

\title{Concours de programmation 2005\\I.U.T. De Lens} \date{3 Mars 2005}

\usepackage[latin1]{inputenc} \usepackage[T1]{fontenc} \usepackage[french]{babel} \usepackage{verbatim} \usepackage{graphicx}

\begin{document}

\maketitle{} \newpage

\tableofcontents{}

\newpage

\section{Les circonstances}

Vous êtes ingénieur en robotique dans une entreprise multinationnale chargée du traitement de la \textbf{stallmanite}, matériel destiné à la fabrication des femtoprocesseurs supercordoïdaux.

Mais la société est en péril : suite aux conséquences désastreuses du bug de l'an 65536, les machines sont devenues complètement imprévisibles et menacent de faire chuter les fragiles paquets remplis à ras-bord de stallmanite de première qualité !

Complètement affolé, votre patron en personne vous appelle au beau milieu de votre réveillon, en proposant à qui sauvegardera les précieux paquets une prime colossale, jamais vue depuis les pots de vins de Microsoft (empire féodal tyrannique)

Par conscience professionnelle (et aussi un peu pour la prime), vous vous armez de courage face aux robots devenus fous.

\section{Plus sérieusement}

Votre but est de programmer un plugin pour un jeu dont le but est de déplacer des paquets dans des champs de tapis roulants. Ce document présente toutes les informations nécessaires à la bonne compréhension des règles du jeu, ainsi que pour programmer les plugins.

\section{Éléments du jeu}

La zone de jeu se présente comme décrit sur la figure 1 (voir page suivante).

\begin{figure}[h!] \centering \includegraphics[scale=0.6]{iaiut.eps} \caption{Zone de jeu} \end{figure}

\begin{enumerate} \item L'usine \item Zones neutres \item La zone du joueur \textit{bleu} \item Un paquet \item Le faisceau de contrôle du joueur \textit{vert} \end{enumerate}

\subsection{Les surfaces}

\subsubsection{L'usine} L'usine est le lieux d'où arrivent les paquets. Elle est située exactement au centre de la surface de jeu globale.

\subsubsection{Surface de jeu globale} On entend par ce terme la surface de jeu totale, c'est-à-dire qui s'étend d'en haut à gauche jusqu'en bas à droite de la partie de l'écran utilisée par le jeu.

\subsubsection{Surface de jeu locale} Chaque joueur possède une surface de jeu locale qui lui est propre, caractérisée par une colorisation rouge, verte, bleue ou jaune.

\subsection{Les zones}

\subsubsection{Zone neutre} Les zones neutres sont les tapis roulants qui n'appartiennent à aucun des joueurs. C'est les seuls tapis qui ne sont pas colorés. Chaque surface de jeu locale est limitée par deux zones neutres.

\subsubsection{Zone neutre d'origine} La zone neutre d'origine est la zone neutre d'où proviennent les paquets qui rentrent dans une surface de jeu locale.

\textit{Exemple} : la zone neutre d'origine du joueur rouge est composée des quatre cases grises directement sous la surface de jeu locale rouge.

\subsubsection{Zone neutre de destination} La zone neutre de destination est la zone à l'extrémité d'une surface de jeu locale où les paquets une fois engagés ne peuvent plus y revenir.

\textit{Exemple} : La zone neutre de destination du joueur rouge est composée des quatre cases grises directement à droite de la surface de jeu locale rouge.

\subsubsection{Zone hors jeu} Les zones aux extrêmitées de la surface de jeu globale, représentées en noir, sont dites zones hors jeu.

\subsection{Les tapis roulants} La plus grande partie de la surface de jeu est remplie de tapis roulants. Certains de ces tapis roulants sont uni-directionnels, d'autres sont bi-directionnels.

\subsubsection{Tapis roulant uni-directionnel} Un tapis roulant uni-directionnel roulera toujours vers la même direction, quoi qu'il arrive.

\subsubsection{Tapis roulant bi-directionnel} Les tapis roulants bi-directionnels, sous l'effet d'un joueur ou d'un paquet, sont susceptibles de changer de sens. Si l'un d'eux se déplaçait de haut en bas, il se déplacera à présent de bas en haut.

\subsubsection{Tapis bi-directionnels liés} La zone neutre d'origine contient des tapis bi-directionnels liés entre eux.

\textit{Exemple} : Pour le joueur rouge, les trois tapis les plus à gauche de l'écran dans la zone neutre d'origine sont liés. L'un d'entre eux, le tapis actifs, va vers la zone de jeu locale du joueur. Les deux autres, les tapis passifs, vont vers une zone hors jeu. Lorsqu'un paquet est redirigé par le tapis actif, un nouveau tapis actif sera sélectionné aléatoirement parmis les quatre tapis actifs disponibles, et les autres tapis deviendront passifs.

Notez bien que sur les cinq tapis constituants la zone neutre d'origine, celui le plus proche de l'usine n'est pas lié aux autres mais unidirectionnel.

\subsection{Les paquets} Des paquets se déplacent sur les tapis roulants. Un paquet arrivant sur un tapis roulant sera redirigé vers la direction indiquée par ce tapis. Par rétroaction, si ce tapis est bi-directionnel, le sens de ce tapis sera inversé.

\subsubsection{Perdre un paquet} Si un paquet sort de la surface de jeu globale pour "tomber" dans une zone hors jeu, celui-ci est perdu et disparaît.

\subsubsection{Déplacer les paquets} En inversant judicieusement le sens de certains tapis roulants, les joueurs doivent être capables de superviser le déplacement des paquets.

\subsubsection{Collision de paquets} Il y a collision de paquets lorsque le déplacement de deux paquets les conduit au même emplacement. Lors d'une collision, les paquets rebondissent l'un sur l'autre et reviennent à leur emplacement initial.

\subsubsection{Redirection d'un paquet} Un paquet apporté par un joueur dans sa zone neutre de destination se verra redirigé vers la zone neutre d'origine du joueur adjacent.

\subsubsection{Bug de collision} Malgré tout le soin apporté au programme, un bug de collision persiste. Lors d'une collision, les paquets reviennent chacun à leur cases initiales. Si ce retour provoque à nouveau une collision avec un autre paquet, la collision n'a pas lieu et les paquets deviennent confondus.

Afin de palier à ce bug, l'un des paquets est immédiatement détruit, et son total de points est ajouté au paquet confondu. De cette façon, le joueur concerné ne perdra aucun point suite aux conséquences de ce bug.

\subsection{Le Joueur} Le joueur est représenté par les faisceaux de lumières plus intenses que l'on trouve sur la surface de jeu locale d'un joueur.

\subsubsection{Position d'un joueur} La position d'un joueur est la position de l'intersection des deux faisceaux de lumières.

\subsection{Les coordonnées}

\subsubsection{Coordonnées globales} Les coordonnées globales sont les coordonnées génériques, utilisées pour représenter la totalité de la zone de jeu. L'origine du repère est le point en haut à gauche de l'écran. Les coordonnées progressent d'elles-mêmes, vers la droite pour les abscisses et vers le bas pour les ordonnées.

\subsubsection{Coordonnées locales} Les coordonnées locales sont les coordonnées relatives à votre surface de jeu locale. L'origine est l'angle de votre surface de jeu locale située vers l'angle de la surface de jeu globale le plus proche de vous. Le repère est orienté en fonction de votre couleur.

Les coordonnées locales considèrent en réalité que vous êtes toujours le joueur rouge. Le repère sera rapporté au repère rouge, quel que soit votre position sur la zone de jeu.

Les coordonnées locales ne prenant en compte qu'une seule zone, il est impossible d'accéder hors de la surface de jeu locale par les coordonnées locales. Les coordonnées locales couvrent toute la surface de jeu locale, plus les tapis roulants en zone neutre directement adjacents à votre surface de jeu locale.

\subsubsection{Changement de position} La première actions consiste à déplacer le faisceau de lumière dans l'une des quatre directions standards (droite, haut, gauche, bas).

\subsubsection{Inversion de tapis} La seconde action disponible consiste à inverser le tapis roulant situé sur la position du joueur.

\section{Les règles du jeu}

\subsection{But du jeu} Le but du jeu est d'apporter un maximum de paquets de la zone neutre d'origine jusqu'à la zone neutre de destination.

\subsection{Unité atomique} L'unité de base utilisée est la case. Il n'est pas possible (et il est totalement inutile) de mesurer une distance plus petite qu'une case.

\subsection{Rounds} Une partie contient un nombre de rounds pré-défini. Chaque round dure un certain nombre de secondes. On peut observer le round actuel par le nombre en blanc situé en haut au milieu de l'écran.

\subsection{Tour} Un tour de jeu représente le temps qu'un paquet met pour aller d'un tapis roulant à l'autre. Pendant un tour de jeu, chaque joueur est capable d'effectuer certaines actions.

\subsection{Action} Le programmeur peut, à l'aide des API présentées ci-dessous, faire effectuer à son joueur certaines actions.

\subsection{Nombre d'actions par tour} Chaque tour de jeu, le joueur commande une et une seule action.

\subsection{Passer son tour} Cette action consiste à passer son tour sans réaliser aucune autre action. Notez que si aucune action n'a été donnée a réaliser à la fin du plugin, le passage de tour sera choisi par défaut.

\subsection{Durée du jeu} Une partie durera environ 5 minutes. Durant ces minutes se dérouleront un nombre défini de rounds (communiqué en début d'épreuve). Un jeu complet contient en général 2 à 4 parties, ce qui fait un total d'environ 10 à 20 minutes.

\subsection{Gagner des points} Chaque paquet rapporté en zone de destination permet de gagner un nombre de points variable.

\subsection{Augmentation du score d'un paquet} Un paquet sortant de l'usine vaut 10 points. A chaque fois que ce paquet est apporté dans la zone de destination d'un joueur, sa valeur augmente de 10 points. Plus un paquet est vieux sur le terrain de jeu, plus sa valeur est grande.

\subsection{Débit de paquets} Le débit des paquets est déterminé en fonction du round actuel. Selon le round courant, les paquets sortiront de l'usine à un intervalle de tours donné. Durant les premiers rounds, le débit de paquets est faible, mais accélère au fil des rounds qui passent.

\textit{Exemple :} \begin{itemize} \item Round 1 : 1 paquet tous les 12 tours \item Round 2 : 1 paquet tous les 8 tours \item Round 3 : 1 paquet tous les 4 tours \end{itemize}

\subsection{Dysfonctionnements} Si votre plugin contient des erreurs qui entraînent son arrêt (erreur de segmentation, erreur mathématique, etc...) ou des boucles/fonctions récursives infinies, le programme mettra immédiatement fin à son exécution. Si une action a été déclenchée avant le plantage, celle-ci sera annulée et le tour sera perdu. Si une variable a été enregistrée grâce aux fonctions SaveInt/SaveTab (voir plus loin), cette variable sera conservée.

\subsection{Fin du jeu} Le jeu se termine au bout d'un temps donné. On peut observer un compte à rebours en blanc en bas au milieu de l'écran indiquant le temps restant avant la fin du jeu.

\subsection{Vainqueur} Le vainqueur est celui qui possède le plus de points à la fin du temps requis.

En cas d'ex-aequo, une partie sera relancée avec les joueurs à départager. Le premier joueur qui apportera un paquet à destination sera déclaré vainqueur. Si les deux joueurs apportent un paquet en même temps, on attendra le paquet suivant, jusqu'à ce qu'un joueur apporte un paquet avant l'autre.

\section{Programmer les IA}

Afin de sauver un maximum de paquets, vous aurez besoin de programmer les actions des faisceaux de lumière.

Vous disposez pour cela de certains outils pour observer le déroulement du jeu, et d'autres pour assigner des actions.

Les programmes doivent être réalisés en langage C++. Toutes les extensions du langage peuvent être utilisés. En revanche, aucune bibliothèque autre que celle présentée ci-dessous n'est autorisée. On tolérera cependant l'utilisation de fonction d'affichage sur la sortie standard, telles que \textit{cout} ou \textit{printf}, pour faciliter le débugage des IA des joueurs. En revanche, aucune de ces fonction ne devra plus être présente lors de la remise des IA à la fin du concours.

Le nom de la bibliothèque utilisée est "ia\_user.h". Toute IA créée devra donc commencer par la ligne : \#include "ia\_user.h"

Puisque vous réalisez une extension d'un programme déjà existant, et non pas un programme indépendant, vous ne devez pas réaliser une fonction main, mais une fonction appelée IaMain que vous devrez écrire de la façon suivante :

\begin{verbatim} extern "C" void IaMain() { ... } \end{verbatim}

En annexe vous trouverez un exemple très simple d'IA programmée.

\section{Utilisation de Stallmanite}

\subsection{Compilation des IA}

Toute IA devra préalablement être compilée avant d'être utilisée. Étant donné les options fastidieuses à fournir au compilateur g++ pour permettre cette compilation, un script nommé "cstlm" a été créé pour automatiser la tâche. Vous pourrez l'appeler simplement grâce à la ligne de commande :

\begin{verbatim} cstlm fichier_source \end{verbatim}

\textbf{fichier\_source} devra être remplacé par le chemin du fichier à compiler. Seules les extensions de fichiers \textit{.cc} et \textit{.cpp} sont supportées par le script. Votre plugin devra impérativement avoir le nom de votre login. L'utilisateur de nom \textbf{jdoe} devra donc avoir un fichier source nommé \textit{jdoe.cpp} (ou \textit{foo.cc})

\subsection{Exécution du programme}

Pour exécuter le programme, vous devrez utiliser la commande "stallmanite" utilisée de la façon suivante :

\begin{verbatim} stallmanite login [login] [login] [login] \end{verbatim}

L'argument \textbf{login} devra être votre nom d'utilisateur, qui est aussi le nom de votre IA. Le premier login entré sera le joueur rouge, le second sera le joueur bleu, le troisième le joueur vert et le quatrième sera le joueur jaune. Un seul joueur est obligatoire. Si la partie n'est pas complète, les tapis des joueurs manquants seront réorientés pour passer automatiquement tous les paquets à sa charge au joueur suivant. Les points de ce paquet ne seront pas augmentés après passage dans la zone de jeu du joueur absent.

\section{Programmer}

\subsection{Le Type vector}

La structure vector permet de représenter une position sur la zone de jeu à l'aide de ses coordonnées (abscisses et ordonnées) :

\begin{verbatim} typedef struct { int x; int y; } vector; \end{verbatim}

\subsection{Le Type packet}

\begin{verbatim} typedef struct { vector pos; int score; int direction; } packet; \end{verbatim} \begin{itemize} \item \textbf{pos} représente la position sur le terrain de jeu du paquet ; \item \textbf{score} représente le nombre de points qui sera rapporté si le paquet est amené à destination ; \item \textbf{direction} est la direction actuelle du paquet (qui n'est pas forcement - et même rarement - celle du tapis roulant sous lequel il se trouve). \end{itemize}

\subsection{Constantes fondamentales}

\begin{verbatim} int RED int GREEN int BLUE int YELLOW \end{verbatim}

Représentent les quatre joueurs différents.

\begin{verbatim} int UNCOLOR \end{verbatim}

Ne représente aucune couleur (généralement utilisé pour signaler un territoire neutre).

\begin{verbatim} int RIGHT int TOP int LEFT int BOTTOM \end{verbatim}

Représentent les quatre directions utilisées.

\begin{verbatim} int NOTHING \end{verbatim}

Aucune direction. Généralement utilisé pour représenter un tapis roulant statique.

\begin{verbatim} int MAX_ROUND \end{verbatim}

Nombre de rounds avant la fin du jeu.

\begin{verbatim} int MAX_TIME \end{verbatim}

Temps total au début de la partie, en secondes.

\begin{verbatim} int LOCAL_SIZE \end{verbatim}

Nombre de cases de coté comprisent dans une surface de jeu locale.

\subsection{Autres constantes}

\begin{verbatim} int BORDER_SIZE \end{verbatim}

Représente la taille des bords, soit les parties de la surface de jeu qui n'ont pas de tapis roulants et où les paquets sont susceptibles d'être perdus (en général égale à 1).

\begin{verbatim} int MIDDLE_SIZE \end{verbatim}

Représente la largeur des zones neutres (en général égale à 2).

\begin{verbatim} int TERRAIN_SIZE \end{verbatim}

Représente la taille totale du terrain (égal à \textbf{BORDER\_SIZE} * 2 + \textbf{LOCAL\_SIZE} * 2 + \textbf{MIDDLE\_SIZE}).

\subsection{Manipulation des vecteurs}

\begin{verbatim} vector Vector(int x, int y); \end{verbatim}

Renvoie un vecteur d'abscisse \textbf{x} et d'ordonnée \textbf{y}.

\subsection{Manipulation des paquets}

\begin{verbatim} int NumPacket(); \end{verbatim}

Cette fonction renvoie le nombre de paquets accessibles via vos coordonnées locales. Les paquets des autres joueurs seront donc ignorés.

\begin{verbatim} packet GetPacket(int pos); \end{verbatim}

Cette fonction renvoie le paquet de position \textbf{pos} accessible via vos coordonnées locales. Les paquets des autres joueurs seront donc ignorés. Le premier paquet est le paquet de position 0, et chaque position suivante contient un paquet jusqu'au dernier paquet de la liste.

\textit{ATTENTION} : si la position est supérieure au nombre de paquets - 1, le résultat sera indéfini. Dans le pire des cas, vous pouvez y perdre votre tour.

\begin{verbatim} vector PlayerPos(); \end{verbatim}

Renvoie la position locale de votre joueur.

\begin{verbatim} int Turn(); \end{verbatim}

Renvoie le nombre de tours écoulés depuis le début de la partie.

\begin{verbatim} int Round(); \end{verbatim}

Renvoie le round actuel.

\begin{verbatim} int TimeLeft(); \end{verbatim}

Renvoie le temps restant avant la fin de la partie.

\begin{verbatim} int NewThrow(); \end{verbatim}

Renvoie le nombre de tours restants avant la prochaine distribution de paquets.

\begin{verbatim} int Random(int max); \end{verbatim}

Renvoie un nombre aléatoire compris entre 0 et \textbf{max}-1.

\begin{verbatim} int Score(int player=SELF); \end{verbatim}

Renvoie le score actuel du joueur passé en paramètre (\textbf{RED}, \textbf{GREEN}, \textbf{BLUE} ou \textbf{YELLOW}). Votre score sera renvoyé si vous laissez le paramètre par défaut (\textit{SELF}).

\begin{verbatim} int RollingFloor(vector pos, bool active=true); \end{verbatim}

Cette fonction renvoie la direction actuelle du tapis roulant situé aux coordonnées locales passées en argument. Si la variable \textbf{active} est positionnée à \textit{true}, c'est la direction active du tapis roulant qui sera renvoyée. Sinon, c'est la direction inactive qui sera renvoyée.

Renvoie \textbf{NOTHING} si la zone indiquée n'est pas un tapis roulant, ou si la zone inactive d'un tapis roulant unidirectionnel est demandée.

\subsection{Actions}

\begin{verbatim} void ActionMove(int direction); \end{verbatim}

Permet le déplacement du joueur dans une direction locale passée en paramètre (\textbf{RIGHT}, \textbf{TOP}, \textbf{LEFT} ou \textbf{BOTTOM}).

\textit{ATTENTION} : si vous demandez le déplacement vers une direction hors de la zone propriétaire du joueur, l'action ne sera pas effectuée mais elle sera perdue.

\begin{verbatim} void ActionReverse(); \end{verbatim}

Inverse la direction du tapis roulant situé à la position du joueur.

\begin{verbatim} void ActionPass(); \end{verbatim}

Indique le passage du tour du joueur sans aucune action.

\subsection{Enregistrement des variables}

\begin{verbatim} void SaveInt(string name, int value); \end{verbatim}

Enregistre pour des utilisation ultérieures la variable de type int sous un nom indiqué par \textbf{name}.

\textit{ATTENTION} : \textbf{name} doit pas contenir plus de 8 caractères.

\begin{verbatim} void SaveTab(string name, int *tab, int length); \end{verbatim}

Enregistre pour des utilisation ultérieures un tableau d'entiers de taille indiquée par \textbf{length}, sous un nom indiqué par \textbf{name}.

\textit{ATTENTION} : \textbf{name} ne doit pas contenir plus de 8 caractères.

\begin{verbatim} int* RecoverTab(string name); \end{verbatim}

Renvoie le tableau sauvegardé de nom \textbf{name}.

\begin{verbatim} int RecoverInt(string name); \end{verbatim}

Renvoie l'entier sauvegardé sous le nom \textbf{name}.

\subsection{Utilisation des coordonnées globales}

Ces fonctions, homologues aux précédentes, utilisent les coordonnées globales plutôt que les coordonnées locales. Dans la plupart des cas, il est fortement recommandé de préférer les coordonnées locales aux coordonnées globales. Elles sont beaucoup plus simples à gérer puisque vous n'avez pas à vous soucier de votre position sur la surface de jeu.

Les seuls cas où les coordonnées globales doivent être utilisées sont lorsque vous souhaitez surveiller des paquets qui ne se trouvent pas dans votre surface de jeu locale par exemple pour anticiper leur arrivée dans votre surface de jeu locale.

\begin{verbatim} int Global_NumPacket(); \end{verbatim}

Renvoie le nombre de paquets présents sur la surface de jeu.

\begin{verbatim} packet Global_GetPacket(int num); \end{verbatim}

Renvoie le paquet de numéro indiqué en paramètre.

\textit{ATTENTION} : voir les avertissements de la fonction GetPacket().

\begin{verbatim} vector Global_PlayerPos(int player=SELF); \end{verbatim}

Renvoie les coordonnées globales du joueur dont la couleur est passée en argument (\textbf{RED}, \textbf{GREEN}, \textbf{BLUE} ou \textbf{YELLOW}). Si la valeur par défaut (\textit{SELF}) est utilisée, les coordonnées globales du joueur lui-même seront renvoyées à la place.

\begin{verbatim} int GlobalRollingFloor(vector pos, bool active=true); \end{verbatim}

Renvoie la direction globale du tapis roulant de coordonnées globales indiquées en paramètre. Si la variable \textbf{active} est positionnée à \textit{true}, c'est la direction active du tapis roulant qui sera renvoyée. Sinon, c'est la direction inactive qui sera renvoyée. Renvoie \textbf{NOTHING} si la zone indiquée n'est pas un tapis roulant, ou si la zone inactive d'un tapis roulant unidirectionnel est demandée.

\begin{verbatim} void ActionGlobalMove(int direction); \end{verbatim}

Permet le déplacement du joueur dans une direction globale passée en paramètre (\textbf{RIGHT}, \textbf{TOP}, \textbf{LEFT} ou \textbf{BOTTOM}).

\textit{ATTENTION} : si vous demandez le déplacement vers une direction hors de la zone propriétaire du joueur, l'action ne sera pas effectuée mais elle sera perdue.

\begin{verbatim} vector Glob2Loc(vector glob); \end{verbatim}

Renvoie les coordonnées locales de coordonnées globales passées en paramètre. Si les coordonnées globales sont situées en dehors de la portée des coordonnées locales, les coordonnées (-1,-1) seront renvoyées à la place.

\begin{verbatim} vector Loc2Glob(vector loc); \end{verbatim}

Renvoie les coordonnées globales d'une coordonnées locale passée en paramètre.

\begin{verbatim} int Glob2Loc(int direction); \end{verbatim}

Renvoie la direction locale relative à la direction globale passée en paramètre.

\begin{verbatim} int Loc2Glob(int direction); \end{verbatim}

Renvoie la direction globale relative à la direction locale passée en paramètre.

\begin{verbatim} int Owner(vector pos); \end{verbatim}

Renvoie la couleur du joueur propriétaire de la zone de coordonnées globales indiquées en paramètre. Renvoie \textbf{UNCOLOR} si la position est en zone neutre.

\begin{verbatim} int Color(); \end{verbatim}

Renvoie votre couleur.

\newpage

\begin{appendix}

\section{Exemple d'IA}

\subsection{L'idée} Cette IA repose sur un principe très simple. On part du principe que le seul moyen de perdre un paquet est de voir un tapis roulant orienté en direction du vide. Cette IA primitive promène donc le faisceau aléatoirement, et inverse la direction d'un tapis roulant lorsque celle-ci met en danger un paquet.

\begin{verbatim} #include "ia_user.h"

extern "C" void IaMain() { // La position du joueur est récupérée pour être analysée ultérieurement. vector pos = PlayerPos();

// Si le faisceau ne se trouve pas contre un bord... if(pos.x != 0 && pos.y != 0) { // ... on l'y déplace le plus vite possible. ActionMove(LEFT); } else { // Sinon on récupère la variable sauvegardée précédemment indiquant la // direction actuelle. int direction = RecoverInt("direction"); // Si le faisceau pointe vers un tapis dirigé vers le vide, on inverse // ce tapis. if(pos.x == 0 && RollingFloor(pos, true) == LEFT || pos.y == 0 && RollingFloor(pos, true) == TOP) { ActionReverse(); } // sinon on cherche à déplacer le faisceau. else { // si cette direction n'existe pas, on va vers le bas. if(direction == -1) { direction = BOTTOM; } // sinon, on vérifie la position // si le faisceau est tout en bas, on le déplace vers le haut else if(pos.y == LOCAL_SIZE-1) { direction = TOP; } // si le faisceau est dans le coin haut/gauche, la direction suivante // dépendra de la direction actuelle else if(pos.x == 0 && pos.y == 0) { if(direction == TOP) { direction = RIGHT; } else { direction = BOTTOM; } } // si on est complètement à droite, on repart vers la gauche else if(pos.x == LOCAL_SIZE-1) { direction = LEFT; }

// On se déplace vers la direction déterminée. ActionMove(direction);

// Puis on sauvegarde la direction courante pour la réutiliser // le tour suivant. SaveInt("direction", direction); } } } \end{verbatim}

De nombreuses améliorations peuvent bien entendu être apportées à cette IA. Au lieu de faire des déplacements aléatoires, l'IA pourrait par exemple déterminer le tapis roulant de direction compromettante le plus proche du faisceau, pour ainsi dépenser moins d'actions à se déplacer.

\subsection{Quelques idées de stratégies} \subsubsection{Tout sauver !} Cette stratégie consiste à empêcher les paquets d'arriver dans des situations critiques qui risqueraient de les faires tomber. Il s'agit donc d'inverser prioritairement tout les tapis roulants qui sont dirigés vers le vide, ou qui menacent un paquet de s'approcher du vide. C'est la stratégie utilisée par l'exemple présenté ci-dessus.

\subsubsection{Visez les gros !} Les paquets apportés a bon port par vos adversaires valent généralement beaucoup plus de points que les autres. Rapporter prioritairement de tels paquets vous permet de faire des points plus efficacement que par des paquets standards. Une stratégie pourrait consister à anticiper le trajet de tels paquets pour leur assurer une arrivée à bon port.

\subsubsection{Saisir sa chance} Les paquets peuvent entrer dans votre surface de jeu locale par quatre tapis roulants différents. On constate qu'un paquet qui rentre dans votre surface de jeu locale très près de l'usine se trouve beaucoup plus proche de sa destination. Cette stratégie consiste à ne s'occuper que des paquets qui entrent tôt en jeu, et de leur assurer un chemin tout tracé à destination.

\subsubsection{Perfectionnisme} Ce qui pourrait être sans doute la plus puissante des stratégies serait d'anticiper les trajectoires de tous les paquets présents, ainsi que les paquets futurs qui vous arrivent depuis votre adversaire. Vous n'avez plus qu'à vous servir de ces aptitudes visionnaires pour déterminer les paquets n'ayant pas besoin de votre aide pour arriver à bon port, des paquets destinés à être perdus quoi qu'il arrive, ou des paquets ayant besoin d'un petit (ou gros) coup de pouce de votre part.

\subsection{Note sur les stratégies} La clé de la victoire ne se trouve certainement pas dans l'implémentation directe des stratégies présentées ici. À vous de les adapter, de les combiner, de trouver des solutions à leurs défauts, et bien sûr de trouver vos propres stratégies pour mettre en place l'IA la plus fiable qui vous assurera la victoire.

Cependant, n'ayez pas trop d'ambition : il vaut mieux une petite IA terminée et débuggée qu'une usine a gaz prévoyant toute les situations sur 60 coups à l'avance mais que vous ne pourrez jamais finir dans les temps.

Pensez également que les ressources restent limitées : vous avez en principe suffisamment de ressources système pour faire à peu près ce que vous voulez, mais si vous en abusez, vous risquez de perdre des tours bêtement.

De même, évitez les boucles infinies et les erreurs de segmentations : elles vous feront perdre votre tour bêtement.

Bonne chance et que le meilleur gagne ! \end{appendix}

\end{document}



This document was generated by Guillaume Libersat on March, 3 2005 using texi2html