Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[ANNOUNCE] 1.1KB RL - Fur Hunter

51 views
Skip to first unread message

Jakub Debski

unread,
Aug 19, 2008, 8:56:03 PM8/19/08
to
My second project for 1KB challenge - "Fur Hunter".

This time I failed... or succeed? It's up to you to decide.

I failed because I couldn't shrink the source code to less than 1.1KB
(it's 1159 bytes with #includes).
At the same time I succeed with implementation of all the features I
wanted:
- Hit points and death
- Control with num pad (1-9)
- Randomly generated maps, fully traversable levels
- Multi-levels with stairs down
- Items to collect (med-packs)
- Monsters to kill
- Monster corpses
- Stronger monsters on deeper levels
- Experience (gold) for killing monsters
- Monsters chasing player
- Field of view (Fanfares!)

Not bad for 1.1KB of source code?

Windows exe + screenshot:
http://www.alamak0ta.republika.pl/furhunter.html

Source code:

#include "curses.h"
#include <string>
#include <time.h>
#define S 40
#define B rand()%S
#define L M[x][y]
#define H(a,b)for(a=0;a<b;++a)
#define F H(x,S)
#define G H(y,S)
#define T H(k,3)H(l,3)
#define O N[x][y]
#define Q O=L;if(L==35)goto
Z;if(L>96){if(abs(x-f)<2&&abs(y-i)<2)h--,L-=32;else M[a][b]=L-32,L=46;}
int
c,e,x,y,k,l,f,i,h=20,g,d,M[S][S],N[S][S],v,w,a,b,nx,ny;char*t="789456123+><.`";float
m,n;
void main(){srand(time(0));initscr();resize_term(S,60);j:d++;F G
L=35;M[20][20]=46;
H(nx,S*S*S){f=x,i=y,x=B,y=B,a=0;T
if(M[x+k-1][y+l-1]!=35)a++;if(a>0&&a<4&&x&&y&&x!=39&&y!=39)
L=B?46:B/10?97+B/(10-d):43;}L=62,x=f,y=i,L=60;for(;;){F G O=32;F G
{v=f,w=i,k=x-v,l=y-w,c=x,e=y;
if(abs(k)>abs(l)){m=l/(float)k,n=w-m*v,k=k<0?-1:1;while(v!=c){a=v;b=ny;x=v+=k;y=ny=(m*v+n);Q}}
else
if(l){m=k/(float)l,n=v-m*w,l=l<0?-1:1;while(w!=e){a=nx;b=w;y=w+=l;x=nx=(m*w+n);Q}}Z:x=c,y=e;}
F G if (L>64 && L<91)L+=32;F G
mvaddch(y,x,O);mvaddch(i,f,64);mvprintw(20,50,"H%d $%d L%d ",h,g,d);
refresh();x=getch();if(h<0)return;T if(x==t[k+l*3])goto
q;q:if(k*l<9){x=f+k-1;y=i+l-1;if(L>='a')
{L--;if(L==96)g++;}if(strchr(t,L))f=x,i=y;if(L==62)goto j;if
(L==43)h+=5,L=46;}}}


Jakub Debski

unread,
Aug 20, 2008, 3:45:21 AM8/20/08
to
Jakub Debski explained :

> I failed because I couldn't shrink the source code to less than 1.1KB (it's
> 1159 bytes with #includes).

http://www.alamak0ta.republika.pl/furhunter.html
Two fixes - source code shrinked to 1141 bytes + new FOV feature.
Now you see the whole maze out of FOV (game is not so 'dark').

regards,
Jakub


sego...@gmail.com

unread,
Aug 21, 2008, 8:36:53 PM8/21/08
to
<Snip>
would int S = 40;
not be shorter ?

T.

corremn

unread,
Aug 22, 2008, 12:58:20 AM8/22/08
to
> T.- Hide quoted text -
>
> - Show quoted text -

int S=40; would save you 4 bytes!! Infact it doesn't even need a
newline character!

Anyway still impressive. Good Job.

Jakub Debski

unread,
Aug 22, 2008, 4:06:06 AM8/22/08
to
corremn explained :

> int S=40; would save you 4 bytes!! Infact it doesn't even need a
> newline character!

It would save, but S is also used for arrays size (level, fov) and
constant is expected there.
I think FOV calculation could be shrinked and maybe I'd get the magic
1024 bytes :) With a few more optimizations I got 1128 bytes.
New version is here:
http://www.alamak0ta.republika.pl/furhunter.html

> Anyway still impressive. Good Job.

Thanks :)

regards,
Jakub


Jakub Debski

unread,
Aug 22, 2008, 6:37:37 AM8/22/08
to
Jakub Debski explained :

