Author Topic: 1kbrl - Sources in C++ and FreeBASIC  (Read 8624 times)

Tapio

  • Newcomer
  • Posts: 46
  • Karma: +2/-1
    • View Profile
    • Email
1kbrl - Sources in C++ and FreeBASIC
« on: February 15, 2010, 03:25:42 PM »
I wanted to see how easily I could get coloured terminal output and key input with C++ and when it started to look promising, I decided to turn it into a <1kb roguelike. After that I wanted to see if could I do the same with FreeBASIC and so I ported the code and succeeded. :)

The game is somewhat inspired by RogueLight and has the following features:
    * Colored output
    * Random dungeons
    * Field of view
    * Torch affects vision
    * Death
The idea is to descend in to the darkness (keys: WASD), collect coins and keep your torch burning.

You can browse and see files, read README, download binaries etc etc here: http://github.com/tapio/1kbrl
(Note: in Windows, you'll probably want the FB version, since the C++ uses ANSI escape codes for colors)

PS. for awesome Git people, a clone URL:
Code: [Select]
git clone git://github.com/tapio/1kbrl.git

Hi

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 154
  • Karma: +0/-0
    • View Profile
    • Email
Re: 1kbrl - Sources in C++ and FreeBASIC
« Reply #1 on: February 15, 2010, 09:33:56 PM »
If there is a coin on your starting position you have to move off and then back on to pick it up.

Other than that, great job. It's simple, colorful, and it works

Ok I've been having fun with the source code (adding torch refills making it so bumping into walls doesn't use a move or torch)
there is one thing I don't quite understand
what does the 1 << 1 mean in
#define COIN (1 << 1)
« Last Edit: February 15, 2010, 10:29:52 PM by Hi »

Tapio

  • Newcomer
  • Posts: 46
  • Karma: +2/-1
    • View Profile
    • Email
Re: 1kbrl - Sources in C++ and FreeBASIC
« Reply #2 on: February 16, 2010, 07:36:03 AM »
there is one thing I don't quite understand
what does the 1 << 1 mean in
#define COIN (1 << 1)
<< is a shift-left operator, meaning that the bit positions of the left side are shifted left by the right side amount. Effectively this means multiplying by 2 for each 1 in right.
1 << 1 thus becomes 10 in binary which in turn is 2 in decimal. I use bitfields to be able to have different items on same tile, so the values need to be powers of two (1,2,4,8,16). By using the shift operator, the sequence transforms into a linear one:
Code: [Select]
1 << 0     = 000001  = 1
1 << 1     = 000010  = 2
1 << 2     = 000100  = 4
1 << 3     = 001000  = 8
1 << 4     = 010000  = 16
1 << 5     = 100000  = 32
etc.
etc.
So in this case, it's just another way of writing things.

(In general, bitshifts are very fast calculations, but you rarely need to use them, because modern compilers can automatically optimize e.g. multiplying by 4 to being a bitshift.)

Hi

  • 7DRL Reviewer
  • Rogueliker
  • *
  • Posts: 154
  • Karma: +0/-0
    • View Profile
    • Email
Re: 1kbrl - Sources in C++ and FreeBASIC
« Reply #3 on: February 17, 2010, 12:02:22 AM »
This is a really fun little game
I'm posting my modifications for fun
the little red 0s are oil so that you can last a little longer

Code: [Select]
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
 
#define CLS std::cout << "\033[2J";
#define ESC "\e["
#define BLACK ESC << "0;30m"
#define RED ESC << "0;31m"
#define GREEN ESC << "0;32m"
#define YELLOW ESC << "0;33m"
#define BLUE ESC << "0;34m"
#define MAGENTA ESC << "0;35m"
#define CYAN ESC << "0;36m"
#define WHITE ESC << "0;37m"
#define DEFAULT ESC << "0;39m"
 
#ifdef WIN32
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
int getch( )
{
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
#endif
 
#define FLOOR 0
#define WALL 1
#define COIN (1 << 1)
#define STAIRS_DOWN (1 << 2)
#define STAIRS_UP (1 << 3)
#define TORCH (1 << 4)
#define OIL (1 << 5)
 
#define MAPSIZE 15
 
int x, y;
int coins = 0, moves = 0, torch = 30, level = 1;
int lvl[MAPSIZE][MAPSIZE];
 
 
void gen(int seed) {
srand(seed);
for (int X = 0; X < MAPSIZE; X++)
{
for (int Y = 0; Y < MAPSIZE; Y++)
{
if (X == 0 || X == MAPSIZE-1 || Y == 0 || Y == MAPSIZE-1 || rand() % 10 == 0)
lvl[X][Y] = 1;
else if (rand() % 20 == 0) //add something to the map
{
if (rand() % 3 == 0)
lvl[X][Y] = OIL;
else
lvl[X][Y] = COIN;
}
else
lvl[X][Y] = 0;
}
}
#define randcoord (1+rand()%(MAPSIZE-2))
x = randcoord;
y = randcoord;
lvl[x][y] ^= STAIRS_DOWN;
lvl[randcoord][randcoord] = STAIRS_UP;
}
 
void draw() {
CLS;
std::cout << YELLOW << "Coins: " << WHITE << coins << std::endl;
std::cout << RED << "Torch: " << WHITE << torch << std::endl;
std::cout << MAGENTA << "Moves: " << WHITE << moves << std::endl;
std::cout << GREEN << "Level: " << WHITE << level << std::endl;
for (int Y = 0; Y < MAPSIZE; Y++)
{
for (int X = 0; X < MAPSIZE; X++)
{
if (X == x && Y == y)
std::cout << WHITE << "@";
// controls your view size
else if (pow(x-X,2) + pow(y-Y,2) > std::min(49,torch/2) )
std::cout << " ";
else if (lvl[X][Y] == 0)
std::cout << BLUE << ".";
else if (lvl[X][Y] & WALL)
std::cout << CYAN << "#";
else if (lvl[X][Y] & COIN)
std::cout << YELLOW << "$";
else if(lvl[X][Y] & OIL)
std::cout << RED << "0";
else if (lvl[X][Y] & STAIRS_DOWN)
std::cout << RED << "<";
else if (lvl[X][Y] & STAIRS_UP)
std::cout << GREEN << ">";
else if (lvl[X][Y] & TORCH)
std::cout << RED << "f";
}
std::cout << std::endl;
}
}
 
 
int main() {
gen(level);
std::cout << GREEN << "Welcome!" << std::endl;
while (true)
{
// Drawing
draw();
// Input
char k = getch();
int oldx = x, oldy = y;
if (k == 'a')
--x;
else if (k == 'd')
++x;
else if (k == 'w')
--y;
else if (k == 's')
++y;
else if (k == 'q')
break;
// Collisions
if (lvl[x][y] & WALL)
{
x = oldx;
y = oldy;
}
else if (lvl[x][y] & COIN)
{
coins++;
lvl[x][y] ^= COIN;
}
else if (lvl[x][y] & OIL)
{
torch+=7;
lvl[x][y] ^= OIL;
}
else if (lvl[x][y] & TORCH)
{
torch++;
lvl[x][y] ^= TORCH;
}
else if (lvl[x][y] & STAIRS_UP)
gen(++level);
// successful move means torch used up
if(oldy != y || oldx != x)
{
++moves;
--torch;
}
// Die
if (torch <= 0)
break;
}
std::cout << DEFAULT;
return 0;
}