Skip to content

"In this project, you will create a virtual “arena” in which programs will fight against one another (the “Champions”). You will also create an assembler to compile those Champions as well as a Champion to show the world that you can create life from coffee." [from 42 subject]

License

Notifications You must be signed in to change notification settings

madvid/42_Corewar

Repository files navigation

Projet Corewar:

auteurs: armajchr, mdavid, yaye


Présentation du projet:

[source: pdf du sujet 42]

  • Le Corewar est un jeu très particulier. Il consiste à rassembler autour d’une "machine virtuelle" des "joueurs", lesquels vont y charger des "champions" qui vont se battre à l’aide de "processus", dans le but, entre autres, de faire en sorte qu’on dise d’eux qu’ils sont "en vie".

  • Les processus s’exécutent séquentiellement au sein de la même machine virtuelle, et du même espace mémoire. Ils peuvent donc, entre autre chose, s’écrire les uns sur les autres afin de se corrompre mutuellement, de forcer les autres à exécuter des instructions qui leur font du mal, de tenter de recréer à la volée l’équivalent logiciel d’un Côtes du Rhône 1982, etc ...

  • Le jeu se termine quand plus aucun processus n’est en vie. À ce moment là, legagnant est le dernier joueur à avoir été rapporté comme étant "en vie".

Description d'ensemble:

[source: pdf du sujet 42] Le projet consiste à rendre trois parties distinctes :

  • L’assembleur: le programme qui va compiler les champions et les traduire du langage dans lequel vous allez les écrire (l’assembleur) vers un "bytecode", à savoir un code machine qui sera directement interprété par la machine virtuelle.
  • La machine virtuelle: l’"arène" dans laquelle les champions vont s’exécuter. Elle offre de nombreuses fonctionnalités, toutes utiles au combat des champions. Il va de soi qu’elle permet d’exécuter plusieurs processus en simultané : on vous demande une arène, pas un simulateur de one-man show.
  • Le champion: C’est un cas un peu particulier. Plus tard, pour le championnat, vous allez devoir rendre un champion si puissant et effrayant qu’il ferait trembler de peur un bocalien. Cependant, comme cela constitue en soi un travail conséquent, et que pour l’instant on est juste intéressés par votre capacité à réaliser les autres programmes du Corewar, et que votre champion du moment ne sert qu’à nous prouver que vous savez écrire des bouts d’ASM de Corewar, le champion à rendre dans le cadre de ce projet précis n’a besoin d’effrayer qu’un hérisson neurasthénique.

Présentation du projet:


ASM:

L'exécutable asm est généré à partir de la règle make asm présente dans le Makefile. Comme indiqué précédemment, l'assembleur permet de traduire les fichiers écrits en assembleur (fichier avec extension .s) des champions en bytecode (fichier avec extension .cor).

DASM:

L'exécutable dasm est généré à partir de la règle make dasm présente dans le Makefile. Ce programme est un bonus du projet, il permet de 'desassembler' les fichiers en bytecode (extension .cor) en fichier assembleur (extension .s).

VM:

Deux exécutables sont associés avec la machine virtuelle:

  • corewar,
  • corewar_visu.

Ces exécutables sont générés à partir des règles make corewar et make corewar_visu présentent dans le Makefile. L'exécutable corewar ne gère pas le viualizer accessible via le flag -SDL tandis que l'exécutable corewar_visu gère l'option permettant de lancer le visualizer. L'exécutable corewar_visu fonctionne uniquement sous OS Mac, le visualizer est donc uniquement disponible sous MacOS.

Les options:

Plusieurs options, sous forme de flag, sont disponibles avec l'exécutable corewar:

  • -dump N: option dump, permet d'afficher sur la sortie standard l'état de l'arène au $N^{ieme}$ cycle,
  • -v verbose_lvl: option verbose, permet d'activer la verbose,
  • -SDL: flag permettant de lancer le visualizer au lancement du programme,
  • -m on: option musique, ,

Les ressources:

Fichier op.h:

Quelques explications concernant les macros définies dans le fichier op.h:

Taille des différents arguments:

#define IND_SIZE				2
#define REG_SIZE				4
#define DIR_SIZE				REG_SIZE

IND_SIZE, REG_SIZE et DIR_SIZE correspond à la taille en byte des différents type d'éléments présent dans le fichier en bytecode (*.cor ou dans la zone mémoire de la VM) qui sont:

  • les arguments de type indirect (2 bytes),
  • les arguments de type direct (4 bytes),
  • les registres (4 bytes).

Note sur bit, byte et octet:

Il faut distinguer c'est 3 objets, un bit est la plus petite unité mémoire qui peut avoir comme valeur 0 ou 1, un byte est un ensemble de byte comme un octet. La différence entre un byte et un octet est que l'octet est obligatoirement un ensemble de 8 bits alors que la définition d'un byte ne donne pas le nombre de bit le constituant (à vérifier).


Remarque:

Attention, en se référant aux différents cheat sheet (voir la section bibliographie), on peut être confus en voyant que pour les registres il est parfois évoqué une taille de 4 octets et d'autres fois une taille d'un octet.

Cela vient du fait que dans le fichier bytecode et dans la zone mémoire de la VM, le byte correspondant à un registre correspond à son numéro/son indice, son indice au sein du tableau de registres. Et non pas le contenu du registre.


Taille des différents arguments:

#define REG_CODE				1
#define DIR_CODE				2
#define IND_CODE				3

Sachant que les paramètres d'un opcode (code d'opération en français ?) ne sont pas tous encodés sur le même nombre de bytes, il nous faut savoir comment lire les bytes. Pour cela, après le byte décrivant l'opération, il y a un byte qui décrit le type des arguments de l'opcode:

Valeur binaire Valeur décimale type de l'argument taille en byte associé
01 1 registre 1
10 2 direct 4/2 (int/addresse)
11 3 indirect 2

REG_CODE, DIR_CODE, IND_CODE correspondent aux valeurs décimal des couples de bits dans le byte d'encoding. En lisant chaque couple de bits dans le byte nous connaissons alors le type du premier, second et troisième paramètre de l'opcode. Comme il n'y a qu'au maximum 3 arguments, le dernier couple de bits est donc non utilisé (et doit être donc 00).

Nombre maximum d'argument et de joueurs:

#define MAX_ARGS_NUMBER			4
#define MAX_PLAYERS				4
  • Commençons par MAX_PLAYERS qui est le plus simple à expliquer: il spécifie que le nombre maximum de champion pouvant être présent dans l'arène (mémoire visible lors de l'affichage du champ de bataille) est de 4.
  • Concernant MAX_ARGS_NUMBER [? No information for the moment ?].

Taille de l'arène, modulo de l'index et taille maximale d'un champion:

#define MEM_SIZE				(4*1024)
#define IDX_MOD					(MEM_SIZE / 8)
#define CHAMP_MAX_SIZE			(MEM_SIZE / 6)
  • L'arène est la zone mémoire dans laquelle les codes des champions sont écrits/exécutés. La taille de l'arène est définie par MEM_SIZE et est de 4096 octets.
  • IDX_MOD définie ... .
  • CHAMP_MAX_SIZE définie la taille maximale en octets de chaque champion, si le code du champion dépasse cette taille, c'est une erreur.

** Caractères de spécification du type en assembleur:**

Au sein des fichiers en assembleur, on utilise différents caractères pour spécifier, au compilateur que nous créons, le type de données qui vient à la partie du code faisant l'analyse lexicale. En d'autre mots, au sein de la ligne parsée, le ou les types des éléments sont spécifiés par des caractères précis.

#define COMMENT_CHAR			'#'
#define LABEL_CHAR				':'
#define DIRECT_CHAR				'%'
#define SEPARATOR_CHAR			','
  • COMMENT_CHAR précise que l'élément qui suit est un commentaire,
  • LABEL_CHAR précise que l'élément qui suit est un label,
  • DIRECT_CHAR précise que l'élément qui suit est un paramètre de type direct,
  • SEPARATOR_CHAR précise que l'élément qui suit est un paramètre de type direct,