> I think FOV calculation could be shrinked and maybe I'd get the magic 1024
> bytes :) With a few more optimizations I got 1128 bytes.

Even more optimizations and I have 1086 bytes (1.06KB).
62 more to cut :)

#include "curses.h"
#include <string>
#include <time.h>
#define S 40

#define B rand()%S
#define L M[x][y]
#define H(a,b)for(a=0;a<b;++a)

#define F H(x,S)H(y,S)


#define T H(k,3)H(l,3)
#define O N[x][y]
#define Q O=L;if(L==35)goto
Z;if(L>96){if(abs(x-f)<2&&abs(y-i)<2)h--,L-=32;else M[a][b]=L-32,L=46;}
int

c,e,x,y,k,l,f,i,h=20,g,d,M[S][S],N[S][S],v,w,a,b,r,s;char*t="789456123+><.`";float
m,n,o,p;void main(){srand(time(0));initscr();resize_term(S,60);j:d++;F
L=35;M[20][20]=46;H(r,S*S*S){f=x,i=y,x=B,y=B,a=0;T
if(M[x+k-1][y+l-1]!=35)a++;if(a>0&&a<4&&x&&y&&x!=39&&y!=39)L=B?46:B/10?97+B/(9-d):43;}L=62,x=f,y=i,L=60;for(;;){F
O=L==35?37:32;F{v=f,w=i,c=x,e=y;if(abs(o=x-v)>abs(p=y-w)){m=p/o,n=w-m*v;while(v!=c){a=v,b=s,x=v+=o<0?-1:1,y=s=m*v+n;Q}}else{m=o/p,n=v-m*w;while(w!=e){a=r,b=w,y=w+=p<0?-1:1,x=r=m*w+n;Q}}Z:x=c,y=e;}F
if(L>64&&L<91)L+=32;F
mvaddch(y,x,y==i&&x==f?64:O);refresh();printf("H%d $%d
L%d",h,g,d);x=getch();if(h<1)break;T if(x==t[k+l*3])goto
q;q:if(k*l<9){x=f+k-1;y=i+l-1;if(L>=97){L--;if(L==96)g++;}if(strchr(t,L))f=x,i=y;if(L==62)goto
j;if(L==43)h+=5,L=46;}}}

regards,
Jakub


konijn_

unread,
Aug 22, 2008, 9:06:07 AM8/22/08
to

S*S*S = S^3 ;)

2 less bytes ?

T.

Soyweiser

unread,
Aug 22, 2008, 9:19:11 AM8/22/08
to
On Aug 22, 3:06 pm, konijn_ <kon...@gmail.com> wrote:
> S*S*S = S^3 ;)
>
> 2 less bytes ?
>
> T.

L>=97 = L>96

1 less byte.

59 to go.
--
Soyweiser

Obnoxious User

unread,
Aug 22, 2008, 9:04:35 AM8/22/08
to
On Fri, 22 Aug 2008 06:06:07 -0700, konijn_ wrote:

> S*S*S = S^3 ;)
>
> 2 less bytes ?
>

That's the XOR operator.

S*S*S ≠ S^3

--
OU

Jakub Debski

unread,
Aug 22, 2008, 9:35:54 AM8/22/08
to
konijn_ explained on 2008-08-22 :

> S*S*S = S^3 ;)
> 2 less bytes ?

It's xor in C.

By the way - I DID IT!!! It's 1024 bytes now! :)

Tricks used:
- Map is smaller - 24x24 - no need to resize term
- Terminal switched to raw mode - no need to refresh
- Removed need for strchr by removing useless stairs up
- Map generator initialization changed
- Some smaller fixes

Removed RNG initialization by time() (unfortunatelly) - need to press
random key at start to init RNG. With it I had to #include <time.h>
that was too long.

I had 3 bytes left to format stats string into full "HP" ;)

http://www.alamak0ta.republika.pl/furhunter.html

regards,
Jakub


Obnoxious User

unread,
Aug 22, 2008, 10:03:03 AM8/22/08
to

It looks like C but since you include <string> instead of <string.h>
I'll try to compile it as both C and C++:

:~$ gcc -ansi -pedantic -Wall -lncurses furhunter.c
furhunter.c:2:18: error: string: No such file or directory
furhunter.c:10: warning: return type of ‘main’ is not ‘int’
furhunter.c: In function ‘main’:
furhunter.c:10: warning: implicit declaration of function ‘srand’
furhunter.c:10: warning: implicit declaration of function ‘rand’
furhunter.c:10: warning: implicit declaration of function ‘abs’

