64
10
NetHack is a roguelike game where a player must retrieve the Amulet of Yendor from the lowest level of the dungeon. Commonly played via telnet, the entire game is represented with ASCII graphics. The game is extremely challenging and requires knowledge of many game mechanics in order to succeed.
For the purposes of this challenge, assume that the entire dungeon is a single level and only 5×16 characters. Furthermore, assume that this is a "safe" dungeon or that you are only implementing a prototype—there will be no monsters, concerns about hunger, etc. In fact, you must only track the location of the character and the amulet and the game will effectively end when the player arrives at the same location as the amulet.
Challenge requirements
- There will be a 5×16 dungeon (single level).
- Give the player a starting location (optionally random) and the amulet a separate random (different each time the program is run) starting square inside the dungeon. That is, the amulet is not allowed to start on the same square as the player.
- Accept four input keys which move the player one square at a time (four cardinal directions). Reading/processing other input is allowed (a readline() function that requires pressing 'enter', etc).
- Travelling outside the bounds of the dungeon is not allowed. E.g., if the player is on the right edge of the dungeon pressing right should do nothing.
- After initial generation and after each movement, print the state of the game. As this is code golf and printing is rather uninteresting, ignore the character count for the print function and function call assuming no state changes. Empty cells should be shown as period (
.
), amulet as double quote ("
) and character as at symbol (@
). - The game is over when the player "discovers" the amulet (arrives at the same square)
Winning
This is a code golf challenege, the shortest code to meet the requirements one week from today will be declared winner.
Example
Here is an example solution in C# (ungolfed) to show basic requirements and sample output.
using System;
namespace nh
{
class Program
{
static Random random = new Random();
// player x/y, amulet x/y
static int px, py, ax, ay;
static void Main(string[] args)
{
px = random.Next(0, 16);
py = random.Next(0, 5);
// amulet starts on a position different from the player
do { ax = random.Next(0, 16); } while (px == ax);
do { ay = random.Next(0, 5); } while (py == ay);
print();
do
{
// reads a single keypress (no need to press enter)
// result is cast to int to compare with character literals
var m = (int)Console.ReadKey(true).Key;
// Move the player. Here standard WASD keys are used.
// Boundary checks for edge of dungeon as well.
if (m == 'W')
py = (py > 0) ? py - 1 : py;
if (m == 'S')
py = (py < 5) ? py + 1 : py;
if (m == 'A')
px = (px > 0) ? px - 1 : px;
if (m == 'D')
px = (px < 16) ? px + 1 : px;
// print state after each keypress. If the player doesn't
// move this is redundant but oh well.
print();
// game ends when player is on same square as amulet
} while (px != ax || py != ay);
}
static void print()
{
Console.Write('\n');
for (int y=0; y<5; y++)
{
for (int x = 0; x < 16; x++)
{
if (x == px && y == py)
Console.Write('@');
else if (x == ax && y == ay)
Console.Write('"');
else
Console.Write('.');
}
Console.Write('\n');
}
}
}
}
Total character count is 1474, but ignoring calls to the print function and its definition the final character count is 896
.
Output when the program is run:
................
...."...........
..........@.....
................
................
Output (including above) after the 'a' key is pressed twice:
................
...."...........
..........@.....
................
................
................
...."...........
.........@......
................
................
................
...."...........
........@.......
................
................
The spec says the amulet should be given a separate square, but the example doesn't enforce that. Is the example valid, or should it be enforced? – Geobits – 2015-07-02T17:11:45.677
10I have a feeling this will be of interest to @Doorknob. – Alex A. – 2015-07-02T17:15:32.390
Whoops, good catch, updated. There should be a check to make sure the amulet doesn't spawn on the player. – None – 2015-07-02T17:15:33.253
1What about buffering on
stdin
? A "non-blockinggetchar
" is very easy in some languages/environments and very hard in others. Is "press w and then enter" also OK? – Lynn – 2015-07-02T17:20:26.033Should the position of the amulet be uniform over the non-player board locations? Or just "there must be a non-zero chance of it landing on any non-player tile"? Right now, "random" could be interpreted as "randomly on one of two squares", which might be easier to implement. – Lynn – 2015-07-02T17:25:23.790
Yes, that's fine. I was using
Console.Read()
but that was cluttering up my C# example by having to ignore newlines. – None – 2015-07-02T17:26:16.480As far as random, the intent is that it's different every time you run the game, not necessary some strict uniform distribution. Pulling bits from the current time would work just as well. – None – 2015-07-02T17:28:12.860
Are we allowed to take input as a string of moves, e.g. "WSSAAWD"? Should we allow for the player running off an edge and compensate by sending them to the opposite side, or just prevent movement? – Kade – 2015-07-02T17:56:58.900
@Vioz- I don't see why a string of input shouldn't be allowed. If the character were to run out of bounds that should just be prevented, e.g., on the right edge pressing right should do nothing. – None – 2015-07-02T18:04:36.340
@tolos: Would you mind taking a look at my Julia answer and letting me know whether my scoring method is valid? – Alex A. – 2015-07-02T18:41:43.547
10Rogue is the original roguelike game where a player must retrieve the Amulet of Yendor from the lowest level of the dungeon. Why not call this a minimal Rogue? – Gilles 'SO- stop being evil' – 2015-07-02T19:10:45.487
@Gilles I've never played Rogue but I've spent a few hours with NetHack – None – 2015-07-02T19:29:11.203
5@Gilles Why not call this a minimal snake? – Casey Kuball – 2015-07-02T22:03:13.317
26Psshh, no diagonal movement? No yubnhjkl? Not even an up staircase to climb after getting the amulet? :P (furiously upvotes anyway) – Doorknob – 2015-07-02T22:43:47.910
2
@tolos: I'm still unclear what counts as random here. It's not really possible to fulfill the different each time the program is run requirement if the program is run 80 times... Specifically, in this answer, the amulet can occupy only 9 of all possible 79 locations. Does that count?
– Dennis – 2015-07-02T22:59:17.547Give the player a starting location (optionally random)
Does this mean that we can choose to make the player start in the same place every time, as long as the amulet's position is random? – M. I. Wright – 2015-07-02T23:46:53.6931@Dennis I'm trying to specify the amulet should start somewhere other than the player and you shouldn't be able to, say, "move right 4, up 3" every single time to "beat" the game. Don't know a better way to word that. – None – 2015-07-03T00:34:54.117
@M.I.Wright Yes. I believe the python solution by Mauris does just that. – None – 2015-07-03T00:38:17.570
@tolos: Can I assume Caps Lock is on? I'd like to use uppercase letters for input. – Dennis – 2015-07-03T04:42:31.520
1It should be nice.to have a challenge asking for a little more complex roguelike game. – edc65 – 2015-07-03T14:00:02.777
@Dennis That's fine. I was trying to leave input requirements a bit open and glad to see answers like the TI-BASIC submission by Thomas Kwa. – None – 2015-07-03T15:40:08.023
1
Related: http://codegolf.stackexchange.com/questions/375/build-an-engine-for-a-maze-game
– dmckee --- ex-moderator kitten – 2015-07-04T02:39:38.760