#define LABEL_CHARS				"abcdefghijklmnopqrstuvwxyz_0123456789"

#define NAME_CMD_STRING			".name"
#define COMMENT_CMD_STRING		".comment"
#define REG_NUMBER				16
#define CYCLE_TO_DIE			1536
#define CYCLE_DELTA				50
#define NBR_LIVE				21
#define MAX_CHECKS				10
typedef char	t_arg_type;

#define T_REG					1
#define T_DIR					2
#define T_IND					4
#define T_LAB					8
# define PROG_NAME_LENGTH		(128)
# define COMMENT_LENGTH			(2048)
# define COREWAR_EXEC_MAGIC		0xea83f3
typedef struct		header_s
{
  unsigned int		magic;
  char				prog_name[PROG_NAME_LENGTH + 1];
  unsigned int		prog_size;
  char				comment[COMMENT_LENGTH + 1];
}					header_t;

Partie VM:

Description du format des fichiers des champions [fichier].cor:

Le contenue d'un fichier correspondant à un champion est en bycode. Ce fichier doit contenir une entête constituée:

  • d'un nombre magique '0x ea 83 f3'. Comme nous pouvons le voir ce nombre magique est constitué de 4 valeurs hexadécimales, chacunes des valeurs hexadécimales représentent 1 byte/octet, le nombre magique occupe donc 4 octets et donc 32 bits.
  • Un ensemble de 128 (PROG_NAME_LENGTH) octets réservé pour le nom du champion.
  • Un padding de 4 octets, qui ont comme valeur NULL,
  • 4 octets donnant la taille (CHP_SIZE) du bytecode du champion (que l'on trouve en dernier).
  • Un champ d'octets correspondant au commentaire d'une taille de 2048 (COMMENT_LENGTH) octets.
  • Un padding de 4 octets, devant être NULL,
  • Un champ de chp_size octets. Nous ne devons trouver rien d'autre a priori, le fichier doit donc être terminé après le code du champion.

Les tailles de plusieurs des champs d'octets étant définies dans le header op.h, la section de code correspondant au parsing doit faire appel à ces définitions. Il est important de vérifier ces champs d'octets lorsque cela est possible, notamment le magic_number ainsi que la valeur des octets constituant les 2 paddings. Pour ce qui est du contenue du nom, commentaire et du code du champion, il a été choisi de ne pas faire de vérification quant à leurs contenus. Cela n'est a priori aucunement gênant pour ces 2 premiers champs, mais pour le dernier des erreurs concernant les valeurs des registres peuvent être présentés par exemple, mais nous ne les vérifierons qu'au moment de l'exécution du code (voir la section correspondante).

Brouillons:

Note sur l'ordre des champions:

cmiran 28 juin 2019 à 18 h 49 cela se traduit par, le joueur ayant le token le plus élevé commence et ainsi de suite jusqu’au token le plus bas, ou simplement le dernier joueur déclaré commence ? 3 réponses

cmiran il y a un an si jamais quelqu’un se pose la meme question..après investigation, et finalement la réponse est toute c*nne, la vm fournie place les champions en mémoire en fonction de l’ordre de déclaration, puis exécute de bas en haut :aussiereversecongaparrot:. ./a.out a.cor -n 1 b.cor -n 2 c.cor -n 3 d.cor b<-c<-d<-a

ndelhomm:génie_homme: il y a un an @cmiran donc si tu as : ./a.out a.cor b.cor -n 1 c.cor d.cor l'ordre sera b, a, c, d ?

cmiran il y a un an c <- a <- b <- d

Bibliographie:

  1. https://docs.google.com/document/d/1DT_47inyTLDEUMevdmsA4jqr3_FXGvgKhzpGv_rtuOo/edit# | Corewar_Cheat_Sheet.pdf (dans le répertoire documentation)

About

"In this project, you will create a virtual “arena” in which programs will fight against one another (the “Champions”). You will also create an assembler to compile those Champions as well as a Champion to show the world that you can create life from coffee." [from 42 subject]

Resources

License

Stars

Watchers

Forks