:~$ g++ -ansi -pedantic -Wall -lncurses furhunter.cpp
furhunter.cpp:10: warning: deprecated conversion from string constant to
‘char*’
furhunter.cpp:10: error: ‘::main’ must return ‘int’

The warnings can be ignored, but there are errors prohibiting proper
compilation.

--
OU

Slash

unread,
Aug 22, 2008, 10:52:32 AM8/22/08
to

Remove "#define S 24" for direct usage of "24" all around the code; 4
more bytes for you!
Can't you use "x=y=B" instead of "x=B,y=B" in C? that would be 2 more
bytes
--
Slashie

Jakub Debski

unread,
Aug 25, 2008, 3:16:37 AM8/25/08
to
Slash explained on 2008-08-22 :

> Remove "#define S 24" for direct usage of "24" all around the code; 4
> more bytes for you!
> Can't you use "x=y=B" instead of "x=B,y=B" in C? that would be 2 more
> bytes

Thanks, I can do both of it :)

regards,
Jakub


Jakub Debski

unread,
Aug 25, 2008, 3:19:19 AM8/25/08
to
Obnoxious User formulated the question :

>> ~$ g++ -ansi -pedantic -Wall -lncurses furhunter.cpp

what if you remove -ansi -pedantic ?
I have no GCC compiler near me to test it.

regards,
Jakub


Jakub Debski

unread,
Aug 25, 2008, 3:36:26 AM8/25/08
to
Slash formulated on piątek :

> Can't you use "x=y=B" instead of "x=B,y=B" in C? that would be 2 more
> bytes

This won't work. B is rand()%24 and then x=y instead of two different
random values.

regards,
Jakub


Jakub Debski

unread,
Aug 25, 2008, 3:48:45 AM8/25/08
to
Obnoxious User pretended :

>> http://www.alamak0ta.republika.pl/furhunter.html
> It looks like C but since you include <string> instead of <string.h>
> I'll try to compile it as both C and C++:

It's C++. <string> is shorter than <string.h> ;)

>> ~$ g++ -ansi -pedantic -Wall -lncurses furhunter.cpp
> furhunter.cpp:10: warning: deprecated conversion from string constant to
> 'char*'

> furhunter.cpp:10: error: 'main' must return 'int'

Fixed. main returns int.

I have also limited game to 7 levels as a goal to reach.
Try to get as much $ as you can on these 7 levels without beeing
killed.

Source code (C++):
#include "curses.h"
#include <string>
#define B rand()%24


#define L M[x][y]
#define H(a,b)for(a=0;a<b;++a)

#define F H(x,24)H(y,24)
#define T H(k,3)H(l,3)
#define Q N[x][y]=L;if(L==35)goto

Z;if(L>96){if(abs(x-f)<2&&abs(y-i)<2)h--,L-=32;else M[a][b]=L-32,L=46;}
int

