REV0 C ++ (Visual Studio sous Windows) 405
#include"stdafx.h"
#include<stdlib.h>
#include<time.h>
int main(){srand(time(NULL));char i,h=rand()%19,w=rand()%19,p=19,d=0,q,e,m[]="e@LwQMQOSOLT";while(p-h&&p-w){for(i=3;i--;){q=(p+m[p%4*3+i])%20;if(q==w)puts("you smell a wumpus");if(q==h)puts("you feel a breeze");}scanf_s("%d",&i);e=(d+i/10)*m[p%4]%3;q=(p+m[p%4*3+e])%20;if(i%5){if(q==w){puts("YOU KILLED THE WUMPUS!");h=p;}else{puts("arrow missed");w=(w+m[w%4*3+rand()%3])%20;}}else{p=q;d=e;if(p==h)puts("YOU FELL IN A HOLE!");}if(p==w)puts("THE WUMPUS GOT YOU!");}}
Vous trouverez ci-dessous un scénario de jeu montrant que si vous jouez correctement, vous pouvez toujours gagner (à condition que vous ne commenciez pas juste à côté d'un obstacle). Le joueur ressent une brise, fait demi-tour et fait une boucle complète dans le sens antihoraire. Comme il lui faut exactement 5 coups pour sentir à nouveau une brise, il connaît le trou à sa droite et s’éloigne le plus possible. De même, quand il sent le wumpus, ne sachant pas si c'est à droite ou à gauche, il se retourne et fait une boucle dans le sens des aiguilles d'une montre. Cela lui prend 5 coups pour sentir à nouveau le wumpus, alors il sait que c'est à gauche et tire avec certitude.
S'il avait bouclé dans l'autre sens, il aurait retrouvé le wumpus plus tôt et aurait su que c'était dans la même direction qu'il se retournait.
REV1 C (GCC sur Cygwin), bonus de 431 à 35% = 280,15
#define u(t,s,c) if(t){puts(s);c;}
i,d,e,a,b;main(){srand(time(0));char q,p=19,h=rand()%p,w=rand()%p,*m="e@LwQMQOSOLT-\\/\n \v ";
while(p-h&&p-w){
for(i=3;i--;){q=(p+m[p%4*3+i])%20;u(q==w,"you smell a wumpus",a|=2<<p)u(q==h,"you feel a breeze",b|=1<<p)}
for(i=20;i--;)printf("%c%c",i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),m[i%4+15]);
scanf("%d",&i);e=(d+i/10)*m[p%4]%3;q=(p+m[p%4*3+e])%20;
if(i%5){u(q-w,"arrow missed",w=(w+m[w%4*3+rand()%3])%20;a=0)else u(1,"YOU KILLED THE WUMPUS!",h=p)}
else{p=q;d=e;u(p==h,"YOU FELL IN A HOLE!",)}
u(p==w,"THE WUMPUS GOT YOU!",)}}
Nouvelles lignes ajoutées pour plus de clarté. Les modifications par rapport à la révision 0 sont les suivantes:
Un grand merci à @Dennis pour avoir recommandé le compilateur GCC sur l'émulateur Cygwin Linux pour Windows. Ce compilateur ne requiert pas le include
s dans le programme rev 0, et il autorise le int
type par défaut pour les variables et main.
c’est un conseil de golf qui change la vie!
De plus, tourner sous Linux signifie que \f
le curseur descendra sans faire de retour chariot (contrairement à Windows où il ne produit qu'un symbole imprimable.) Cela a permis de raccourcir considérablement l'instruction printf imprimant le tableau.
Plusieurs conseils supplémentaires de Dennis dans les commentaires, et un des miens: changement de condition lors de la vérification si la flèche touche le wumpus: if(q==w)
> if(q-w)
(..else .. est inversé)
Ajout d'un affichage graphique montrant les informations que le joueur sait sur l'endroit où un wumpus est senti / une brise semble réclamer le bonus de 35%. (J'ai supprimé l'ancienne version de débogage de celle-ci, qui indiquait la position exacte du wumpus et du trou. Elle peut être vue dans l'historique d'édition.)
REV2 C (GCC sur Cygwin), bonus de 389 à 35% = 252,85
#define Q(N) (N+"QTLOQMQOSOLT"[N%4*3+e])%20
#define P printf(
i,d,e,a,b;main(){int p=19,q=srand(&p),h=rand()%p,w=rand()%p;
while(p-h&&p-w){
for(e=3;e--;){q=Q(p);q-w||P"You smell a wumpus\n",a|=2<<p);q-h||P"You feel a breeze\n",b|=1<<p);}
for(i=20;i--;)P"%c%c",i-p?48+(a>>i&2)+(b>>i&1):"-\\/"[d],"\n \v "[i%4]);
scanf("%d",&i);e=(d+i/9)*"edde"[p%4]%3;q=Q(p);
if(i%5){e=rand()%3;w=q-w?P"Your arrow didn't hit anything\n",a=0)&Q(w):(p=20);}
else p=q,d=e;
}
P p-20?p-w?"YOU FELL IN A HOLE!\n":"THE WUMPUS GOT YOU!\n":"YOU KILLED THE WUMPUS!\n");}
Merci encore à Dennis pour refactoriser mon code:
Constante de caractère m[]
remplacée par des littéraux (je ne savais pas que vous pouviez indexer un littéral.)
Amorçage de nombres aléatoires avec une variable de pile (dépendant du système, certains systèmes randomisent l'allocation de mémoire comme mesure de sécurité)
Macro à puts
remplacé par une macro avec printf
un code supplémentaire à exécuter lorsque le message affiché est placé à l'intérieur d' printf
arguments (avantage de la face que printf n'imprime pas les derniers arguments s'il n'y a pas suffisamment de spécificateurs de format dans la chaîne de format.) if
remplacé par||
Calcul de la nouvelle position du joueur / wumpus placé dans la nouvelle macro.
Messages gagnants / perdus placés en dehors de la while
boucle. if
remplacé par l'opérateur conditionnel.
Utilisation de l'opérateur conditionnel en ligne pour la flèche de tir. Si le joueur manque, cela nécessite à la fois d’imprimer un message et d’ajuster la position de Wumpus. Dennis a proposé plusieurs façons de combiner printf
et de calculer la position de wumpus en une seule expression, mais je suis parti avec l'une des miennes. printf
renvoie le nombre de caractères imprimés, qui , pour Your arrow didn't hit anything\n
se 31 (11111 binaire). Donc, 31&Q(w)==Q(w)
.
Mon autre contribution à cette vérification a été l’élimination de certains crochets inutiles.
Sortie
Ici, le joueur a déjà trouvé où se trouve le Wumpus, mais choisit de faire une exploration approfondie pour savoir exactement où se trouve la fosse. Contrairement à mon ancienne version de débogage qui indiquait où se trouvaient le wumpus et la fosse tout au long du jeu, elle ne montre que les pièces où le joueur s’est rendu et a senti une brise (1) sentait le wumpus (2) ou les deux (3). (Si le joueur tire une flèche et manque, la variable a
contenant les informations de position de wumpus est réinitialisée.)
REPRÉSENTATION ICOSAHEDRON
Remarque: cette section est basée sur la rév. 1
Mon film vedette! Il n'y a pas de graphique dans mon code. Pour expliquer son fonctionnement, voir la carte du monde ci-dessous. Tout point de l'icosaèdre peut être représenté par une latitude comprise entre 0 et 3 et une longitude comprise entre 0 et 4 (ou par un seul chiffre long*4+lat
,.) le centre des faces avec une latitude zéro.
Le joueur peut être orienté sur 3 axes possibles, représentés par les symboles suivants: nord-sud -
nord-sud-sud-ouest \
nord-ouest-sud-est /
. Dans n'importe quelle pièce, il dispose exactement d'une sortie sur chacun de ces axes. Sur l’affichage indiqué, le lecteur effectue une boucle complète dans le sens des aiguilles d’une montre. Il est généralement facile d'identifier le joueur qui marque d'où il vient et donc où il est autorisé à aller.
Le quatrième cas est un peu difficile pour l'œil non initié. Lorsque vous voyez une inclinaison dans l'une de ces rangées polaires, le joueur vient de la cellule polaire la plus proche de l'extrémité extérieure de l'inclinaison et fait généralement face à l'équateur. Ainsi, le joueur fait face au sud-est et ses options sont: 15 (SUD, la cellule à droite) 25 (nord-est, la cellule ci-dessus) ou 35 (nord-ouest, la cellule ci-dessous.)
Donc, fondamentalement, je mappe l'icosaèdre sur une grille 5x4, avec les cellules numérotées de 19 à 0 dans l'ordre dans lequel elles sont imprimées. Le déplacement est effectué en ajoutant ou en soustrayant de la position actuelle, en fonction de la latitude et de la direction du joueur, conformément au tableau ci-dessous.
Si le joueur quitte le bord inférieur (ouest) du plateau, il revient sur le côté supérieur (est) et inversement, sa position est donc prise modulo 20. Généralement, les mouvements sont codés dans m [] en ajoutant ascii 80 ( P
) à la valeur brute donnant les caractères montrés ci-dessous, mais en principe, tout multiple de 20 peut être ajouté sans affecter le fonctionnement.
Table of addition values for moves
Direction Symbol Latitude 0 1 2 3 Latitude 0 1 2 3
0, N-S - 1 -1 1 -1 Q O Q O
1, NE-SW \ -4 1 -1 4 L Q O T
2, NW-SE / 4 -3 3 -4 T M S L
L'entrée du joueur (divisée par 10 pour supprimer le deuxième chiffre) est ajoutée à sa direction actuelle et prise en modulo 3 pour obtenir sa nouvelle direction. Cela fonctionne bien dans la majorité des cas. Cependant, il y a un problème lorsqu'il se trouve dans une pièce polaire et se dirige vers le pôle. En pliant la carte ci-dessous, il est clair que s’il quitte la pièce face au "nord-est", il entrera dans la nouvelle place faisant face au "sud-est"; une correction doit donc être effectuée. Cela se fait dans la ligne e=(d+i/10)*m[p%4]%3;
par la multiplication par m[p%4]
. Les quatre premières valeurs de m [] sont sélectionnées de telle sorte que, en plus de leur fonction ci-dessus, elles possèdent également la caractéristique m[1]%3==m[2]%3==1
et m[0]%3==m[3]%3==2
. Cela laisse la direction seule pour les salles équatoriales et applique la correction nécessaire pour les salles polaires.
Le moment logique pour faire la correction serait après le déménagement. Cependant, pour sauvegarder les personnages, cela est fait avant le déplacement. Par conséquent, certaines valeurs dans m [] doivent être transposées. Ainsi, les 2 derniers caractères sont LT
au lieu de TL
par la table ci-dessus par exemple.
CODE UNGOLFED
c'est le code rev 1, qui est moins obscurci que le rev 2.
Cela fonctionnera sous GCC / Linux. J'ai inclus dans les commentaires le code supplémentaire nécessaire pour le faire fonctionner sous Visual studio / Windows. C'est une grande différence!
//Runs on gcc/linux. For visual studio / windows, change printf(...)
//to printf(" %c%c%c",9*(i%4==1),i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),10*!(i%2)) and uncomment the following lines
//#include"stdafx.h"
//#include<stdlib.h>
//#include<time.h>
//#pragma warning(once:996;once:430) //allow the use of scanf instead of scanf_s, allow default type=int.
//Though rather than using the pragma, it is shorter to follow compiler recommendation and use scanf_s and int.
#define u(t,s,c) if(t){puts(s);c;} //if(test){puts(string);additional code;}
i, //player input, loop counter
d,e, //current and proposed direction
a,b; //bit flags for where wumpus smelt / breeze felt
main(){
srand(time(0));
char q,p=19,h=rand()%p,w=rand()%p, //Initialise player, hole and wumpus. q stores proposed player position.
*m="e@LwQMQOSOLT-\\/\n \f "; //Chars 0-11: movetable. Chars 12-14:symbol for player. Chars 15-18: graphics format.
while(p-h&&p-w){
// Print warnings
for(i=3;i--;){q=(p+m[p%4*3+i])%20;u(q==w,"you smell a wumpus",a|=2<<p)u(q==h,"you feel a breeze",b|=1<<p)}
// graphic display
for(i=20;i--;)printf("%c%c",i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),m[i%4+15]);
// Get player input and work out direction and room
scanf("%d",&i);
e=(d+i/10)*m[p%4]%3;
q=(p+m[p%4*3+e])%20;
// i%5 is false if player inputs 5 (move player) otherwise true (shoot arrow)
if(i%5)
{u(q-w,"arrow missed",w=(w+m[w%4*3+rand()%3])%20;a=0)else u(1,"YOU KILLED THE WUMPUS!",h=p)}
else{p=q;d=e;u(p==h,"YOU FELL IN A HOLE!",)}
u(p==w,"THE WUMPUS GOT YOU!",)
}
}
QUESTIONS ET CURIOISITES
J'ai profité du point mentionné par @professorfish, si le wumpus et la fosse commencent à des endroits aléatoires, il n’est pas nécessaire que le joueur démarre dans un endroit aléatoire. Le joueur commence toujours dans la salle 19 face au nord.
Je comprends que, le wumpus n'étant "pas affecté par la fosse", il peut commencer ou entrer dans la pièce où se trouve la fosse. En général, cela simplifie les choses sauf pour un point. Je n'ai pas de variable spécifique pour indiquer que le jeu est terminé; c'est fini quand le joueur coïncide avec le wumpus ou la fosse. Ainsi, lorsque le joueur gagne, j'affiche le message gagnant mais déplace le stand au joueur pour qu'il sorte de la boucle! Je ne peux pas mettre le joueur dans la fosse car le wumpus est peut-être là et je voudrais recevoir un message sur le wumpus que je ne veux pas.
Le rev0program fonctionnait parfaitement dans Visual Studio, mais l’EDI disait "pile corrompue autour de la variable i" à la sortie. En effet , scanf tente de mettre int
en char.
Dennis ont signalé un comportement incorrect sur sa machine Linux à cause de cela. Quoi qu’il en soit, il est corrigé par l’utilisation du type correct dans rev 1.
La ligne d'affichage du tableau dans rev 0 est maladroite et semble légèrement différente sur d'autres plates-formes. Au printf(" %c%c%c")
milieu,% c est le caractère imprimable affiché. Le dernier% c est ASCII 0 ou ASCII 10 (\ n, nouvelle ligne avec retour chariot dans Windows.) Il semble qu’aucun caractère de Windows fonctionnant dans la console ne passe sur une ligne sans donner de retour chariot. Si c'était le cas, je n'aurais pas besoin du premier c% (onglet ASCII 0 ou ASCII 9 avant le caractère de latitude 1. Les onglets sont notoirement non définis dans leur comportement.) .) La rév. 1 a une révision de cette ligne qui utilise un caractère de saut de page et ne nécessite par conséquent aucun caractère de format au début de printf. Cela le rend plus court, mais le \ f ne fonctionne pas sous Windows.