#include <ctime>
#include <cstdlib>
#include <curses.h>
#include <iostream>
using namespace std;
/***************************/
const int viewY=23; //height of view
const int viewX=40; //1/2 width of veiw
const int Y=53; //height of world
const int X=101; //width of world
int SAND[Y][X];
bool wall[Y][X];
int WATER[Y][X];
int water[Y][X];
int CHART[Y][X];
int chart[Y][X]; //up down left right
int tree[Y][X];
int cursorX=0;
int cursorY=0;
char inchar;
int windY=1; //wind direction
int windX=1;
int showSlope=0;
bool instructions=0;
int Time=16384*4;
char view[Y][X];
/***************************/
void sleep();
void print();
void init();
void wind();
void input();
void flow();
void land(int y, int x, int a, int b);
void grow();
void calc();
/***************************/
int main()
{
WINDOW *window;
window = initscr(); // set up the curses window
nodelay(window,1); // don't wait for user input
srand(time(NULL)); // initializes the random number generator
clear(); // clear the window
noecho(); // don't show typed characters on the screen
init();
for(int i=0; i<5; i++)
calc();
while(inchar!='q') //press q to quit
{
print();
if(instructions==0)
{
wind();
flow();
grow();
}
input();
sleep(); // wait a bit
}
refresh();
echo(); // turn echoing back on before exiting
endwin(); // end curses control of the window
}
/***************************/
void init()
{
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
view[y][x]=' ';
WATER[y][x]=0;
SAND[y][x]=rand()%3;
wall[y][x]=0;
CHART[y][x]=rand()%4;
tree[y][x]=0;
}
}
}
/***************************/
void print()
{
int a,b;
for(int y=0; y<Y; y++)
{
a= (y+Y+cursorY)%Y;
for(int x=0; x<X; x++)
{
b= (x+X+cursorX)%X;
if(showSlope==1)
{
if(CHART[a][b]==0)
view[y][x]='^';
else if(CHART[a][b]==1)
view[y][x]='<';
else if(CHART[a][b]==2)
view[y][x]='v';
else if(CHART[a][b]==3)
view[y][x]='>';
}
if(CHART[a][b]==4)
view[y][x]='o';
//*/
if(SAND[a][b]>4)
view[y][x]=';';
else if(SAND[a][b]>1)
view[y][x]=',';
else if(SAND[a][b]>0)
view[y][x]='.';
//*/
if(WATER[a][b]>1)
view[y][x]='~';
else if(WATER[a][b]>0)
view[y][x]='-';
if(tree[a][b]==1)
view[y][x]='%';
else if(tree[a][b]==2)
view[y][x]='*';
if(wall[a][b]==1)
view[y][x]='#';
}
}
view[viewY/2][viewX/2]='@';
clear();
if(instructions==0)
{
for(int y=0; y<viewY; y++)
{
for(int x=0; x<viewX; x++)
{
mvaddch(y, x*2, view[y][x]);
view[y][x]=' ';
}
}
}
else
{
char strng[][34]={
"\'w\' \'a\' \'s\' \'d\' to move ",
"SPACE to place or remove a wall ",
"\'z\' to change the wind ",
"\'t\' to slow down ",
"\'r\' to speed up ",
"\'q\' to quit ",
"\'x\' to dig a hole ",
"\'v\' to plant a tree ",
" ",
" . is blowing sand ",
" , is more sand ",
" ; is piled sand ",
" - is shallow water ",
" ~ is deeper water ",
" # is a wall ",
" % is a tree ",
" * is a dead tree ",
" @ is you ",
" ",
"Press SPACE to return to the game"};
for(int y=0; y<viewY; y++)
{
for(int x=0; x<viewX; x++)
{
if(y<20 && x<33)
mvaddch(y, x, strng[y][x]);
view[y][x]=' ';
}
}
}
refresh(); // refresh the screen
}
/***************************/
// function that waits a little while, keeps the game slow
void sleep()
{
clock_t goal = Time + clock();
while (goal > clock());
}
/***************************/
void input()
{
int y=(cursorY+viewY/2)%Y;
int x=(cursorX+viewX/2)%X;
inchar = char(getch());
if(inchar != ERR)
{
if(instructions==0)
{
if(inchar=='w')
cursorY=(cursorY+Y-1)%Y;
else if(inchar=='s')
cursorY=(cursorY+1)%Y;
else if(inchar=='a')
cursorX=(cursorX+X-1)%X;
else if(inchar=='d')
cursorX=(cursorX+1)%X;
else if(inchar=='v')
tree[y][x]=1;
else if(inchar=='f')
showSlope^=1;
else if(inchar=='x')
{
CHART[y][x]=4;
CHART[(y+1)%Y][x]=0;
CHART[y][(x+1)%X]=1;
CHART[(y+Y-1)%Y][x]=2;
CHART[y][(x+X-1)%X]=3;
}
else if(inchar=='r')
Time/=2;
else if(inchar=='t')
{
if(Time==0)
Time=1;
Time*=2;
}
else if(inchar=='z')
{
if(windX==1)
{
windY+=2;
windY=windY%3-1;
}
windX+=2;
windX=windX%3-1;
}
else if(inchar=='?')
instructions=1;
else if(inchar==' ')
wall[y][x]^=1;
}
else
{
if(inchar==' ')
instructions=0;
}
}
}
/***************************/
void wind()
{
int sand[Y][X];
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
sand[y][x]=SAND[y][x]; //get a copy of the perminent record
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
for(int a=(y+Y-1)%Y; a!=(y+2)%Y; a=(a+1)%Y)
{
//choose a square one above this and iterate until one below
for(int b=(x+X-1)%X; b!=(x+2)%X; b=(b+1)%X)
{
//choose a square one to the left of this and iterate until one to the right
int temp=SAND[y][x]-SAND[a][b];
//the sand falls over if it piles too high
if(temp/10>0 && !wall[a][b] && !tree[a][b])
{
sand[y][x]--;
sand[a][b]++;
}
}
}
// erode
int temp = SAND[y][x];
if(temp!=0 && rand()%(temp+WATER[y][x])==0 && (!tree[(y+windY+Y)%Y][(x+windX+X)%X] || rand()%2) && !wall[(y+windY+Y)%Y][(x+windX+X)%X])
{
sand[(y+windY+Y)%Y][(x+windX+X)%X]++;
sand[y][x]--;
}
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
SAND[y][x] = sand[y][x]; //record it on the perminent record
}
}
}
/***************************/
void flow()
{
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
water[y][x]=WATER[y][x];
chart[y][x]=CHART[y][x];
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
if(WATER[y][x])
{
for(int a=(y+Y-1)%Y; a!=(y+3)%Y; a=(a+2)%Y)
{
land(y,x,a,x);
}
for(int b=(x+X-1)%X; b!=(x+3)%X; b=(b+2)%X)
{
land(y,x,y,b);
}
}
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
if(water[y][x]>0 && (SAND[y][x]-water[y][x])>0) //evaporate
{
if((rand()%(SAND[y][x]-water[y][x]))/7)
water[y][x]--;
}
water[0][0]+=2; //a spring
WATER[y][x] = water[y][x];
CHART[y][x]=chart[y][x];
}
}
}
/***************************/
void land(int y, int x, int a, int b)
{
int c;
int temp=0;
if(a==(y+Y-1)%Y)
c=0;
else if(b==(x+X-1)%X)
c=1;
else if(a==(y+1)%Y)
c=2;
else if(b==(x+1)%X)
c=3;
if(CHART[y][x]==c)
temp++;
else if(CHART[y][x]==(c+10)%8) //if we slope away from that directio
temp--;
else if(CHART[a][b]==(c+10)%8) //if that direction slopes toward us
temp--;
temp+=(WATER[y][x]-WATER[a][b]-SAND[a][b])/5;
if(temp>0 && !wall[a][b])
{
water[y][x]--;
water[a][b]++;
chart[y][x]=c;
}
}
/***************************/
void grow()
{
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
if(WATER[y][x]==1 && SAND[y][x]>1 && rand()%64==0)
tree[y][x]=1;
else if(tree[y][x]==1 && WATER[y][x]==0 && rand()%128==0)
tree[y][x]=2;
else if(tree[y][x]==2 &&rand()%512==0)
tree[y][x]=0;
}
}
}
/***************************/
void calc()
{
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
chart[y][x]=CHART[y][x];
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
for(int a=(y+Y-1)%Y; a!=(y+2)%Y; a=(a+1)%Y)
{
for(int b=(x+X-1)%X; b!=(x+2)%X; b=(b+1)%X)
{
if(CHART[y][x]==(CHART[a][b]+10)%8 && CHART[y][x]!=5)
chart[y][x]=rand()%4; //reshufles any arrows that don't fit
}
}
}
}
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
CHART[y][x]=chart[y][x];
}
}
}
/***************************/