c,e,x,y,k,l,f,i,h=20,g,d,M[24][24],N[24][24],v,w,a,b,r,s;char*t="789456123";float
m,n,o,p;int main(){initscr();raw();srand(getch());j:d++;F
L=35;M[9][9]=46;H(r,9999){f=x,i=y,x=B,y=B,a=0;T
if(M[x+k-1][y+l-1]!=35)a++;if(a>0&&a<4&&x&&y&&x!=23&&y!=23)L=B?46:B/9?97+B/(9-d):43;}L=62;for(;;){F
N[x][y]=L==35?37:32;F{v=f,w=i,c=x,e=y;if(abs(o=x-v)>abs(p=y-w)){m=p/o,n=w-m*v;while(v!=c){a=v,b=s,x=v+=o<0?-1:1,y=s=m*v+n;Q}}else{m=o/p,n=v-m*w;while(w!=e){a=r,b=w,y=w+=p<0?-1:1,x=r=m*w+n;Q}}Z:x=c,y=e;}F
if(L>64&&L<91)L+=32;F mvaddch(y,x,y==i&&x==f?64:N[x][y]);printf(" HP%d
$%d L%d ",h,g,d);x=getch();if(h<1||d>7)return 0;T if(x==t[k+l*3])goto
q;q:if(k*l<9){x=f+k-1;y=i+l-1;if(L>96){L--;if(L==96)g++;}else
if(L!=35)f=x,i=y;if(L==62)goto j;if(L==43)h+=5,L=46;}}}

regards,
Jakub


Martin Read

unread,
Aug 25, 2008, 6:33:27 AM8/25/08
to
Jakub Debski <debski...@wp.pl> wrote:
>Obnoxious User formulated the question :
>>> ~$ g++ -ansi -pedantic -Wall -lncurses furhunter.cpp
>
>what if you remove -ansi -pedantic ?

That won't stop it bitching about main() not returning int.

The C++ Standard *requires* main() to return int. It is not valid C++
code if main() either does not return int, or has no return type
specified (there are no implicit return types in C++).
--
\_\/_/ turbulence is certainty turbulence is friction between you and me
\ / every time we try to impose order we create chaos
\/ -- Killing Joke, "Mathematics of Chaos"

Jakub Debski

unread,
Aug 25, 2008, 6:50:20 AM8/25/08
to
Martin Read formulated the question :

> The C++ Standard *requires* main() to return int. It is not valid C++
> code if main() either does not return int, or has no return type
> specified (there are no implicit return types in C++).

From C++ Standard (3.6.1.2):

An implementation shall not predefine the main function. This function
shall not be overloaded. It shall
have a return type of type int, but otherwise its type is
implementation-defined.

Also (3.6.1.5):

A return statement in main has the effect of leaving the main function
(destroying any objects with automatic
storage duration) and calling exit with the return value as the
argument. If control reaches the end
of main without encountering a return statement, the effect is that of
executing
return 0;

regards,
Jakub


Martin Read

unread,
Aug 25, 2008, 7:17:32 AM8/25/08
to
Jakub Debski <debski...@wp.pl> wrote:
>From C++ Standard (3.6.1.2):
>
>An implementation shall not predefine the main function. This function
>shall not be overloaded. It shall have a return type of type int, but
>otherwise its type is implementation-defined.

That's what I said.

(I don't have a copy of the ISO C++ standard to hand, because last time
I looked, ISO wanted me to pay CHF340 for the PDF.)

Jakub Debski

unread,
Aug 25, 2008, 7:54:31 AM8/25/08
to
on 2008-08-25, Martin Read supposed :

>> An implementation shall not predefine the main function. This function
>> shall not be overloaded. It shall have a return type of type int, but
>> otherwise its type is implementation-defined.
>
> That's what I said.

Well... "otherwise its type is implementation-defined" and many
compilers support "void main()".

The second paragraph "If control reaches the end


of main without encountering a return statement, the effect is that of

executing return 0;" can be useful when writing 1KB roguelike.

regards,
Jakub


Derek Ray

unread,
Aug 25, 2008, 8:40:30 AM8/25/08
to
On 2008-08-25, Jakub Debski <debski...@wp.pl> wrote:
> on 2008-08-25, Martin Read supposed :
>>> An implementation shall not predefine the main function. This function
>>> shall not be overloaded. It shall have a return type of type int, but
>>> otherwise its type is implementation-defined.
>> That's what I said.
> Well... "otherwise its type is implementation-defined" and many
> compilers support "void main()".

That's not what the text says. It says:

"It shall have a return type of type int," <-- this is non-optional.
"but otherwise..." <-- everything but the return type is optional.

Compilers that support void main() are not standards-compliant; this
only becomes meaningful when you move to a compiler that _is_.

> The second paragraph "If control reaches the end
> of main without encountering a return statement, the effect is that of
> executing return 0;" can be useful when writing 1KB roguelike.

That involves omitting the return statement entirely, moot here.

--
Derek

Game info and change log: http://sporkhack.com
Beta Server: telnet://sporkhack.com
IRC: irc.freenode.net, #sporkhack

Simon Richard Clarkstone

unread,
Aug 23, 2008, 11:25:29 AM8/23/08
to
Jakub Debski wrote:
> Jakub Debski explained :
>> I think FOV calculation could be shrinked and maybe I'd get the magic
>> 1024 bytes :) With a few more optimizations I got 1128 bytes.
>
> Even more optimizations and I have 1086 bytes (1.06KB).
> 62 more to cut :)
>

Beware: in some places, I may be wrong about the precedence of the C
operators.

Sometimes one can do:
#define D define

if(L>96){if(abs(x-f)<2&&abs(y-i)<2)h--,L-=32;else M[a][b]=L-32,L=46;}

L>96&&(abs(x-f)<2&abs(y-i)<2&&h--,L-=32)||M[a][b]=L-32,L=46;

Moving the }} after each Q into the macro is possible but evil

ITYM "int main"

if(L==43)h+=5,L=46;
L^43?0:h+=5,L=46;

if(M[x+k-1][y+l-1]!=35)a++;
M[x+k-1][y+l-1]^35&&a++;

a=0;T if(M[x+k-1][y+l-1]!=35)a++;
if(a>0&&a<4&&x&&y&&x!=39&&y!=39)L=B?46:B/10?97+B/(9-d):43;

a=2;T M[x+k-1][y+l-1]^35||a--;
a*a<2&&x*y&&x^39&&y^39&&L=B?46:B/10?97+B/(9-d):43;

