REV0 C ++ (Visual Studio unter 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!");}}
Im Folgenden sehen Sie einen Durchgang, der zeigt, dass Sie bei korrektem Spiel immer gewinnen können (vorausgesetzt, Sie beginnen nicht direkt neben einer Gefahr). Der Spieler fühlt eine Brise, dreht sich um und macht eine vollständige Schleife gegen den Uhrzeigersinn. Da er genau 5 Züge braucht, um wieder eine Brise zu spüren, kennt er das Loch zu seiner Rechten und kommt so weit wie möglich weg. Wenn er den Wumpus riecht und nicht weiß, ob er rechts oder links ist, dreht er sich um und macht eine Schleife im Uhrzeigersinn. Er braucht 5 Züge, um den Wumpus wieder zu riechen, also weiß er, dass er links ist und schießt mit Sicherheit.
Wenn er sich anders herum geschleift hätte, hätte er den Wumpus früher gefunden und gewusst, dass er sich in die gleiche Richtung drehte.
REV1 C (GCC auf Cygwin), 431-35% Bonus = 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!",)}}
Zeilenumbrüche zur Verdeutlichung hinzugefügt. Die Änderungen von Rev 0 sind wie folgt:
Ein großes Dankeschön an @Dennis für die Empfehlung des GCC-Compilers für den Cygwin Linux-Emulator für Windows. Für diesen Compiler ist das include
s im Rev. 0-Programm nicht erforderlich , und der Standardtyp int
für Variablen main.
ist zulässig. Dies ist ein lebensverändernder Golftipp!
Wenn Sie zusätzlich unter Linux arbeiten \f
, bewegt sich der Cursor nach unten, ohne dass ein Wagenrücklauf ausgeführt wird (im Gegensatz zu Windows, in dem nur ein druckbares Symbol erstellt wird). Dadurch konnte die printf-Anweisung, mit der die Karte gedruckt wird, erheblich verkürzt werden
Einige zusätzliche Tipps von Dennis in den Kommentaren und einen von mir: Zustandsänderung beim Prüfen, ob der Pfeil auf den Wumpus trifft: if(q==w)
> if(q-w)
(..else .. ist umgekehrt)
Zusätzliches Grafikdisplay mit den Informationen, die der Spieler darüber kennt, wo ein Wumpus riecht / eine Brise spürt, dass er den 35% -Bonus beansprucht. (Ich habe die alte Debug-Version gelöscht, in der die genaue Position von Wumpus und Loch angegeben ist. Sie ist im Bearbeitungsverlauf zu sehen.)
REV2 C (GCC auf Cygwin), 389-35% Bonus = 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");}
Nochmals vielen Dank an Dennis für die Überarbeitung meines Codes:
Zeichenkonstante m[]
durch Literale ersetzt (Ich wusste nicht, dass Sie ein Literal indizieren können.)
Seeding von Zufallszahlen mit Stapelvariablen (systemabhängig, einige Systeme setzen die Speicherzuordnung als Sicherheitsmaßnahme zufällig fest.)
Makro mit puts
ersetzt durch ein Makro mit printf
und zusätzlichem Code, der ausgeführt werden muss, wenn die angezeigte Nachricht in printf
Argumenten platziert wird (Vorteil, dass printf die letzten Argumente nicht druckt, wenn nicht genügend Formatspezifizierer in der Formatzeichenfolge vorhanden sind.) if
ersetzt durch||
Berechnung der neuen Position des Spielers / Wumpus innerhalb des neuen Makros.
Nachrichten außerhalb der while
Schleife gewinnen / verlieren . if
ersetzt durch bedingten Operator.
Verwendung des bedingten Operators in der Linie zum Schießen des Pfeils. Wenn der Spieler ausfällt, müssen Sie sowohl eine Nachricht drucken als auch die Wumpusposition anpassen. Dennis bot ein paar Möglichkeiten an, printf
die Wumpus-Position in einem Ausdruck zu kombinieren und zu berechnen, aber ich habe mich für einen eigenen entschieden. printf
gibt die Anzahl der gedruckten Zeichen, die Your arrow didn't hit anything\n
also 31 (11111 binär.) 31&Q(w)==Q(w)
.
Mein anderer Beitrag zu dieser Bearbeitung war die Beseitigung einiger unnötiger Klammern.
Ausgabe
Hier hat der Spieler bereits gefunden, wo sich der Wumpus befindet, entscheidet sich jedoch für eine gründliche Untersuchung, um herauszufinden, wo sich auch die Grube befindet. Im Gegensatz zu meiner alten Debug-Version, in der angezeigt wurde, wo sich Wumpus und Pit während des Spiels befanden, werden hier nur die Räume angezeigt, in denen der Spieler den Wumpus (2) oder beides (3) besucht und eine Brise gespürt hat (1). (Wenn der Spieler einen Pfeil schießt und verfehlt, wird die Variable a
mit den Wumpuspositionsinformationen zurückgesetzt.)
ICOSAHEDRON-VERTRETUNG
Hinweis: Dieser Abschnitt basiert auf Version 1
Mein Star-Feature! Mein Code enthält kein Diagramm. Informationen zur Funktionsweise finden Sie auf der folgenden Weltkarte. Jeder Punkt auf dem Ikosaeder kann durch einen Breitengrad 0-3 und einen Längengrad 0-4 (oder eine einzelne Zahl) dargestellt werden long*4+lat
. Die auf der Karte markierte Längengradlinie verläuft nur durch die Flächen mit dem Längengrad Null, und die Breitengradlinie verläuft durch die Mitte der Gesichter mit dem Breitengrad Null.
Der Spieler kann sich an drei möglichen Achsen orientieren, die durch die folgenden Symbole dargestellt werden: Nord-Süd- -
Nordost-Südwest \
- Nordost -Südost /
. In jedem Raum steht ihm auf jeder dieser Achsen genau ein Ausgang zur Verfügung. In der angezeigten Anzeige macht der Player eine vollständige Schleife im Uhrzeigersinn. Es ist im Allgemeinen einfach, anhand der Spielermarkierung zu erkennen, woher er kam und wohin er gehen darf.
Der eine Fall, der für das nicht eingeweihte Auge etwas schwierig ist, ist der vierte. Wenn Sie eine Neigung in einer dieser Polarreihen sehen, ist der Spieler von der Polarzelle gekommen, die dem äußeren Ende der Neigung am nächsten liegt, und zeigt im Allgemeinen zum Äquator. Der Spieler ist also nach Südosten ausgerichtet und hat folgende Optionen: 15 (SÜD, die Zelle rechts) 25 (Nordosten, die Zelle oben) oder 35 (Nordwesten, die Zelle unten).
Im Grunde genommen ordne ich das Ikosaeder einem 5x4-Raster zu, wobei die Zellen in der Reihenfolge, in der sie gedruckt werden, von 19 bis 0 nummeriert sind. Der Zug erfolgt durch Addieren oder Subtrahieren der aktuellen Position, abhängig vom Breitengrad und der Richtung des Spielers, gemäß der folgenden Tabelle.
Wenn der Spieler vom Boden (Westen) des Bretts absteigt, kehrt er auf die Oberseite (Osten) zurück und umgekehrt, sodass seine Position modulo 20 eingenommen wird. Im Allgemeinen werden die Züge durch Hinzufügen von ASCII 80 in m [] codiert. P
) zu dem Rohwert hinzu, der die unten gezeigten Zeichen angibt, aber grundsätzlich kann ein beliebiges Vielfaches von 20 hinzugefügt werden, ohne die Operation zu beeinflussen.
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
Die Eingabe des Spielers (geteilt durch 10, um die zweite Ziffer zu entfernen) wird zu seiner aktuellen Richtung addiert und modulo 3 genommen, um seine neue Richtung zu erhalten. Dies funktioniert in den meisten Fällen einwandfrei. Es gibt jedoch ein Problem, wenn er sich in einem Polarraum befindet und sich auf die Stange zubewegt. Wenn Sie die Karte darunter falten, wird klar, dass er, wenn er den Raum nach "Nordosten" verlässt, das neue Quadrat nach "Südosten" betritt, sodass eine Korrektur vorgenommen werden muss. Dies geschieht in der Zeile e=(d+i/10)*m[p%4]%3;
durch Multiplikation mit m[p%4]
. Die ersten vier Werte von m [] werden so gewählt, dass sie zusätzlich zu ihrer obigen Funktion auch die Charakteristik m[1]%3==m[2]%3==1
und haben m[0]%3==m[3]%3==2
. Dies lässt die Richtung für die Äquatorialräume allein und wendet die notwendige Korrektur für Polarräume an.
Die logische Zeit für die Korrektur wäre nach dem Umzug. Das Speichern von Zeichen erfolgt jedoch vor dem Verschieben. Daher müssen bestimmte Werte in m [] transponiert werden. So sind die letzten 2 Zeichen LT
anstelle der TL
obigen Tabelle zum Beispiel.
UNGOLFED CODE
Dies ist Rev. 1 Code, der weniger verschleiert ist als Rev. 2.
Dies wird unter GCC / Linux ausgeführt. Ich habe in den Kommentaren den zusätzlichen Code angegeben, der für die Ausführung unter Visual Studio / Windows erforderlich ist. Das ist ein großer Unterschied!
//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!",)
}
}
FRAGEN UND NEUGIERIGKEITEN
Ich habe den von @professorfish erwähnten Punkt ausgenutzt. Wenn der Wumpus und die Grube an zufälligen Orten beginnen, muss der Spieler nicht an zufälligen Orten beginnen. Der Spieler startet immer in Raum 19 nach Norden.
Ich verstehe, dass, da der Wumpus "von der Grube nicht betroffen" ist, der Wumpus beginnen oder den Raum betreten kann, in dem sich die Grube befindet. Im Allgemeinen vereinfacht dies die Dinge bis auf einen Punkt. Ich habe keine spezifische Variable, die anzeigt, dass das Spiel beendet ist. es ist vorbei, wenn der Spieler mit dem Wumpus oder der Grube zusammenfällt. Wenn der Spieler gewinnt, zeige ich die Gewinnnachricht an, aber bewege die Grube zum Spieler, um aus der Schleife herauszukommen! Ich kann den Spieler nicht in die Box setzen, da der Wumpus dort sein könnte und ich eine Nachricht über den Wumpus erhalten würde, die ich nicht möchte.
Das rev0-Programm funktionierte perfekt in Visual Studio, aber die IDE meldete beim Beenden "Stapel um Variable i beschädigt". Dies ist darauf zurückzuführen, dass scanf versucht, int
ein von char.
Dennis gemeldetes falsches Verhalten auf seinem Linux-Computer zu erzeugen . Auf jeden Fall wird es durch Verwendung des richtigen Typs in Rev. 1 behoben.
Die Zeile für die Anzeige des Boards in Rev. 0 ist unbeholfen und sieht auf anderen Plattformen etwas anders aus. In printf(" %c%c%c")
der Mitte% c wird das druckbare Zeichen angezeigt. Das letzte% c ist entweder ASCII 0 oder ASCII 10 (\ n, Zeilenumbruch mit Wagenrücklauf in Windows.) In Windows scheint es kein Zeichen zu geben, das in der Konsole funktioniert und das eine Zeile ohne Wagenrücklauf abfährt. Wenn es das gäbe, bräuchte ich nicht das erste c% (ASCII 0- oder ASCII 9-Tab vor dem 1. Breitengrad-Zeichen. Tabs sind in ihrem Verhalten notorisch undefiniert.) Das führende Leerzeichen verbessert die Formatierung (bringt die 3. und 2. Breite näher an das 1. Breitengrad-Zeichen .) Rev 1 enthält eine Überarbeitung dieser Zeile, die ein \ f-Formatvorschubzeichen verwendet und daher am Anfang des Ausdrucks kein Formatzeichen benötigt. Das macht es kürzer, aber das \ f funktioniert nicht in Windows.