(If precedence permits, the condition can become:)
a*a<2&&x*y*x^39*y^39

O=L==35?37:32;
O=L^35?32:37;

v!=c ... w!=e
v^c ... w^e

F if(L>64&&L<91)L+=32
F L>64&L<91&&L+=32

y==i&&x==f?64:O
y^i+x^f?O:64 /* Assuming that i and f are positive */

I think curses's getch() does a refresh for you; maybe that would help
here? OTOH, refresh might be needed before the printf().

T if(x==t[k+l*3])goto q;q:if(k*l<9)

Aren't k and l always 0, 1, or 2 at the second condition?
Also, you can break instead of using a goto+label.

if(L>=97){L--;if(L==96)g++;}
L>96&&--L>96||g++;

if(strchr(t,L))f=x,i=y;
strchr(t,L)&&f=x,i=y;

if(L==43)h+=5,L=46;
L^43||h+=5,L=46;

HTH. I think it cuts 70 or so characters off.

--
Simon Richard Clarkstone:
s.r.cl?rkst?n?@dunelm.org.uk / s?m?n_cl?rkst?n?@yahoo.co.uk
| My half-daughter went to the GMH riots |
| But all I got was this stupid ¥-shirt. |

Martin Read

unread,
Aug 25, 2008, 9:45:48 AM8/25/08
to
Jakub Debski <debski...@wp.pl> wrote:
>on 2008-08-25, Martin Read supposed :
>>> An implementation shall not predefine the main function. This function
>>> shall not be overloaded. It shall have a return type of type int, but
>>> otherwise its type is implementation-defined.
>>
>> That's what I said.
>
>Well... "otherwise its type is implementation-defined" and many
>compilers support "void main()".

When they support void main(), they are not in compliance with the C++
standard.

The type of a function consists of its return type and its arguments (if
any). The above-quoted text says that *standard-compliant* main() *shall
have a return type of int*, but that the *permitted arguments* of main()
shall be defined by the implementation.

>The second paragraph "If control reaches the end
>of main without encountering a return statement, the effect is that of
>executing return 0;" can be useful when writing 1KB roguelike.

Yes.

Jakub Debski

unread,
Aug 25, 2008, 7:34:51 PM8/25/08
to
Simon Richard Clarkstone expressed precisely :

> HTH. I think it cuts 70 or so characters off.

Thanks! Very nice optimizations!
With them I was able to put "proper" RNG initialization and to fix code
in many places. I could add other dungeon generator but IMHO program
should be stable first.

regards,
Jakub


Jakub Debski

unread,
Aug 27, 2008, 8:08:38 PM8/27/08
to
Jakub Debski brought next idea :

> My second project for 1KB challenge - "Fur Hunter".

Well... Not to start a new thread.
Here is my new tiny roguelike game "The Horde"

http://www.alamak0ta.republika.pl/horde.zip

This time I didn't play much with code shrinking and it's about 2KB
long. For sure it can be less than 1KB if anyone wants to improve size
:)

THE STORY

"You play Chauncey, one of King Winthrop the Good's humble servants.
During a meal at which you are serving food, the king begins choking on
a bit of turkey.

The other people at the table are so engrossed in one of Kronus
Maelor("the Evil High Chancellor")'s stories, that they don't notice
the king's predicament. But you, realizing the magnitude of the
situation, perform a royal Heimlich maneuver on his highness, saving
his life.

Although Maelor wishes you imprisoned for attacking the king, King
Winthrop has a better grasp on the situation and rewards your valor by
knighting you "Sir Chauncey" and giving you a small tract of land known
as the Shimto Plains.

While vast tracts of land are nice, these particular tracts of land are
infested with "The Horde". Luckily, as part of your reward for saving
his life, the good king has given you his mighty hordling-crushing
sword, Grimthwacker with which to thwart the advance of the foul
beasts."

CONTROLS
1-9 Move
5 - Place/improve fence ($1), expensive fence can kill monsters.
c - Place cow ($20)
t - Wait for next season/horde to come

GOAL

Your goal is to reach 2000$ to pay tax to the Evil High Chancellor.
At the beginning of each season you get $10 per cow.
You loose when you are out of money.

The game is quite fun and the goal is reachable :)

regards,
Jakub


Inuga...@gmail.com

unread,
Sep 8, 2008, 12:15:31 AM9/8/08
to
Whenever I press "t", press "c" without enough funds, or press any
other key that's not a movement key, a wall will be built. It's
annoying when you can't not move (stand still) or build because the
the playing field starts getting smaller every time you press 't'.
0 new messages