1
0
mirror of https://github.com/abakh/nbsdgames.git synced 2024-12-04 14:46:22 -05:00

Second version

This commit is contained in:
untakenstupidnick 2019-03-20 17:46:33 +03:30
parent e6e0db8894
commit e2bfedbee1
23 changed files with 4237 additions and 0 deletions

62
README.rst Normal file
View File

@ -0,0 +1,62 @@
New BSD Games
-------------
You have a computing machine from 1980's and you wonder how can you use it?
You deal with a GUI-less machine at work and are looking for ways to kill time?
You have to make a Reversi AI for your homework and you don't know where to copy it from?
You have been so excited about the bsdgames, but have grown tired of playing tetris, snake and robots for billions of times?
You feel they have fooled you by bundling stuff like phantasia with a package you except to contain GAMES?
Don't worry anymore as you've got nbsdgames now!
I originally made these to be added to NetBSD (but the few i talked with preferred to have games in the repositories rather than in /usr/games itself).
These include:
Jewels (A game with a gameplay kinda similiar to that of Tetris, NOT my invention)
Sudoku
Mines (Minesweeper)
Reversi
Checkers
Battleship
Post Made-for-NetBSD games:
SOS
Rabbithole (A maze-exploring game where you have to gather items from all around the maze rather reaching an end,the idea maybe mine)
Pipes (Same as the famous Pipe Mania, unplayable on the environments that don't support the line characters)
Prerequisites
-------------
* make (optional)
* A C compiler with C99 enabled
* The standard library
* libncurses (the dev package if you are on debian-based distros)
How to run
----------
1) Download the files
2) Go to the sources directory
3) Set the environment variable PREFIX to the address you want them to be in
4) Install
Like this:
.. code:: bash
cd ~/Downloads/sources
export PREFIX= ~/bin
make install
How do these look like
-----------------------
.. image:: https://raw.githubusercontent.com/untakenstupidnick/new-bsd-games/master/screenshot.png
License
-------
No rights reserved.
I am living outside the Berne convention and therefore no meaningful licensing can be applied (meaning that it's public domain in most of the world).

BIN
banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
linux_exec/battleship Executable file

Binary file not shown.

BIN
linux_exec/checkers Executable file

Binary file not shown.

BIN
linux_exec/jewels Executable file

Binary file not shown.

BIN
linux_exec/mines Executable file

Binary file not shown.

BIN
linux_exec/pipes Executable file

Binary file not shown.

BIN
linux_exec/rabbithole Executable file

Binary file not shown.

BIN
linux_exec/reversi Executable file

Binary file not shown.

BIN
linux_exec/sos Executable file

Binary file not shown.

BIN
linux_exec/sudoku Executable file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

31
sources/Makefile Normal file
View File

@ -0,0 +1,31 @@
# -*- Makefile -*-
all: jewels sudoku mines reversi checkers battleship rabbithole sos pipes
jewels: jewels.c config.h
$(CC) jewels.c -lncurses -o ./jewels
sudoku: sudoku.c
$(CC) sudoku.c -lncurses -lm -o ./sudoku
mines: mines.c
$(CC) mines.c -lncurses -o ./mines
reversi: reversi.c
$(CC) reversi.c -lncurses -o ./reversi
checkers: checkers.c
$(CC) checkers.c -lncurses -o ./checkers
battleship: battleship.c
$(CC) battleship.c -lncurses -o ./battleship
rabbithole: rabbithole.c
$(CC) rabbithole.c -lncurses -o ./rabbithole
sos: sos.c
$(CC) sos.c -lncurses -o ./sos
pipes: pipes.c config.h
$(CC) pipes.c -lncurses -o ./pipes
clean:
rm ./jewels ./sudoku ./checkers ./mines ./reversi ./battleship ./rabbithole ./sos ./pipes
uninstall:
rm $(PREFIX)/jewels $(PREFIX)/sudoku $(PREFIX)/checkers $(PREFIX)/mines $(PREFIX)/reversi $(PREFIX)/battleship $(PREFIX)/rabbithole $(PREFIX)/sos $(PREFIX)/pipes
copy_sources:
cp Makefile config.h jewels.c sudoku.c mines.c reversi.c checkers.c battleship.c rabbithole.c sos.c pipes.c $(PREFIX)
install: all
cp jewels sudoku mines reversi checkers battleship rabbithole sos pipes $(PREFIX)

618
sources/battleship.c Normal file
View File

@ -0,0 +1,618 @@
#include <curses.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <signal.h>
#define MISS -2
#define SEA -1
#define HIT 0
#define ENGLISH_LETTERS 26
#define NOTHING -1
#define ALL 0x7c
#define RED 3
#define CYAN 2
/*
_
|_)
|_)ATTLESHIP
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
typedef unsigned char bitbox;
bool multiplayer;
byte py,px;//cursor
chtype colors[4]={0};
byte game[2][10][10];//main board
bool computer[2] = {0};
byte score[2] = {0};//set by header()
bitbox sunk[2]={0};
byte just_sunk[2]={0};//to be displayed for human players
byte firstinrowy , firstinrowx ;
byte lastinrowy ,lastinrowx;
byte goindirection;
byte shotinvain;
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(bool ingame){
MEVENT minput;
getmouse(&minput);
if(minput.bstate & (BUTTON1_CLICKED|BUTTON1_RELEASED)){
if( minput.y-4 < 10){
if( (ingame && minput.x-23<20 && minput.x-23>=0 ) || (!ingame && minput.x-1<20) ){//it most be on the trackboard if ingame is true
py=minput.y-4;
px=(minput.x-1-(ingame*2)) /2;
}
}
else
return;
}
if(minput.bstate & (BUTTON1_CLICKED|BUTTON1_RELEASED))
ungetch('\n');
if(minput.bstate & (BUTTON2_CLICKED|BUTTON2_RELEASED|BUTTON3_CLICKED|BUTTON3_RELEASED) )
ungetch('r');
}
void rectangle(byte sy,byte sx){
for(byte y=0;y<=10+1;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+10*2,ACS_VLINE);
}
for(byte x=0;x<=10*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+10+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+10+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+10*2,ACS_URCORNER);-
mvaddch(sy+10+1,sx+10*2,ACS_LRCORNER);
}
void print_type(byte type){
switch(type){
case(2):
addstr("patrol boat");
break;
case(3):
addstr("destroyer");
break;
case(4):
addstr("battleship");
break;
case(5):
addstr("carrier");
break;
case(6):
addstr("submarine");
break;
}
}
void MID(byte *y , byte *x, byte direction){
switch(direction){
case(0):
*x=*x-1;
break;
case(1):
*y=*y-1;
break;
case(2):
*x=*x+1;
break;
case(3):
*y=*y+1;
break;
}
}
void genocide(bool side , byte type){
byte y,x;
for(y=0;y<10;y++){
for(x=0;x<10;x++){
if(game[side][y][x] == type)
game[side][y][x] = SEA;
}
}
}
void header(bool side){
score[0]=score[1]=0;
byte y,x;
for(y=0;y<10;y++){
for(x=0;x<10;x++){
if(game[!side][y][x] == HIT)
score[side]++;
if(game[side][y][x] == HIT)
score[!side]++;
}
}
mvaddch(0,1, '_');
mvprintw(1,0,"|_) %2d:%2d",score[side],score[!side]);
mvprintw(2,0,"|_)ATTLESHIP ");
}
void draw(bool side,byte sy,byte sx){//the game's board
rectangle(sy,sx);
chtype ch ;
byte y,x;
for(y=0;y<10;y++){
for(x=0;x<10;x++){
ch =A_NORMAL;
if(y==py && x==px)
ch |= A_STANDOUT;
if(game[side][y][x] == HIT)
ch |= 'X'|colors[RED];
else if(game[side][y][x] > 0 )
ch |= ACS_BLOCK|colors[side];
else if(game[side][y][x]== MISS)
ch |= 'O'|colors[CYAN];
else
ch |= '~'|colors[CYAN];
mvaddch(sy+1+y,sx+x*2+1,ch);
}
}
}
void draw_trackboard(bool side,byte sy,byte sx){
rectangle(sy,sx);
chtype ch ;
byte y,x;
for(y=0;y<10;y++){
for(x=0;x<10;x++){
ch =A_NORMAL;
if(y==py && x==px-10)
ch |= A_STANDOUT;
if(game[!side][y][x] == HIT)
ch |= '*'|colors[RED];
else if(game[!side][y][x]== MISS)
ch |= '~'|colors[CYAN];
else
ch |= '.';
mvaddch(sy+1+y,sx+x*2+1,ch);
}
}
refresh();
}
void autoset(bool side){
byte y=0,x=0,direction=0, invain=0;
byte realy,realx;
byte l;
for(byte type=2;type<7;type++){
SetLocation:
realy=random()%10;
realx=random()%10;
invain=0;
SetDirection:
y=realy;
x=realx;
direction=random()%4;
for(l=0;(type != 6 && l<type) || (type==6 && l<3) ; l++){//there are two kinds of ship sized 3 tiles
if( y<0 || x<0 || y>=10 || x>=10 || game[side][y][x] != SEA ){
genocide(side,type);
invain++;
direction= (direction+1)%4;
if(invain<4)
goto SetDirection;
else
goto SetLocation;//endless loop
}
else{
game[side][y][x]=type;
MID(&y,&x,direction);
}
}
}
}
void set_the_board(bool side){
if( computer[side] ){
autoset(side);
return;
}
erase();
mvaddch(0,1, '_');
mvaddstr(1,0,"|_) Set your board");
mvaddstr(2,0,"|_)ATTLESHIP");
mvaddstr(16,0,"Press RETURN to specify the location and press R to rotate the ship.");
int input;
byte y=0,x=0,direction=0, invain=0;
byte realy,realx;
byte l;
py=px=0;
for(byte type=2;type<7;type++){
mvaddstr(15,0,"Put your ");
print_type(type);
addstr(" in its position: ");
SetLocation:
while(1){
draw(side,3,0);
refresh();
input = getch();
if( input == KEY_MOUSE )
mouseinput(0);
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<9)
py++;
if( (input=='h' || input==KEY_LEFT) && px>0)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<9)
px++;
if( input=='\n' )
break;
if( input=='q' )
sigint_handler(EXIT_SUCCESS);
}
realy=y=py;
realx=x=px;
invain=0;
SetDirection:
y=realy;
x=realx;
for(l=0;(type != 6 && l<type) || (type==6 && l<3) ; l++){//there are two kinds of ship sized 3 tiles
if( y<0 || x<0 || y>=10 || x>=10 || game[side][y][x] != SEA ){
genocide(side,type);
invain++;
direction= (direction+1)%4;
if(invain<4)
goto SetDirection;
else
goto SetLocation;//endless loop
}
else{
game[side][y][x]=type;
MID(&y,&x,direction);
}
}
while(1){
invain=0;
draw(side,3,0);
input=getch();
if( input== 'r' || input == 'R' ){
genocide(side,type);
direction= (direction+1)%4;
goto SetDirection;
}
else if(input == KEY_MOUSE)
mouseinput(0);
else
break;
}
}
}
void turn_shift(void){
if(!multiplayer)
return;
char key = 'a'+(random()%ENGLISH_LETTERS);
int input1,input2,input3;
input1=input2=input3=0;
erase();
beep();
mvaddch(0,1, '_');
mvaddstr(1,0,"|_) Anti-cheater");
mvaddstr(2,0,"|_)ATTLESHIP");
mvaddstr(4,0,"********************");
mvprintw(5,0," Type '%c' 3 times ",key);
mvaddstr(6,0," before ");
mvaddstr(7,0," proceeding ");
mvaddstr(8,0," to the game ");
mvaddstr(10,0,"********************");
refresh();
while(1){
input3=input2;
input2=input1;
input1=getch();
if( (input1==input2) && (input2==input3) && (input3==key) )
break;
}
erase();
}
byte shoot(bool turn, byte y , byte x){
byte s = game[!turn][y][x];
if(s>0){
game[!turn][y][x]=HIT;
return 1;
}
else if(s==HIT || s==MISS || y<0 || x<0 || y>9 || x>9 ){ //didn't shoot at all
return NOTHING;
}
else{
game[!turn][y][x]=MISS;
return 0;
}
}
void sink_announce(bool side){
byte type,y,x;
for(type=2;type<7;type++){
for(y=0;y<10;y++){
for(x=0;x<10;x++){
if( game[!side][y][x] == type )
goto Next;
}
}
//there is no instance of 'type' in the opponet's board
if( ( (1 << type) | sunk[!side] ) != sunk[!side] ){
sunk[!side] |= (1 << type);
if(computer[side]){
lastinrowy=lastinrowx=firstinrowy=firstinrowx=-1;
shotinvain=0;
}
else{
just_sunk[!side]=type;//leave to be displayed by you_sunk
}
return;
}
Next:
continue;
}
}
void you_sunk(bool side){
if( just_sunk[!side] == 3)
mvaddstr(15,0,"You have destroyed my destroyer!!");
else if( just_sunk[!side]){
mvaddstr(15,0,"You have sunk my ");
print_type(just_sunk[!side]);
addstr("!!");
}
just_sunk[!side]=0;
}
void cheat(bool side){
/* its actually an anti-cheat, the player can place all their ships adjacent to the others and in the same direction,
and the algorithm will often play in a way that it will be left with one or two isolated tiles being unshot (with their respective ships being shot before).
in a such a situation a human will *very easily* find the tiles with logical thinking, but the computer shoots randomly and it will take such a long time for it
that it will often lose the winning game.
this function still doesn't make a win,it's randomly executed.*/
byte y,x;
for(y=0;y<10;y++){
for(x=0;x<10;x++){
if(game[!side][y][x]>0){
shoot(side,y,x);
firstinrowy=y;
firstinrowx=x;
return;
}
}
}
}
void decide(bool side){// sink_announce is responsible for unsetting the global variables involved
byte y,x,r;
Again:
if( firstinrowy == NOTHING ){
if( score[side] > 14 && score[side]<score[!side] && random()%2 ){
cheat(side);
return;
}
while(1){
y = random()%10;
x = random()%10;
r = shoot(side,y,x);
if(r == 1){
firstinrowy=y;
firstinrowx=x;
}
if(r != NOTHING)
return;
}
}
else if( lastinrowy ==NOTHING ){
if(goindirection == NOTHING)
goindirection = random()%4;
while(1){
y= firstinrowy;//we know there is hit already
x= firstinrowx;
MID(&y,&x,goindirection);
r= shoot(side,y,x);
if( r != 1 ){
goindirection = (goindirection+1)%4;//the ship is oriented in another way then
shotinvain++;
if(shotinvain==4){ // this only occurs in case of a ship being shot before but not sunk ( e.g. in exprimenting for the direction)
shotinvain=0;
y=firstinrowy;
x=firstinrowx;
goindirection = (goindirection+1)%4;
while(game[!side][y][x]==HIT){//go till you reach an unshot tile
MID(&y,&x,goindirection);
if( (y<0 || x<0 || y>9 || x>9) && r==NOTHING){
goto Again;
}
}
r= shoot(side,y,x);//(y,x) may be MISS, but its impossible for it to be empty water, as executing this means it has tested every direction before
if(r==1){
lastinrowy=y;//continue from the imaginary firstinrow
lastinrowx=x;
}
if(r==NOTHING)
goto Again;
}
}
else{
lastinrowy= y;
lastinrowx= x;
}
if( r != NOTHING )
return;
}
}
else{
y=lastinrowy;
x=lastinrowx;
MID(&y,&x,goindirection);
r=shoot(side,y,x);
if( r == 1 ){
lastinrowy=y;
lastinrowx=x;
}
else{
lastinrowy=lastinrowx=NOTHING;
goindirection=(goindirection+2)%4;
}
if( r != NOTHING )
return;
else{
goto Again;
}
}
}
void help(bool side){//side is only there to feed header()
erase();
header(side);
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(9,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"RETURN/ENTER : Shoot");
mvprintw(5,0,"R : Rotate");
mvprintw(6,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(7,0,"q : Quit");
mvprintw(8,0,"F1 & F2 : Help on controls & gameplay");
mvprintw(11,0,"Press a key to continue");
getch();
erase();
}
void gameplay(bool side){//side is only there to feed header()
erase();
header(side);
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("Guess the location of your opponet's\n");
printw("ships and sink them! The player\n");
printw("who sinks all the opponet's ships wins.");
getch();
erase();
}
int main(void){
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
curs_set(0);
noecho();
cbreak();
keypad(stdscr,1);
if( has_colors() ){
start_color();
use_default_colors();
init_pair(1,COLOR_GREEN,-1);
init_pair(2,COLOR_YELLOW,-1);
init_pair(3,COLOR_CYAN,-1);
init_pair(4,COLOR_RED,-1);
for(byte b=0;b<4;b++)
colors[b]=COLOR_PAIR(b+1);
}
int input;
printw("Choose type of the game:\n");
printw("1 : Single Player*\n");
printw("2 : Multi Player\n");
input=getch();
if(input == '2'){
multiplayer=1;
computer[1]=computer[0]=0;
}
else{
multiplayer=0;
computer[1]=1;
computer[0]=0;
}
Start:
firstinrowy=firstinrowx=lastinrowy=lastinrowx=goindirection=-1;
shotinvain=0;
sunk[0]=sunk[1]=0;
memset(game,SEA,200);
srandom(time(NULL)%UINT_MAX);
erase();
set_the_board(0);
turn_shift();
set_the_board(1);
bool won;
bool turn=1;
Turn:
px=10;
py=0;
sink_announce(turn);
if( sunk[0]==ALL ){
won=1;
goto End;
}
else if( sunk[1]==ALL ){
won=0;
goto End;
}
//the turn starts HERE
turn=!turn;
turn_shift();
if( computer[turn] ){
decide(turn);
goto Turn;
}
else{
erase();
you_sunk(turn);
while(1){
header(turn);
draw(turn,3,0);
draw_trackboard(turn,3,22);
refresh();
input=getch();
if(input == KEY_F(1) || input=='?' )
help(turn);
if(input == KEY_F(2) )
gameplay(turn);
if(input == KEY_MOUSE)
mouseinput(1);
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<9)
py++;
if( (input=='h' || input==KEY_LEFT) && px>10)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<19)
px++;
if( input=='q')
sigint_handler(EXIT_SUCCESS);
if( input=='\n'){
byte r=shoot(turn,py,px-10);
if(r != -1){
goto Turn;
}
}
}
}
End:
erase();
header(won);
draw(won,3,0);
draw_trackboard(won,3,22);
if( computer[won] )
mvaddstr(15,0,"Hahaha! I won! ");
else
mvprintw(15,0,"Player %d won the game.",won+1);
addstr(" Wanna play again? (y/n)");
refresh();
curs_set(1);
input=getch();
if( input!='n' && input !='N' && input!='q' ){
curs_set(0);
goto Start;
}
endwin();
return 0;
}

678
sources/checkers.c Normal file
View File

@ -0,0 +1,678 @@
#include <curses.h>
#include <string.h>
#include <time.h>
#include <float.h>
#include <limits.h>
#include <stdlib.h>
#include <signal.h>
#include <math.h>
#define LIGHT -1
#define DARK 1
#define KING 2
#define DOESNT_MATTER 1
#define IMAGINARY 0
#define NORMAL 1
#define ALT_IMG 2
#define ALT_NRM 3
#define WIN 100000
/*
.-.
| '
'._.HECKERS
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
Compile with -lncurses
*/
typedef signed char byte;
byte py,px;//cursor
byte cy,cx;//selected(choosen) piece
int dpt;
byte game[8][8];
byte computer[2]={0,0};
byte score[2];//set by header()
bool endgame=false;
byte jumpagainy , jumpagainx;
bool kinged;//if a piece jumps over multiple others and becomes a king it cannot continue jumping
bool in(byte A[4],byte B[4],byte a,byte b){
for(byte c=0;c<4;c++)
if(A[c]==a && B[c]==b)
return true;
return false;
}
void rectangle(byte sy,byte sx){
byte y,x;
for(y=0;y<=8+1;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+8*2,ACS_VLINE);
}
for(x=0;x<=8*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+8+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+8+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+8*2,ACS_URCORNER);
mvaddch(sy+8+1,sx+8*2,ACS_LRCORNER);
}
void header(void){
score[0]=score[1]=0;
byte y,x;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if(game[y][x]){
if(game[y][x]<0)
score[0]++;
else
score[1]++;
}
}
}
mvprintw(0,0," .-.");
mvprintw(1,0,"| ' %2d:%2d",score[0],score[1]);
mvprintw(2,0,"'._,HECKERS ");
}
void draw(byte sy,byte sx){//the game's board
rectangle(sy,sx);
chtype ch ;
byte y,x;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
ch=A_NORMAL;
if(y==py && x==px)
ch |= A_STANDOUT;
if(y==cy && x==cx)
ch |= A_BOLD;
if(game[y][x]){
if(game[y][x]<0){
if(has_colors())
ch|=COLOR_PAIR(1);
else
ch |= A_UNDERLINE;
}
if(abs(game[y][x])<2)
ch |='O';
else
ch |='K';
}
else if( (y%2) != (x%2) )
ch|='.';
else
ch|=' ';
mvaddch(sy+1+y,sx+x*2+1,ch);
}
}
}
//place the pieces on the board
void fill(void){
byte y,x;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
game[y][x]=0;
if( (y%2) != (x%2)){
if(y<3) game[y][x]=1;
if(y>4) game[y][x]=-1;
}
}
}
}
//fill mvy/x with possible moves
bool moves(byte ty,byte tx,byte mvy[4],byte mvx[4]){
bool ret=0;
byte ndx=0;
byte t= game[ty][tx];
move(15,0);
byte dy,dx;
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if( !dy || !dx || (!ty && dy<0) || (!tx && dx<0) || (dy==-t) || (ty+dy>=8) || (tx+dx>=8) )
;
else if(!game[ty+dy][tx+dx]){
ret=1;
mvy[ndx]=ty+dy;
mvx[ndx]=tx+dx;
ndx++;
}
else
ndx++;
}
}
return ret;
}
//would be much faster than applying moves() on every tile
bool can_move(byte side){
byte y , x ,t, dy , dx;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if( (t=game[y][x])*side > 0 ){
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if( !dy || !dx || (!y && dy<0) || (!x && dx<0) || (dy==-t) || (y+dy>=8) || (x+dx>=8) )
;
else if( !game[y+dy][x+dx] )
return 1;
}
}
}
}
}
return 0;
}
//fill mvy/x with possible jumping moves
bool jumps(byte ty,byte tx,byte mvy[4],byte mvx[4]){
bool ret=0;
byte ndx=0;
byte ey,ex;
byte t= game[ty][tx];
byte dy,dx;
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
ey = dy*2;
ex = dx*2;
if(!dy || !dx ||(dy==-t)|| (ty+ey<0) || (tx+ex<0) || (ty+ey>=8) || (tx+ex>=8) )
;
else if(!game[ty+ey][tx+ex] && game[ty+dy][tx+dx]*t<0){
ret=1;
mvy[ndx]=ty+ey;
mvx[ndx]=tx+ex;
ndx++;
}
else
ndx++;
}
}
return ret;
}
//same as can_move for jumps
byte can_jump(byte ty,byte tx){
byte dy,dx,t=game[ty][tx];
byte ey,ex;
byte ret=0;
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
ey=dy*2;
ex=dx*2;
if((dy==-t)||(ty+ey<0)||(tx+ex<0)||(ty+ey>=8)||(tx+ex>=8) )
;
else if(!game[ty+dy*2][tx+dx*2]&&game[ty+dy][tx+dx]*t<0){
ret++;
if(ret>1)
return ret;
}
}
}
return ret;
}
//see if the side is forced to do a jump
byte forced_jump(byte side){
byte y,x;
byte foo,ret;
foo=ret=0;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if(game[y][x]*side>0 && (foo=can_jump(y,x)) )
ret+=foo;
if(ret>1)
return ret;
}
}
return ret;
}
byte cmove(byte fy,byte fx,byte sy,byte sx){//really move/jump , 'move' is a curses function
byte a = game[fy][fx];
byte ret=0;
game[fy][fx]=0;
game[sy][sx]=a;
if(abs(fy-sy) == 2){
ret =game[(fy+sy)/2][(fx+sx)/2];
game[(fy+sy)/2][(fx+sx)/2]=0;
}
return ret;
}
//make the pawn a king
bool king(byte y,byte x){
byte t= (4-y)*game[y][x];
if( (y==7 || !y) && t<0 && t>-5 ){
game[y][x]*=2;
return 1;
}
return 0;
}
double advantage(byte side){
unsigned char own,opp;
own=opp=0;
byte foo;
byte y,x;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
foo=game[y][x]*side;
if(foo>0){
own++;//so it wont sacrfice two pawns for a king ( 2 kings == 3 pawns)
own+=foo;
}
else if(foo<0){
opp++;
opp-=foo;
}
}
}
if(!own)
return 0;
else if(!opp)
return WIN;
else
return (double)own/opp;
}
double posadvantage(byte side){
double adv=0;
double oppadv=0;
byte foo;
byte y,x;
byte goal= (side>0)*7 , oppgoal=(side<0)*7;
/*This encourages the AI to king its pawns and concentrate its kings in the center.
The idea is : With forces concentrated in the center, movements to all of the board would be in the game tree's horizon of sight(given enough depth);
and with forces being focused , its takes less movements to make an attack. */
for(y=0;y<8;y++){
for(x=0;x<8;x++){
foo=game[y][x]*side;
if(foo>0){
adv+=foo;
adv++;
if(foo==1)
adv+= 1/( abs(y-goal) );//adding positional value
else if(foo==2)
adv+= 1/( fabs(y-3.5)+ fabs(x-3.5) );
}
else if( foo<0 ){
oppadv-=foo;
oppadv++;
if(foo==-1)
adv+=1/( abs(y-oppgoal) );
else if(foo==-2)
adv+= 1/( fabs(y-3.5)+ fabs(x-3.5) );
}
}
}
if(!adv)
return 0;
else if( !oppadv )
return WIN;
else
return adv/oppadv;
return adv;
}
//the AI algorithm
double decide(byte side,byte depth,byte s){//s is the type of move, it doesn't stand for anything
byte fj=forced_jump(side);//only one legal jump if returns 1
byte nextturn;
byte mvy[4],mvx[4];
byte n;
bool didking;
byte captured;
double adv=0;
byte toy,tox;
byte y,x;
double wrstadv=WIN+1;
double bestadv=0;
byte besttoy,besttox;
byte besty,bestx;
bestx=besty=besttox=besttoy=-100;
bool canmove=0;
byte nexts ;
if(s == IMAGINARY || s == NORMAL )
nexts=IMAGINARY;
else
nexts=ALT_IMG;
for(y=0;y<8;y++){
for(x=0;x<8;x++){
if(fj && (s==NORMAL || s==ALT_NRM) && jumpagainy>=0 && (jumpagainy!=y || jumpagainx!=x) )
continue;
if(game[y][x]*side>0){
canmove=0;
memset(mvy,-1,4);
memset(mvx,-1,4);
if(fj)
canmove=jumps(y,x,mvy,mvx);
else
canmove=moves(y,x,mvy,mvx);
if(canmove){
for(n=0;n<4;n++){
if(mvy[n] != -1){//a real move
toy=mvy[n];
tox=mvx[n];
captured=cmove(y,x,toy,tox);//do the imaginary move
if(fj && can_jump(toy,tox) ) //its a double jump
nextturn=side;
else
nextturn=-side;
didking=king(toy,tox);
//see the advantage you get
if(fj==1 && (s==ALT_NRM || s==NORMAL) )
adv= DOESNT_MATTER;//you have to do the move anyway
else if(!depth){
if(s==IMAGINARY || s==NORMAL)//calculating advantage only based on numerical superiority
adv=advantage(side);
else
adv=posadvantage(side);//taking to account the position of the pieces
}
else{
if(nextturn==side)
adv=decide(nextturn,depth,nexts);
else{ //best move is the one that gives least advantage to the opponet
adv=decide(nextturn,depth-!fj,nexts);
if(adv==WIN)
adv=0;
else if(adv)
adv=1/adv;
else
adv=WIN;
}
}
//undo the imaginary move
if(didking)
game[toy][tox]/=2;
game[y][x]=game[toy][tox];
game[toy][tox]=0;
if(fj)
game[(toy+y)/2][(tox+x)/2]=captured;
if(besty<0 || adv>bestadv || (adv==bestadv && ( random()%2 )) ){
besty=y;
bestx=x;
besttoy=toy;
besttox=tox;
bestadv=adv;
}
if(adv<wrstadv)
wrstadv=adv;
if(fj == 1)
goto EndLoop;
}
}
}
}
}
}
EndLoop:
if( (s==NORMAL || s==ALT_NRM) && besty >= 0 ){
if(endgame && fj!=1 && s==NORMAL && bestadv==wrstadv ){//the algorithm is not given enough depth to determine which move is better
if(wrstadv == WIN){//the randomization in the algorithm may cause an illusion of an inevitable win in several moves
if(depth > 1)
decide(side,depth-1,NORMAL);
else
goto Move;
}
else
decide(side,depth,ALT_NRM);//change your opinion about what advantage means
}
else{
Move:
cmove(besty,bestx,besttoy,besttox);
kinged=king(besttoy,besttox);
if(!kinged && can_jump(besttoy,besttox) ){
jumpagainy = besttoy;//so the next player (itself) can only continue the chain of jumps from there
jumpagainx = besttox;
}
else
jumpagainy=jumpagainx=-1;
}
}
return bestadv;
}
//peacefully close when ^C is pressed
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(void){
MEVENT minput;
getmouse(&minput);
if( minput.y-4 <8 && minput.x-1<16){
py=minput.y-4;
px=(minput.x-1)/2;
}
else
return;
if(minput.bstate & (BUTTON1_CLICKED|BUTTON1_PRESSED|BUTTON1_RELEASED) )
ungetch('\n');
}
void help(void){
erase();
header();
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(9,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"RETURN/ENTER : Select or move the piece");
mvprintw(5,0,"SPACE : Flag/Unflag");
mvprintw(6,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(7,0,"q : quit");
mvprintw(8,0,"F1 & F2 : Help on controls & gameplay");
mvprintw(11,0,"Press a key to continue");
refresh();
getch();
erase();
}
void gameplay(void){
erase();
header();
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("1) The game starts with each player having 12 men;\n");
printw(" men can only diagonally move forwards \n");
printw(" (toward the opponet's side).\n\n");
printw("2) Men can become kings by reaching the opponet's \n");
printw(" first rank; kings can diagonally move both forwards\n");
printw(" and backwards.\n\n");
printw("3) Pieces can capture opponet's pieces by jumping over them\n");
printw(" also they can capture several pieces at once by doing a\n");
printw(" chain of jumps.\n\n");
printw("4) You have to do a jump if you can.\n\n");
printw("5) A player wins when the opponet can't do a move e. g. \n");
printw(" all of their pieces are captured.\n\n");
refresh();
getch();
erase();
}
int main(int argc,char** argv){
dpt=4;
if(argc>2){
printf("Usage: %s [AIpower]\n",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
if(sscanf(argv[1],"%d",&dpt) && dpt<128 && dpt>0)
;
else{
puts("That should be a number from 1 to 127.");
return EXIT_FAILURE;
}
}
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
noecho();
cbreak();
keypad(stdscr,1);
int input ;
printw("Dark plays first.\nChoose type of the dark player(H/c)\n" );
input=getch();
if(input=='c'){
computer[0]=dpt;
printw("Computer.\n");
}
else{
computer[0]=0;
printw("Human.\n");
}
printw("Choose type of the light player(h/C)\n");
input=getch();
if(input=='h'){
computer[1]=0;
printw("Human.\n");
}
else{
computer[1]=dpt;
printw("Computer.\n");
}
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_RED,-1);
}
signal(SIGINT,sigint_handler);
Start:
srandom(time(NULL)%UINT_MAX);
fill();
cy=cx=-1;
py=px=0;
byte mvy[4],mvx[4];
memset(mvy,-1,4);
memset(mvx,-1,4);
byte turn=1;
bool t=1;
bool fj;
byte result;
byte todraw=0;
double adv = 1;//used to determine when the game is a draw
double previousadv =1;
Turn:
jumpagainy=jumpagainx=-1;
kinged=0;
turn =-turn;
t=!t;//t == turn<0 that's turn in binary/array index format
fj = forced_jump(turn);
erase();
flushinp();
header();
draw(3,0);
if(t){
previousadv=adv;
adv= advantage(1) + (score[0]*score[1]);//just taking the dry scores to account too,nothing special
if(previousadv==adv)
todraw++;
else
todraw=0;
}
if(!score[0] || (turn==-1 && !fj && !can_move(-1))){
result=1;
goto End;
}
else if(!score[1] || (turn==1 && !fj && !can_move(1))){
result=-1;
goto End;
}
else if(todraw==50){ // 50 turns without any gains for each side
result=0;
goto End;
}
endgame= score[t]<=5 || score[!t]<=5;
draw(3,0);
refresh();
while(computer[t]){
mvprintw(13,0,"Thinking...");
refresh();
computer[t]=dpt+ (score[!t] != score[t]) + endgame;
decide(turn,computer[t],1);
if(!(fj && jumpagainy>=0 && !kinged )){
goto Turn;
}
}
while(1){
erase();
draw(3,0);
header();
refresh();
input=getch();
if( input == KEY_F(1) || input=='?' )
help();
if( input == KEY_F(2) )
gameplay();
if( input == KEY_MOUSE )
mouseinput();
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<7)
py++;
if( (input=='h' || input==KEY_LEFT) && px>0)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<7)
px++;
if( input=='q'){
result=2;
goto End;
}
if(input=='\n'){
if(game[py][px]*turn>0){
cy=py;
cx=px;
memset(mvy,-1,4);
memset(mvx,-1,4);
if(!fj)
moves(py,px,mvy,mvx);
jumps(py,px,mvy,mvx);
}
if( in(mvy,mvx,py,px) && !(jumpagainy>=0 && (cy !=jumpagainy || cx != jumpagainx) ) ){
memset(mvy,-1,4);
memset(mvx,-1,4);
cmove(cy,cx,py,px);
kinged=king(py,px);
cy=-1;
cx=-1;
if( !(fj && can_jump(py,px) && !kinged ) ){
goto Turn;
}
else{
jumpagainy=py;
jumpagainx=px;
}
}
}
}
End:
move(13,0);
switch(result){
case -1:
printw("The dark side has won the game.");
break;
case 0:
printw("Draw.");
break;
case 1:
printw("The light side has won the game.");
break;
case 2:
printw("You resigned.");
}
printw(" Wanna rematch?(y/n)");
curs_set(1);
input=getch();
if(result==2){
if (input=='Y' || input=='y')
goto Start;
}
else if(input!='n' && input!='N' && input!= 'q'){
/*byte b=computer[0]; //switch sides, i don't know if it's necessary
computer[0]=computer[1];
computer[1]=b;*/
goto Start;
}
endwin();
return EXIT_SUCCESS;
}

3
sources/config.h Normal file
View File

@ -0,0 +1,3 @@
#define PP_SCORES "PipesScores"
#define JW_SCORES "JewelsScores"
//for easier access

389
sources/jewels.c Normal file
View File

@ -0,0 +1,389 @@
#include <curses.h>
#include <time.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include "config.h"
#define LEN 17
#define WID 19
#define DELAY 2
#define SAVE_TO_NUM 10
/*
Jewels
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lnucrses
A pair of jewels appear on top of the window, And you can move and rotate them while they are falling down.
If you make a vertical or horizontal row of 4 jewels they will explode and add up to your score.
Like Tetris,You will lose the game when the center of the uppermost row is filled.
*/
typedef signed char byte;
chtype board[LEN][WID];
chtype colors[6]={0};
chtype next1,next2;
byte jx,jy; //first jewel's position
byte kx,ky;//second jewel's position in relation to that of j
long score=0;
char* controls = "j,l-Move k-Rotate p-Pause q-Quit";
FILE* scorefile;
byte scorewrite(long score){// only saves the top 10
bool deforno;
if( !getenv("JW_SCORES") && (scorefile= fopen(JW_SCORES,"r")) ){
deforno=1;
}
else{
deforno=0;
if( !(scorefile = fopen(getenv("JW_SCORES"),"r")) ){
fprintf(stderr,"\nNo accessible score files found. You can make an empty text file in %s/%s or set JW_SCORES to such a file to solve this. \n",getenv("HOME"),JW_SCORES);
exit(EXIT_SUCCESS);
}
}
char namebuff[SAVE_TO_NUM][60];
long scorebuff[SAVE_TO_NUM];
memset(namebuff,0,SAVE_TO_NUM*60*sizeof(char) );
memset(scorebuff,0,SAVE_TO_NUM*sizeof(long) );
long fuckingscore =0;
char fuckingname[60]={0};
byte location=0;
while( fscanf(scorefile,"%59s : %ld\n",fuckingname,&fuckingscore) == 2 && location<SAVE_TO_NUM ){
strcpy(namebuff[location],fuckingname);
scorebuff[location] = fuckingscore;
location++;
memset(fuckingname,0,60);
fuckingscore=0;
}
if(deforno)
scorefile = fopen(JW_SCORES,"w+");//get rid of the text
else
scorefile = fopen(getenv("JW_SCORES"), "w+") ;
if(!scorefile){
printf("\nThe file cannot be opened in w+.\n");
exit(EXIT_SUCCESS);
}
byte itreached=location;
byte ret = -1;
bool wroteit=0;
for(location=0;location<=itreached && location<SAVE_TO_NUM-wroteit;location++){
if(!wroteit && (location>=itreached || score>=scorebuff[location]) ){
fprintf(scorefile,"%s : %ld\n",getenv("USER"),score);
ret=location;
wroteit=1;
}
if(location<SAVE_TO_NUM-wroteit && location<itreached)
fprintf(scorefile,"%s : %ld\n",namebuff[location],scorebuff[location]);
}
fflush(scorefile);
return ret;
}
void showscores(byte playerrank){
if(playerrank == 0){
char formername[60]={0};
long formerscore=0;
rewind(scorefile);
fscanf(scorefile,"%*s : %*d\n");
if ( fscanf(scorefile,"%s : %ld\n",formername,&formerscore)==2){
printf("\n*****CONGRATULATIONS!****\n");
printf(" _____ You bet the\n");
printf(" .' | previous\n");
printf(" .' | record\n");
printf(" | .| | of\n");
printf(" |.' | |%14ld\n",formerscore);
printf(" | | held by\n");
printf(" ___| |___%11s\n",formername);
printf(" | |\n");
printf(" |____________|\n");
printf("*************************\n");
}
}
//scorefile is still open with w+
char pname[60] = {0};
long pscore=0;
byte rank=0;
rewind(scorefile);
printf("\n>*>*>Top %d<*<*<\n",SAVE_TO_NUM);
while( rank<SAVE_TO_NUM && fscanf(scorefile,"%s : %ld\n",pname,&pscore) == 2){
if(rank == playerrank)
printf(">>>");
printf("%d) %s : %ld\n",rank+1,pname,pscore);
rank++;
}
putchar('\n');
}
//apply gravity
bool fall(void){
bool jfall,kfall,ret;
jfall=kfall=ret=0;
for(int y=LEN-1;y>0;y--){
chtype c,d;
for(int x=WID-1;x>=0;x--){
c=board[y][x];
d=board[y-1][x];
if(!c && d){
board[y-1][x]=0;
board[y][x]=d;
if(y-1==jy && x==jx)
jfall=1;
if((y-1==jy+ky) && (x==jx+kx))
kfall=1;
ret=1;
}
}
}
if(jfall&&kfall)
jy++;
else
jy = LEN+1;
return ret;
}
// rotate 90d clockwise in ky/x format
void clockwise(byte* y,byte* x){
/*
o x
x xo o ox*/
chtype fx,fy;
if(*y)
fy=0;
fx=-*y;
if(*x)
fx=0;
fy=*x;
*y=fy;
*x=fx;
}
//rtt jwls
bool rotate(void){//f:future
if(jy>LEN)
return 0;
byte fy,fx;
fy=ky;fx=kx;
clockwise(&fy,&fx);
if( jy+fy<0 || jy+fy>=LEN || jx+fx<0 || jx+fx>=WID )
return 0;
if(board[jy+fy][jx+fx])
return 0;
chtype a = board[jy+ky][jx+kx];
board[jy+ky][jx+kx]=0;
ky=fy;
kx=fx;
board[jy+ky][jx+kx]=a;
return 1;
}
//mv jwls
bool jmove(byte dy,byte dx){
if(jy>LEN)
return 0;
if(jx+dx>=WID || jx+dx<0 || jx+kx+dx>=WID ||jx+kx+dx<0 || jy+dx<0 ||jx+dx+kx<0)
return 0;
if( board[jy+ky+dy][jx+kx+dx] )
if( !(jy+ky+dy == jy && jx+kx+dx==jx) )
return 0;
if( board[jy+dy][jx+dx])
if(!(dx==kx && dy==ky))
return 0;
//still alive?
chtype a = board[jy][jx];
chtype b = board[jy+ky][jx+kx];
board[jy][jx]=0;
board[jy+ky][jx+kx]=0;
board[jy+dy][jx+dx]=a;
board[jy+ky+dy][jx+kx+dx]=b;
jy+=dy;jx+=dx;
return 1;
}
//scoring algorithm
bool explode(byte combo){
bool ret =0;
chtype c,uc;
byte n;
byte y,x;
for(y=0;y<LEN;y++){
c=uc=n=0;
for(x=0;x<WID;x++){
uc = c;
c = board[y][x];
if(c && c == uc){
n++;
if(n>=3 && x==WID-1){//the chain ends because the row ends
x++;
goto HrExplsn;
}
}
else if(n>=3){
HrExplsn:
score+=n*10*(n-2)*combo;
ret=1;
for(;n>=0;n--)
board[y][x-1-n]=0;
n=0;
}
else
n=0;
}
}
for(x=0;x<WID;x++){
c=uc=n=0;
for(byte y=0;y<LEN;y++){
uc=c;
c = board[y][x];
if(c && c == uc){
n++;
if(n>=3 && y==LEN-1){
y++;
goto VrExplsn;
}
}
else if(n>=3){
VrExplsn:
score+=n*10*(n-2)*combo;
ret=1;
for(;n>=0;n--)
board[y-1-n][x]=0;
n=0;
}
else
n=0;
}
}
return ret;
}
//display
void draw(void){
erase();
int middle = (COLS/2-1)-(WID/2);
chtype a=A_STANDOUT|' ';
mvhline(LEN,middle-2,a,WID+4);
mvvline(0,middle-1,a,LEN);
mvvline(0,middle-2,a,LEN);
mvvline(0,middle+WID,a,LEN);
mvvline(0,middle+WID+1,a,LEN);
mvprintw(0,0,"Score:%d",score);
mvaddstr(1,0,"Next:");
addch(next1);
addch(next2);
for(byte y=0;y<LEN;y++){
for(byte x=0;x<WID;x++){
chtype c = board[y][x];
if(c)
mvaddch(y,middle+x,c);
}
}
mvaddstr(LINES-2,middle-5,controls);
refresh();
}
int main(void){
initscr();
cbreak();
halfdelay(DELAY);
noecho();
curs_set(0);
wnoutrefresh(stdscr);
keypad(stdscr,1);
int input;
bool falls;
byte stop=0 , combo;
char jwstr[] = {'*','^','~','"','$','V'};
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_RED,-1);
init_pair(2,COLOR_GREEN,-1);
init_pair(3,COLOR_MAGENTA,-1);
init_pair(4,COLOR_BLUE,-1);//array this thing
init_pair(5,COLOR_YELLOW,-1);
init_pair(6,COLOR_CYAN,-1);
for(byte n=0;n<6;n++){
colors[n] = COLOR_PAIR(n+1);
}
}
srandom(time(NULL)%UINT_MAX);
byte ran1= random()%6;
byte ran2= random()%6;
next1= colors[ran1]|jwstr[ran1];
next2= colors[ran2]|jwstr[ran2];
while(1){
chtype a,b;
a=board[0][WID/2];
b=board[0][WID/2-1];
if(a || b ){
goto Lose;
}
jy=ky=0;
jx=WID/2;
kx=-1;
board[jy][jx]=next2;
board[jy+ky][jx+kx]=next1;
ran1= random()%6;
ran2= random()%6;
next1=colors[ran1]|jwstr[ran1];
next2=colors[ran2]|jwstr[ran2];
falls = 1;
while(falls){
input = getch();
if(input != ERR)
stop+=1;
if( stop >= 10){
falls=fall();
stop=0;
}
else if(input=='l' || input==KEY_RIGHT)
jmove(0,+1);
else if(input=='j' || input==KEY_LEFT )
jmove(0,-1);
else if(input=='k' || input==KEY_UP)
rotate();
else if(input=='p'){
mvaddstr(LINES-2,COLS/2-15,"Paused - Press a key to continue ");
refresh();
nocbreak();
cbreak();
getch();
halfdelay(DELAY);
}
else if(input=='q')
goto Lose;
else if(input==' ')
while( (falls=fall()) )
stop=0;
else{
falls=fall();
stop=0;
}
draw();
}
combo=1;
while(explode(combo)){ // explode, fall, explode, fall until nothing is left
combo++;
while(fall());
draw();
}
}
Lose:
nocbreak();
endwin();
printf("%s _Jewels_ %s\n",jwstr,jwstr);
printf("You have scored %ld points.\n",score);
showscores(scorewrite(score));
return EXIT_SUCCESS;
}

361
sources/mines.c Normal file
View File

@ -0,0 +1,361 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
#define FLAG 9
#define UNCLEAR 10
/*
|\/|
| |INES
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
int len,wid,py,px,flags;
int untouched;
int mscount;
chtype colors[6]={0};
void rectangle(int sy,int sx){
for(int y=0;y<=len+1;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+wid*2,ACS_VLINE);
}
for(int x=0;x<=wid*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+len+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+len+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+wid*2,ACS_URCORNER);
mvaddch(sy+len+1,sx+wid*2,ACS_LRCORNER);
}
//display
void draw(int sy,int sx,byte board[len][wid]){
rectangle(sy,sx);
chtype attr ;
char prnt;
int y,x;
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
attr=A_NORMAL;
if(y==py && x==px)
attr |= A_STANDOUT;
if(board[y][x]<0)
prnt='.';
else if(!board[y][x])
prnt=' ';
else if(board[y][x] < 8){
attr |= colors[board[y][x]-1];
prnt='0'+board[y][x];
}
else if(board[y][x]==9){
attr |= colors[3];
prnt='P';
}
else if(board[y][x]>9)
prnt='?';
mvaddch(sy+1+y,sx+x*2+1,attr|prnt);
}
}
}
//show the mines
void drawmines(int sy,int sx,byte board[len][wid],bool mines[len][wid]){
int y,x;
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
if(mines[y][x]){
if(y==py&&x==px)
mvaddch(sy+y+1,sx+x*2+1,'X');
else if(board[y][x]==9)
mvaddch(sy+y+1,sx+x*2+1,'%');
else
mvaddch(sy+y+1,sx+x*2+1,'*');
}
}
}
}
//place mines
void mine(bool mines[len][wid]){
int y=random()%len;
int x=random()%wid;
for(int n=0;n<mscount;n++){
while(mines[y][x]){
y=random()%len;
x=random()%wid;
}
mines[y][x]=true;
}
}
bool click(byte board[len][wid],bool mines[len][wid],int ty,int tx){
if(board[ty][tx]>=0 && board[ty][tx] <9)//it has been click()ed before
return 0;
else{//untouched
if(board[ty][tx]==FLAG)
flags--;
board[ty][tx]=0;
untouched--;
}
int y,x;
for(y=ty-1;y<ty+2;y++){
if(y<0)
y=0;
if(y>=len)
break;
for (x=tx-1;x<tx+2;x++){
if(x<0)
x=0;
if(x>=wid)
break;
if(mines[y][x])
board[ty][tx]++;
}
}
if(!board[ty][tx]){//there are no mines in the adjacent tiles
for(y=ty-1;y<ty+2;y++){
if(y<0)
y=0;
if(y>=len)
break;
for(x=tx-1;x<tx+2;x++){
if(x<0)
x=0;
if(x>=wid)
break;
click(board,mines,y,x);
}
}
}
return 0;
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(int sy, int sx){
MEVENT minput;
getmouse(&minput);
if( minput.y-4-sy<len && minput.x-1-sx<wid*2){
py=minput.y-4-sy;
px=(minput.x-1-sx)/2;
}
else
return;
if(minput.bstate & BUTTON1_CLICKED)
ungetch('\n');
if(minput.bstate & (BUTTON2_CLICKED|BUTTON3_CLICKED) )
ungetch(' ');
}
void help(void){
erase();
mvprintw(1,0,"|\\/|");
mvprintw(2,0,"| |INES");
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(10,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"RETURN/ENTER : Examine for bombs");
mvprintw(5,0,"SPACE : Flag/Unflag");
mvprintw(6,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(7,0,"q : Quit");
mvprintw(8,0,"F1 & F2 : Help on controls & gameplay");
mvprintw(9,0,"PgDn,PgUp,<,> : Scroll");
mvprintw(12,0,"Press a key to continue");
refresh();
getch();
erase();
}
void gameplay(void){
erase();
mvprintw(1,0,"|\\/|");
mvprintw(2,0,"| |INES");
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
mvprintw(4,0,"Try to find the landmines in the field\n");
printw("with logical reasoning: When you click\n");
printw("on a tile ( a '.' here), numbers may show\n");
printw("up that indicate the number of landmines\n");
printw("in adjacent tiles; you should find and \n");
printw("avoid the landmines based on them; and\n");
printw("clicking on a landmine would make you\n");
printw("lose the game.");
refresh();
getch();
erase();
}
int main(int argc, char** argv){
signal(SIGINT,sigint_handler);
if(argc>4 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [len wid [minescount]]\n",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
puts("Give both dimensions.");
return EXIT_FAILURE;
}
if(argc>=3){
bool lool = sscanf(argv[1],"%d",&len) && sscanf(argv[2],"%d",&wid);
if(!lool){
puts("Invalid input.");
return EXIT_FAILURE;
}
if(len<5 || wid<5 || len>1000 || wid>1000){
puts("At least one of your given dimensions is either too small or too big.");
return EXIT_FAILURE;
}
}
else
len=wid=8;
if(argc==4){
if( !sscanf(argv[3],"%d",&mscount)){
puts("Invalid input.");
return EXIT_FAILURE;
}
if( mscount<5 || mscount>= len*wid){
puts("Too few/many mines.");
return EXIT_FAILURE;
}
}
else
mscount = len*wid/6;
srandom(time(NULL)%UINT_MAX);
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
noecho();
cbreak();
keypad(stdscr,1);
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_BLUE,-1);
init_pair(2,COLOR_GREEN,-1);
init_pair(3,COLOR_YELLOW,-1);
init_pair(4,COLOR_RED,-1);
init_pair(5,COLOR_RED,COLOR_YELLOW);
init_pair(6,COLOR_RED,COLOR_MAGENTA);
for(byte b= 0;b<6;b++){
colors[b]=COLOR_PAIR(b+1);
}
}
byte board[len][wid];
bool mines[len][wid];
char result[70];
int input;
int sy,sx;
Start:
sy=sx=0;
py=px=0;
untouched=len*wid;
flags=0;
curs_set(0);
memset(board,-1,len*wid);
memset(mines,false,len*wid);
mine(mines);
while(1){
erase();
mvprintw(sy+1,sx+0,"|\\/| Flags:%d\n",flags);
mvprintw(sy+2,sx+0,"| |INES Mines:%d\n",mscount);
draw(sy+3,sx+0,board);
refresh();
if(untouched<=mscount){
strcpy(result,"YAY!!");
break;
}
input = getch();
if( input==KEY_PPAGE && LINES< len+3){//the board starts in 3
sy+=10;
if(sy>0)
sy=0;
}
if( input==KEY_NPAGE && LINES< len+3){
sy-=10;
if(sy< -(len+3) )
sy=-(len+3);
}
if( input=='<' && COLS< wid*2+1){
sx+=10;
if(sx>0)
sx=0;
}
if( input=='>' && COLS< wid*2+1){
sx-=10;
if(sx< -(wid*2+1))
sx=-(wid*2+1);
}
if( input==KEY_F(1) || input=='?' )
help();
if( input==KEY_F(2) )
gameplay();
if( input==KEY_MOUSE )
mouseinput(sy,sx);
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<len-1)
py++;
if( (input=='h' || input==KEY_LEFT) && px>0)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<wid-1)
px++;
if( input=='q')
sigint_handler(0);
if(input=='x' && getch()=='y' && getch()=='z' && getch()=='z' && getch()=='y' ){
strcpy(result,"It is now pitch dark. If you proceed you will likely fall into a pit.");
break;
}
if(input=='\n' && board[py][px] < 9){
if(mines[py][px]){
switch( random()%3){
case 0:
strcpy(result,"You lost The Game.");
break;
case 1:
strcpy(result,"You exploded!");
break;
case 2:
strcpy(result,"Bring your MRAP with you next time!");
}
break;
}
click(board,mines,py,px);
}
if(input==' '){
if(board[py][px] == -1){
board[py][px]=FLAG;
flags++;
}
else if(board[py][px] == FLAG){
board[py][px]=UNCLEAR;
flags--;
}
else if(board[py][px] == UNCLEAR)
board[py][px]=-1;
}
}
drawmines(sy+3,sx+0,board,mines);
mvprintw(sy+len+5,sx+0,"%s Wanna play again?(y/n)",result);
curs_set(1);
input=getch();
if(input != 'N' && input != 'n' && input != 'q')
goto Start;
endwin();
return EXIT_SUCCESS;
}

534
sources/pipes.c Normal file
View File

@ -0,0 +1,534 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
#include "config.h"
#define UP 1
#define RIGHT 2
#define DOWN 4
#define LEFT 8
#define CROSSOVER 15
#define FILLED 16
#define SPILL 13
#define FLOWDELAY 5
#define DELAY 3
#define SAVE_TO_NUM 10
#define SY 0
#define SX 7
/*
_
|_)
| IPES
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
typedef unsigned char bitbox;
int len,wid,py,px,fy,fx;//p: pointer f: fluid
bitbox tocome[5]={0};//the row of pipes in the left side
chtype green=A_BOLD;//will use bold font instead of green if colors are not available
long score;
FILE* scorefile;
char error [150]={0};
void logo(void){
mvprintw(0,0," _ ");
mvprintw(1,0,"|_)");
mvprintw(2,0,"| IPES");
}
byte scorewrite(void){// only saves the top 10, returns the place in the chart
bool deforno;
if( !getenv("PP_SCORES") && (scorefile= fopen(PP_SCORES,"r")) ){
deforno=1;
}
else{
deforno=0;
if( !(scorefile = fopen(getenv("PP_SCORES"),"r")) ){
sprintf(error,"No accessible score files found. You can make an empty text file in %s/%s or set PP_SCORES to such a file to solve this.",getenv("HOME"),PP_SCORES);
return -1;
}
}
char namebuff[SAVE_TO_NUM][60];
long scorebuff[SAVE_TO_NUM];
memset(namebuff,0,SAVE_TO_NUM*60*sizeof(char) );
memset(scorebuff,0,SAVE_TO_NUM*sizeof(long) );
long fuckingscore =0;
char fuckingname[60]={0};
byte location=0;
while( fscanf(scorefile,"%59s : %ld\n",fuckingname,&fuckingscore) == 2 && location<SAVE_TO_NUM ){
strcpy(namebuff[location],fuckingname);
scorebuff[location] = fuckingscore;
location++;
memset(fuckingname,0,60);
fuckingscore=0;
}
if(deforno)
scorefile = fopen(PP_SCORES,"w+");//get rid of the previous text first
else
scorefile = fopen(getenv("PP_SCORES"), "w+") ;
if(!scorefile){
strcpy(error, "The file cannot be opened in w+. ");
return -1;
}
byte itreached=location;
byte ret = -1;
bool wroteit=0;
for(location=0;location<=itreached && location<SAVE_TO_NUM-wroteit;location++){
if(!wroteit && (location>=itreached || score>=scorebuff[location]) ){
fprintf(scorefile,"%s : %ld\n",getenv("USER"),score);
ret=location;
wroteit=1;
}
if(location<SAVE_TO_NUM-wroteit && location<itreached)
fprintf(scorefile,"%s : %ld\n",namebuff[location],scorebuff[location]);
}
fflush(scorefile);
return ret;
}
void showscores(byte playerrank){
erase();
logo();
if(*error){
mvaddstr(SY,SX,error);
mvprintw(SY+1,SX,"However, your score is %ld.",score);
refresh();
return;
}
if(playerrank == 0){
char formername[60]={0};
long formerscore=0;
rewind(scorefile);
fscanf(scorefile,"%*s : %*d");
if ( fscanf(scorefile,"%s : %ld",formername,&formerscore)==2 && formerscore>0){
byte a = (len-9)/2;
attron(A_BOLD);
mvprintw(SY,SX, "**** ***");
mvprintw(SY+len+1,SX,"***********************");
attroff(A_BOLD);
attron(green);
mvprintw(SY,SX+4,"CONGRATULATIONS!");
attroff(green);
mvprintw(SY+a+1,SX," _____ You bet the");
mvprintw(SY+a+2,SX," .' | previous");
mvprintw(SY+a+3,SX," .' | record");
mvprintw(SY+a+4,SX," | .| | of");
mvprintw(SY+a+5,SX," |.' | |%11ld",formerscore);
mvprintw(SY+a+6,SX," | | held by");
mvprintw(SY+a+7,SX," ___| |___%7s!",formername);
mvprintw(SY+a+8,SX," | |");
mvprintw(SY+a+9,SX," |____________|");
mvprintw(len+2,0,"Game over! Press a key to proceed:");
refresh();
getch();
erase();
logo();
}
}
attron(A_BOLD);
mvprintw(3,0," HIGH");
mvprintw(4,0,"SCORES");
attroff(A_BOLD);
//scorefile is still open with w+
char pname[60] = {0};
long pscore=0;
byte rank=0;
rewind(scorefile);
while( rank<SAVE_TO_NUM && fscanf(scorefile,"%s : %ld\n",pname,&pscore) == 2){
move(SY+1+rank,SX+1);
attron(green);
if(rank == playerrank)
printw(">>>");
printw("%d",rank+1);
attroff(green);
printw(") %s : %ld",pname,pscore);
rank++;
}
refresh();
}
//move in direction
void MID(bitbox direction){
switch(direction){
case UP:
fy--;
break;
case DOWN:
fy++;
break;
case LEFT:
fx--;
break;
case RIGHT:
fx++;
break;
}
}
bitbox opposite(bitbox direction){
switch(direction){
case UP:
return DOWN;
case DOWN:
return UP;
case LEFT:
return RIGHT;
case RIGHT:
return LEFT;
}
return 0;
}
void rectangle(void){
for(int y=0;y<=len;y++){
mvaddch(SY+y,SX,ACS_VLINE);
mvaddch(SY+y,SX+wid+1,ACS_VLINE);
}
for(int x=0;x<=wid;x++){
mvaddch(SY,SX+x,ACS_HLINE);
mvaddch(SY+len+1,SX+x,ACS_HLINE);
}
mvaddch(SY,SX,ACS_ULCORNER);
mvaddch(SY+len+1,SX,ACS_LLCORNER);
mvaddch(SY,SX+wid+1,ACS_URCORNER);
mvaddch(SY+len+1,SX+wid+1,ACS_LRCORNER);
}
//this generates the pipes...
bitbox pipegen(void){
if(random()%17){//17 so all forms have the same chance
byte a=random()%4;
byte b;
do{
b=random()%4;
}while(b==a);
return (1 << a) | ( 1 << b);
}
else
return CROSSOVER;//sum of all directions, the crossover
}
//.. and this is only for display
void addpipe(int y,int x,bitbox pipe , bool highlight){
bitbox p= pipe & ~FILLED;
chtype foo ;
switch(p){
case UP|RIGHT :
foo= ACS_LLCORNER;
break;
case UP|DOWN :
foo=ACS_VLINE;
break;
case UP|LEFT :
foo=ACS_LRCORNER;
break;
case DOWN|RIGHT :
foo =ACS_ULCORNER;
break;
case DOWN|LEFT :
foo=ACS_URCORNER;
break;
case LEFT|RIGHT:
foo=ACS_HLINE;
break;
case RIGHT:
foo = '>';
break;
case LEFT:
foo = '<';
break;
case UP:
foo = '^';
break;
case DOWN:
foo = 'v';
break;
case CROSSOVER: //all
foo = ACS_PLUS;
break;
default:
foo = ' ';
break;
}
if( pipe & FILLED )
foo |= green;
mvaddch(y,x, foo|(highlight*A_REVERSE) );
}
//display
void draw(bitbox board[len][wid]){
int y,x;
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
addpipe(SY+1+y,SX+x+1,board[y][x], (y==py&&x==px) );//its highlighted when y==py and x==px
}
}
rectangle();
}
void mouseinput(void){
MEVENT minput;
getmouse(&minput);
if( minput.y-4 <len && minput.x-1<wid*2){
py=minput.y-(1+SY);
px=minput.x-(1+SX);
}
else
return;
if(minput.bstate & BUTTON1_CLICKED)
ungetch('\n');
}
//peacefully close when ^C is pressed
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void help(void){
erase();
logo();
attron(A_BOLD);
mvprintw(SY,SX+5,"-* *-");
mvprintw(3,0," HELP");
mvprintw(4,0," PAGE");
mvprintw(SY+7,SX,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
attron(green);
mvprintw(SY,SX+7,"THE CONTROLS");
attroff(green);
mvprintw(SY+1,SX,"RETURN/ENTER : Place/Replace a pipe");
mvprintw(SY+2,SX,"hjkl/ARROW KEYS : Move cursor");
mvprintw(SY+3,SX,"p : Pause");
mvprintw(SY+4,SX,"q : Quit");
mvprintw(SY+5,SX,"f : Toggle fast flow");
mvprintw(SY+6,SX,"g : Go! (End the countdown.)");
mvprintw(SY+6,SX,"F1 & F2 : Help on controls & gameplay");
mvprintw(SY+9,SX,"Press a key to continue");
refresh();
while(getch()==ERR);
erase();
}
void gameplay(void){
erase();
logo();
attron(A_BOLD);
mvprintw(SY,SX+5,"-* *-");
mvprintw(3,0," HELP");
mvprintw(4,0," PAGE");
attroff(A_BOLD);
attron(green);
mvprintw(SY,SX+7,"THE GAMEPLAY");
attroff(green);
mvprintw(SY+1,SX,"Keep maintaining the pipeline and");
mvprintw(SY+2,SX,"don't let the sewage leak.");
refresh();
while(getch()==ERR);
erase();
}
int main(int argc, char** argv){
signal(SIGINT,sigint_handler);
if(argc>3 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [len wid]\n",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
puts("Give both dimensions.");
return EXIT_FAILURE;
}
if(argc==3){
bool lool = sscanf(argv[1],"%d",&len) && sscanf(argv[2],"%d",&wid);
if(!lool){
puts("Invalid input.");
return EXIT_FAILURE;
}
if(len<5 || wid<5 || len>1000 || wid>1000){
puts("At least one of your given dimensions is too small or too big.");
return EXIT_FAILURE;
}
}
else{
wid=20;
len=14;
}
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
time_t tstart , now, lasttime, giventime=len*wid/4;
srandom(time(NULL)%UINT_MAX);
bitbox direction,board[len][wid];
int input;
byte foo;
bool flow,fast;
Start: //TODO in all the games, some things have to be moved behind the start . definize sy and sx
flow=0;
fast=0;
score=0;
memset(error,0,150);
memset(board,0,len*wid);
fy=1+(random()%(len-2) );
fx=1+(random()%(wid-2) );
board[fy][fx]= 1 << (random()%4);
direction= board[fy][fx];
board[fy][fx]|=FILLED;
for(foo=0;foo<5;foo++)
tocome[foo]=pipegen();
tstart = time(NULL);
lasttime=0;
initscr();
curs_set(0);
noecho();
cbreak();
halfdelay(DELAY);
keypad(stdscr,1);
if(has_colors()){
start_color();
use_default_colors();
init_pair(2,COLOR_GREEN,-1);
green=COLOR_PAIR(2);
}
py=px=0;
while(1){
now=time(NULL);
erase();
logo();
if(fast){
attron(A_BOLD);
mvprintw(3,0," FAST");
attroff(A_BOLD);
}
if(!flow && giventime >= now-tstart){
mvprintw(4,0,"Time:%ld",giventime-(now-tstart));
mvprintw(5,0,"Score:");
mvprintw(6,0,"%ld",score);
}
else{
mvprintw(4,0,"Score:");
mvprintw(5,0,"%ld",score);
}
for(foo=0;foo<5;foo++)
addpipe(11-foo,4,tocome[foo],0);
draw(board);
refresh();
if(now-tstart == giventime){
flow=1;
}
if(flow && (fast || ( !(now%FLOWDELAY)&& now!=lasttime ) )){
lasttime = now;
MID(direction);
if(fy<len && fx<wid && fy>=0&& fx>=0 && ( board[fy][fx]&opposite(direction) ) ){
if(board[fy][fx] != CROSSOVER && board[fy][fx] != (CROSSOVER|FILLED) )
direction = board[fy][fx] & ~opposite(direction);
score++;
if(fast)
score++;
}
else
goto End;
board[fy][fx]|=FILLED;
}
input = getch();
if( input == KEY_F(1) || input=='?' ){
help();
if(!flow)
tstart += time(NULL)-now;
}
if( input == KEY_F(2) ){
gameplay();
if(!flow)
tstart += time(NULL)-now;
}
if( input == KEY_MOUSE )
mouseinput();
if( (input=='k' || input==KEY_UP) && py>0 )
py--;
if( (input=='j' || input==KEY_DOWN) && py<len-1 )
py++;
if( (input=='h' || input==KEY_LEFT) && px>0 )
px--;
if( (input=='l' || input==KEY_RIGHT) && px<wid-1 )
px++;
if( input == '\n' && !(board[py][px] & FILLED) ){
if(board[py][px])
score-=3;
board[py][px]=tocome[0];
for(foo=0;foo<4;foo++)
tocome[foo]=tocome[foo+1];
tocome[4]= pipegen();
}
if( input=='f' ){
if(fast){
halfdelay(DELAY);
fast=0;
}
else{
halfdelay(1);
fast=1;
}
}
if( input=='p'){
erase();
logo();
attron(A_BOLD);
mvprintw(3,0,"PAUSED");
attroff(A_BOLD);
refresh();
while(getch()==ERR);
if(!flow)//pausing should not affect the countdown
tstart += time(NULL)-now;//now is not right now
continue;
}
if(!flow && input == 'g' )
flow=1;
if( score < -1000)
goto End;
if( input=='q'){
nocbreak();
cbreak();
curs_set(1);
mvprintw(len+2,0,"Do you want to see the high scores?(y/n)");
input=getch();
if(input == 'N' || input=='n' || input =='q')
sigint_handler(EXIT_SUCCESS);
showscores(scorewrite());
mvprintw(len+2,0,"Press a key to exit:");
refresh();
getch();
sigint_handler(EXIT_SUCCESS);
}
}
End:
nocbreak();
cbreak();
curs_set(1);
attron(A_BOLD|green);
mvprintw(3,0," OOPS!");
attroff(A_BOLD|green);
draw(board);
mvprintw(len+2,0,"Game over! Press a key to see the high scores:");
getch();
showscores(scorewrite());
mvprintw(len+2,0,"Game over!");
printw(" Wanna play again?(y/n)");
input=getch();
if( input!= 'N' && input!= 'n' && input!='q')
goto Start;
endwin();
return EXIT_SUCCESS;
}

318
sources/rabbithole.c Normal file
View File

@ -0,0 +1,318 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
#define UP 1
#define RIGHT 2
#define DOWN 4
#define LEFT 8
#define VISITED 16
#define CARROT 32
/*
_
|_)
| \ABBITHOLE
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
typedef unsigned char bitbox;
int len,wid,py,px;
chtype colors[6]={0};
typedef struct point{
int y;
int x;
} point;
point MID(int y,int x,bitbox direction){//move in direction
point pt = {y,x};
switch(direction){
case UP:
pt.y--;
return pt;
case DOWN:
pt.y++;
return pt;
case LEFT:
pt.x--;
return pt;
case RIGHT:
pt.x++;
return pt;
}
return pt;
}
void rectangle(int sy,int sx){
for(int y=0;y<=len*2;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+wid*2,ACS_VLINE);
}
for(int x=0;x<=wid*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+len*2,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+len*2,sx,ACS_LLCORNER);
mvaddch(sy,sx+wid*2,ACS_URCORNER);
mvaddch(sy+len*2,sx+wid*2,ACS_LRCORNER);
}
void draw(int sy,int sx,bitbox board[len][wid]){
int y,x;
bitbox d;
chtype prnt;
point pt;
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
prnt=0;
if( board[y][x] & CARROT )
prnt='%'|A_BOLD|colors[3];
else if(y==py && x==px)
prnt= 'r'|A_REVERSE;
if( board[y][x] & VISITED ){
if(y!=py || x!=px)
prnt='.'|A_REVERSE;
for(d=1;d<32;d=d << 1){
if(board[y][x] & d){
pt=MID(sy+1+y*2,sx+x*2+1,d);
mvaddch(pt.y,pt.x,' '|A_REVERSE);
}
}
}
if(prnt)
mvaddch(sy+1+y*2,sx+x*2+1,prnt);
}
}
rectangle(sy,sx);
}
void make_maze(bitbox board[len][wid],point f){
byte ds_tried=0;
byte dnumber=random()%4;
bitbox direction= 1 << (dnumber);
while( direction == board[f.y][f.x] )
direction= 1 << (dnumber=random()%4);
point pt = MID(f.y,f.x,direction);
while(ds_tried<4){
if(pt.y<0 || pt.y==len || pt.x<0 || pt.x==wid || board[pt.y][pt.x])
;
else{ //if the tile exists and is empty
board[f.y][f.x] |= direction;
board[pt.y][pt.x]= 1 << ( (dnumber+2)%4 );//direction's reverse
make_maze(board,pt);//recursion
}
direction= 1 << (dnumber= (dnumber+1)%4 );
pt= MID(f.y,f.x,direction);
ds_tried++;
}
}
void carrotify(bitbox board[len][wid],int count){
int y,x,c=count;
while(c){
y=random()%len;
x=random()%wid;
while( board[y][x] & CARROT ){
y=random()%len;
x=random()%wid;
}
board[y][x] |= CARROT;
c--;
}
}
void help(void){
erase();
mvprintw(0,0," _ ");
mvprintw(1,0,"|_)");
mvprintw(2,0,"| \\ABBITHOLE");
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(8,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(5,0,"q : Quit");
mvprintw(6,0,"F1 & F2: Help on controls & gameplay (viewing these pages doesn't pause the timer!)");
mvprintw(7,0,"PgDn,PgUp,<,> : Scroll");
mvprintw(10,0,"Press a key to continue");
refresh();
while ( getch()==ERR );
erase();
}
void gameplay(void){
erase();
mvprintw(0,0," _ ");
mvprintw(1,0,"|_)");
mvprintw(2,0,"| \\ABBITHOLE");
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("Try to gather all the carrots in the maze\n");
printw("in the given time. The determining factors\n");
printw("are your choice of paths and the speed of\n ");
printw("your fingers.\n");
refresh();
while ( getch()==ERR );
erase();
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
int main(int argc, char** argv){
bool autoset=0;
signal(SIGINT,sigint_handler);
if(argc>3 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [len wid]\n",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
puts("Give both dimensions.");
return EXIT_FAILURE;
}
if(argc==3){
bool lool = sscanf(argv[1],"%d",&len) && sscanf(argv[2],"%d",&wid);
if(!lool){
puts("Invalid input.");
return EXIT_FAILURE;
}
if(len<5 || wid<5 || len>800 || wid>800){
puts("At least one of your given dimensions is either too small or too big.");
return EXIT_FAILURE;
}
}
else{
autoset=1;
}
initscr();
if(autoset){
if((LINES-7)/2 < 10)
len=10;
else
len=(LINES-7)/2;
if((COLS-5)/2 < 20)
wid=20;
else
wid=(COLS-5)/2;
}
int carrot_count= (len*wid)/50;
int carrots_found;
time_t tstart , now, giventime=len*wid/5;
srandom(time(NULL)%UINT_MAX);
point start={0,0};
bitbox board[len][wid];
int sy,sx;
Start:
tstart = time(NULL);
carrots_found=0;
initscr();
curs_set(0);
noecho();
cbreak();
halfdelay(3);
keypad(stdscr,1);
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_BLUE,-1);
init_pair(2,COLOR_GREEN,-1);
init_pair(3,COLOR_YELLOW,-1);
init_pair(4,COLOR_RED,-1);
init_pair(5,COLOR_RED,COLOR_YELLOW);
init_pair(6,COLOR_RED,COLOR_MAGENTA);
for(byte b= 0;b<6;b++){
colors[b]=COLOR_PAIR(b+1);
}
}
sy=sx=0;
py=px=0;
memset(board,0,len*wid);
make_maze(board,start);
carrotify(board,carrot_count);
int input;
while(1){
board[py][px] |= VISITED;
if( board[py][px] & CARROT ){
carrots_found++;
board[py][px] &= ~CARROT;
}
now=time(NULL);
erase();
mvprintw(sy+0,sx+0," _ ");
mvprintw(sy+1,sx+0,"|_) Time left :%ld",giventime-(now-tstart));
mvprintw(sy+2,sx+0,"| \\ABBITHOLE Carrots left :%d",carrot_count-carrots_found);
draw(sy+3,sx+0,board);
refresh();
if(carrots_found==carrot_count || now-tstart == giventime){
flushinp();
break;
}
input = getch();
if( input==KEY_PPAGE && LINES< len+3){//the board starts in 3
sy+=10;
if(sy>0)
sy=0;
}
if( input==KEY_NPAGE && LINES< len+3){
sy-=10;
if(sy< -(len+3) )
sy=-(len+3);
}
if( input=='<' && COLS< wid*2+1){
sx+=10;
if(sx>0)
sx=0;
}
if( input=='>' && COLS< wid*2+1){
sx-=10;
if(sx< -(wid*2+1))
sx=-(wid*2+1);
}
if( input == KEY_F(1) || input=='?' )
help();
if( (input=='k' || input==KEY_UP) && py>0 && (board[py][px]&UP) )
py--;
if( (input=='j' || input==KEY_DOWN) && py<len-1 && (board[py][px]&DOWN) )
py++;
if( (input=='h' || input==KEY_LEFT) && px>0 && (board[py][px]&LEFT) )
px--;
if( (input=='l' || input==KEY_RIGHT) && px<wid-1 && (board[py][px]&RIGHT) )
px++;
if( input=='q')
sigint_handler(0);
if( board[py][px] & CARROT ){
carrots_found++;
board[py][px] &= ~CARROT;
}
}
End:
nocbreak();
cbreak();
draw(3,0,board);
refresh();
if(carrots_found==carrot_count)
mvprintw(len*2+4,0,"YAY!!");
else
mvprintw(len*2+4,0,"You gathered %2.1f%% of the carrots in %d seconds.",(float) carrots_found*100/carrot_count,giventime);
printw(" Wanna play again?(y/n)");
curs_set(1);
input=getch();
if(input == 'Y' || input == 'y')
goto Start;
else if( input!= 'N' && input!= 'n' && input!='q')
goto End;
endwin();
return EXIT_SUCCESS;
}

399
sources/reversi.c Normal file
View File

@ -0,0 +1,399 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
/*
_
|_)
| \EVERSI
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
byte py,px;//cursor
const char piece[2] = "OX";
char game[8][8];//main board
byte computer[2] = {0,0};
byte score[2];//set by header()
void rectangle(byte sy,byte sx){
for(byte y=0;y<=8+1;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+8*2,ACS_VLINE);
}
for(byte x=0;x<=8*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+8+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+8+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+8*2,ACS_URCORNER);
mvaddch(sy+8+1,sx+8*2,ACS_LRCORNER);
}
void header(void){//abuse, used to count the pieces on each side too
score[0]=score[1]=0;
for(byte y=0;y<8;y++){
for(byte x=0;x<8;x++){
if(game[y][x]){
if(game[y][x]==piece[0])
score[0]++;
else
score[1]++;
}
}
}
mvaddch(0,1, '_');
mvprintw(1,0,"|_) %2d:%2d",score[0],score[1]);
mvprintw(2,0,"| \\EVERSI ");
}
void draw(byte sy,byte sx){//the game's board
rectangle(sy,sx);
chtype attr ;
for(byte y=0;y<8;y++){
for(byte x=0;x<8;x++){
attr=A_NORMAL;
if(y==py && x==px)
attr |= A_STANDOUT;
if(game[y][x])
mvaddch(sy+1+y,sx+x*2+1,attr|game[y][x]);
else
mvaddch(sy+1+y,sx+x*2+1,attr|'.');
}
}
}
bool can_reverse(byte ty , byte tx,char board[8][8],char piece){//can place a piece there?
byte y,x,count;
if(board[ty][tx])
return false;
for(byte dy=-1;dy<2;dy++){ //changes the direction
for(byte dx=-1;dx<2;dx++){
if(dx==0&&dy==0)//it would be itself
dx=1;
count=0;
y=ty+dy;
x=tx+dx;
while(1){
if(y<0 || y>=8 ||x<0 || x>=8){//reaches edges of the board
count=0;
break;
}
if(!board[y][x]){//gap
count=0;
break;
}
if(board[y][x]!=piece){
count++;
y+=dy;
x+=dx;
}
else
break;//same color
}
if(count)
return true;
}
}
return false;
}
void reverse(byte ty,byte tx,char board[8][8],char piece){//place a piece there
board[ty][tx]=piece;
byte y,x;
for(byte dy=-1;dy<2;dy++){//changes the direction
for(byte dx=-1;dx<2;dx++){
if(dy==0 && dx==0)
dx=1;
y=ty+dy;
x=tx+dx;
while(1){
if(y<0 || y>=8 || x<0 || x>=8)
break;
if(!board[y][x])
break;
if(board[y][x]!=piece){
y+=dy;
x+=dx;
}
else{ //of same kind
while(y!=ty || x!=tx){ //reverse the disks
board[y][x]=piece;
y-=dy;
x-=dx;
}
break;
}
}
}
}
}
bool can_move(char board[8][8],char piece){//can move at all?
for(byte y=0;y<8;y++)
for(byte x=0;x<8;x++)
if(can_reverse(y,x,board,piece))
return true;
return false;
}
double advantage(char board[8][8],char piece){
double own=0;
double opp=0;
for(byte y=0;y<8;y++){
for(byte x=0;x<8;x++){
if(board[y][x]){
if(board[y][x]==piece){
own++;
if( ((y==7 || y==0)&&(x!=7 && x!=0)) || ((x==7 || x==0)&&(y!=7 && y!=0)) )//edges
own+=100;
if( (y==7 || y==0)&&(x==7 || x==0) )//corners
own+=10000;
}
else{
opp++;
if( ((y==7 || y==0)&&(x!=7 && x!=0)) || ((x==7 || x==0)&&(y!=7 && y!=0)) )
opp+=100;
if( (y==7 || y==0)&&(x==7 || x==0) )
opp+=10000;
}
}
}
}
return own/opp;
}
void cp(char A[8][8],char B[8][8]){//copy the board A to B
for(byte y=0;y<8;y++)
for(byte x=0;x<8;x++)
B[y][x]=A[y][x];
}
double decide(char board[8][8],char piece,char opponet,byte depth){//AI algorithm
if(!can_move(board,piece))
return 0;
char plan[8][8];
double adv,bestadv;
adv=bestadv=0;
byte besty,bestx;
for(byte y=0;y<8;y++){
for(byte x=0;x<8;x++){
if(can_reverse(y,x,board,piece) ){
cp(board,plan);//backtrack
reverse(y,x,plan,piece);
if(depth){
adv= decide(plan,opponet,piece,depth-1);//least benefit for the opponet
if(adv) //the opponet can make a move
adv = 1/adv;
else
adv=advantage(plan,piece);
}
else
adv=advantage(plan,piece);
if(adv>bestadv){
bestadv=adv;
besty=y;
bestx=x;
}
}
}
}
reverse(besty,bestx,board,piece);//do the move
return bestadv;
}
//peacefully close when ^C is pressed
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(void){
MEVENT minput;
getmouse(&minput);
if( minput.y-4 <8 && minput.x-1<16){
py=minput.y-4;
px=(minput.x-1)/2;
}
else
return;
if(minput.bstate & BUTTON1_CLICKED)
ungetch('\n');
}
void help(void){
erase();
header();
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(8,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"RETURN/ENTER : Put the piece");
mvprintw(5,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(6,0,"q : Quit");
mvprintw(7,0,"F1 & F2 : Help on controls & gameplay");
mvprintw(10,0,"Press a key to continue");
curs_set(1);
getch();
}
void gameplay(void){
erase();
header();
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("Players take turns placing disks on the board:\n\n");
printw("1) Any pieces of the opponet's color that is bounded\n");
printw(" in a straight line between the piece just placed and\n");
printw(" another piece of the current player's color would turn\n");
printw(" to the current player's color.\n\n");
printw("2) You can only put pieces if at least one of your \n");
printw(" opponet's pieces turns into your color.\n\n");
printw("3) The game ends when neither side can do a move and\n");
printw(" the player with more pieces wins.\n");
getch();
}
int main(int argc , char** argv){
int depth=2;
if(argc>2){
printf("Usage:%s [AIpower]",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
if(sscanf(argv[1],"%d",&depth) && depth<128 && 0<depth)
;//already done in sscanf
else{
printf("That should be a number from 1 to 127.\n");
return EXIT_FAILURE;
}
}
signal(SIGINT,sigint_handler);
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
noecho();
cbreak();
keypad(stdscr,1);
int input;
printw("Black plays first:\n");
printw("Choose type of the white player (H/c)\n");
input=getch();
if(input == 'c'){
computer[0]=depth;
printw("Computer.\n");
}
else{
computer[1]=0;
printw("Human.\n");
}
printw("Choose type of the black player(h/C)\n");
input=getch();
if(input == 'h'){
computer[1]=0;
printw("Human.\n");
}
else{
computer[1]=depth;
printw("Computer.\n");
}
Start:
curs_set(0);
py=px=0;
memset(game,0,64);
bool turn=0;
bool resign=0;
byte cantmove=0;
game[3][3]=piece[0];
game[4][4]=piece[0];
game[3][4]=piece[1];
game[4][3]=piece[1];
Turn:
erase();
flushinp();
header();
draw(3,0);
refresh();
if(cantmove >=2)//both sides cant move, the game ends
goto End;
turn = !turn;
if(computer[turn]){
if(can_move(game,piece[turn])){
mvprintw(13,0,"Thinking...");
refresh();
decide(game,piece[turn],piece[!turn],computer[turn]);
cantmove=0;
}
else
cantmove++;
goto Turn;
}
if(!can_move(game,piece[turn])){
cantmove++;
goto Turn;
}
else{
cantmove=0;
while(1){ //human control
erase();
header();
draw(3,0);
input=getch();
if( input==KEY_F(1) || input=='?' )
help();
if( input==KEY_F(2) )
gameplay();
if( input==KEY_MOUSE )
mouseinput();
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<7)
py++;
if( (input=='h' || input==KEY_LEFT) && px>0)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<7)
px++;
if( input=='q'){
resign=1;
goto End;
}
if(input=='\n'){
if(can_reverse(py,px,game,piece[turn])){
reverse(py,px,game,piece[turn]);
goto Turn;
}
}
}
}
End:
if(resign)
mvprintw(13,0,"You resigned.");
else if(score[0]==score[1])
mvprintw(13,0,"Draw!!");
else if(score[0] > score[1])
mvprintw(13,0,"'%c' won.",piece[0]);
else
mvprintw(13,0,"'%c' won.",piece[1]);
printw(" Wanna play again?(y/n)");
curs_set(1);
input=getch();
if( resign){
if (input=='Y' || input=='y')
goto Start;
}
else if(input != 'N' && input != 'n' && input != 'q')
goto Start;
endwin();
return EXIT_SUCCESS;
}

403
sources/sos.c Normal file
View File

@ -0,0 +1,403 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
#define NOTHING 123
/*
_ _ _
(_'| |(_'
._):_:._)
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
typedef signed char byte;
int len,wid,py,px;
chtype colors[6]={A_BOLD};
int score[2] ={0};
int computer[2]={0};
char so[2] = {'S','O'};
char rd(char board[len][wid],int y, int x){
if(y<0 || x<0 || y>= len || x>=wid)
return NOTHING;
else
return board[y][x];
}
void color(byte colored[len][wid],int y,int x,bool side){
if(colored[y][x] == !side || colored[y][x]==2)
colored[y][x]=2;
else
colored[y][x]=side;
}
void rectangle(int sy,int sx){
for(int y=0;y<=len+1;y++){
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+wid*2,ACS_VLINE);
}
for(int x=0;x<=wid*2;x++){
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+len+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+len+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+wid*2,ACS_URCORNER);
mvaddch(sy+len+1,sx+wid*2,ACS_LRCORNER);
}
void draw(int sy,int sx,char board[len][wid],byte colored[len][wid]){
rectangle(sy,sx);
chtype attr ;
char prnt;
int y,x;
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
attr=A_NORMAL;
if(y==py && x==px)
attr |= A_STANDOUT;
if(colored[y][x]>=0)
attr |= colors[colored[y][x]];
if( board[y][x] )
prnt = board[y][x];
else
prnt = '_';
mvaddch(sy+1+y,sx+x*2+1,attr|prnt);
}
}
}
byte did_sos(char board[len][wid], int y , int x ){
byte dy,dx;
byte soses=0;
if(board[y][x]== 'S'){
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if(rd(board,y+dy,x+dx)=='O' && rd(board,y+2*dy,x+2*dx) == 'S' )
soses++;
}
}
return soses;
}
else if(board[y][x]== 'O'){
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if(rd(board,y+dy,x+dx)=='S' && rd(board,y-dy,x-dx) =='S')
soses++;
}
}
return soses/2;
}
return 0;
}
void color_sos(char board[len][wid],byte colored[len][wid], int y , int x ,bool side){
byte dy,dx;
if(board[y][x]== 'S'){
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if(rd(board,y+dy,x+dx)=='O' && rd(board,y+2*dy,x+2*dx) == 'S' ){
color(colored,y,x,side);
color(colored,y+dy,x+dx,side);
color(colored,y+2*dy,x+2*dx,side);
}
}
}
}
else if(board[y][x]== 'O'){
for(dy=-1;dy<2;dy++){
for(dx=-1;dx<2;dx++){
if(rd(board,y+dy,x+dx)=='S' && rd(board,y-dy,x-dx) =='S'){
color(colored,y,x,side);
color(colored,y+dy,x+dx,side);
color(colored,y-dy,x-dx,side);
}
}
}
}
}
void randmove(int* y,int* x,byte* c){
*y=random()%len;
*x=random()%wid;
*c=random()%2;
}
int decide ( char board[len][wid],byte colored[len][wid], byte depth , byte side ){ //the move is imaginary if side is negative
int adv,bestadv;
int oppadv;
int besty,bestx;
char bestchar;
byte c;
oppadv=adv=bestadv=INT_MIN;
besty=bestx=-1;
int y,x;
int ry,rx;
byte rc;
randmove(&ry,&rx,&rc);//provides efficient randomization
for(y=0;y<len;y++){
for(x=0;x<wid;x++){
if(!board[y][x]){
for(c=0;c<2;c++){
board[y][x]=so[c];
adv=did_sos(board,y,x);
if(depth>0)
oppadv= decide(board,NULL,depth-1,-1);
if(depth>0 && oppadv != INT_MIN)//this has no meanings if the opponet cannot move
adv-=1*oppadv;
if(besty<0 ||adv>bestadv || (adv==bestadv && y==ry && x==rx && c==rc /*c==0*/) ){
bestadv=adv;
besty=y;
bestx=x;
bestchar=so[c];
}
board[y][x]=0;
}
}
}
}
if(besty>=0 && side >= 0 ){
board[besty][bestx]=bestchar;
score[side]+= did_sos(board,besty,bestx);
color_sos(board,colored,besty,bestx,side);
}
return bestadv;
}
bool isfilled(char board[len][wid]){
int y,x;
for(y=0;y<len;y++)
for(x=0;x<wid;x++)
if(!board[y][x])
return 0;
return 1;
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(int sy,int sx){
MEVENT minput;
getmouse(&minput);
if( minput.y-4-sy <len && minput.x-1-sx<wid*2){
py=minput.y-4-sy;
px=(minput.x-1-sx)/2;
}
else
return;
if(minput.bstate & BUTTON1_CLICKED)
ungetch('S');
if(minput.bstate & (BUTTON2_CLICKED|BUTTON3_CLICKED) )
ungetch('O');
}
void help(void){
erase();
mvprintw(0,0," _ _ _");
mvprintw(1,0,"(_'| |(_' ");
mvprintw(2,0,"._):_:._) ");
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(9,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(5,0,"S & O : Write S or O");
mvprintw(6,0,"q : Quit");
mvprintw(7,0,"F1 & F2: Help on controls & gameplay");
mvprintw(8,0,"PgDn,PgUp,<,> : Scroll");
mvprintw(11,0,"Press a key to continue");
refresh();
getch();
erase();
}
void gameplay(void){
erase();
mvprintw(0,0," _ _ _");
mvprintw(1,0,"(_'| |(_' ");
mvprintw(2,0,"._):_:._) ");
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("The game is similiar to Tic Tac Toe:\n");
printw("The players write S and O in the squares\n");
printw("and making the straight connected sequence\n");
printw("S-O-S makes you a score; obviously, the\n");
printw("player with a higher score wins.");
refresh();
getch();
erase();
}
int main(int argc, char** argv){
int dpt=1;
signal(SIGINT,sigint_handler);
if(argc>4 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [len wid [AIpower]]\n",argv[0]);
return EXIT_FAILURE;
}
if(argc==2){
puts("Give both dimensions.");
return EXIT_FAILURE;
}
if(argc>=3){
bool lool = sscanf(argv[1],"%d",&len) && sscanf(argv[2],"%d",&wid);
if(!lool){
puts("Invalid input.");
return EXIT_FAILURE;
}
if(len<3 || wid<3 || len>300 || wid>300){
puts("At least one of your given dimensions is either too small or too big.");
return EXIT_FAILURE;
}
}
else{
len=5;
wid=6;
}
if(argc==4){
if( !sscanf(argv[3],"%d",&dpt)){
puts("Invalid input.");
return EXIT_FAILURE;
}
if( dpt<1 || dpt>= 127){
puts("That should be between 1 and 127.");
return EXIT_FAILURE;
}
}
srandom(time(NULL)%UINT_MAX);
int input;
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
curs_set(0);
noecho();
cbreak();
keypad(stdscr,1);
printw("Black plays first.\n Choose the type of the blue player(H/c)\n" );
input=getch();
if(input=='c'){
computer[0]=dpt;
printw("Computer.\n");
}
else{
computer[0]=0;
printw("Human.\n");
}
printw("Choose the type of the yellow player(h/C)\n");
input=getch();
if(input=='h'){
computer[1]=0;
printw("Human.\n");
}
else{
computer[1]=dpt;
printw("Computer.\n");
}
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_BLUE,-1);
init_pair(2,COLOR_YELLOW,-1);
init_pair(3,COLOR_GREEN,-1);
for(byte b= 0;b<6;b++){
colors[b]=COLOR_PAIR(b+1);
}
}
int sy,sx;
Start:
sy=sx=0;//for scrolling
py=px=0;
char board[len][wid];
byte colored[len][wid];
bool t=1;
score[0]=score[1]=0;
memset(board,0,len*wid);
memset(colored,-1,len*wid);
Turn:
erase();
mvprintw(sy+0,sx+0," _ _ _");
mvprintw(sy+1,sx+0,"(_'| |(_' %d vs %d \n",score[0],score[1]);
mvprintw(sy+2,sx+0,"._):_:._) \n");
draw(sy+3,sx+0,board,colored);
if( isfilled(board) )
goto End;
refresh();
t=!t;
if(computer[t]){
mvprintw(sy+len+5,sx+0,"Thinking...");
refresh();
decide(board,colored,dpt,t);
goto Turn;
}
//else
while(1){
erase();
mvprintw(sy+0,sx+0," _ _ _");
mvprintw(sy+1,sx+0,"(_'| |(_' %d vs %d \n",score[0],score[1]);
mvprintw(sy+2,sx+0,"._):_:._) \n");
draw(sy+3,sx+0,board,colored);
refresh();
input = getch();
if( input==KEY_PPAGE && LINES< len+3){//the board starts in 3
sy+=10;
if(sy>0)
sy=0;
}
if( input==KEY_NPAGE && LINES< len+3){
sy-=10;
if(sy< -(len+3) )
sy=-(len+3);
}
if( input=='<' && COLS< wid*2+1){
sx+=10;
if(sx>0)
sx=0;
}
if( input=='>' && COLS< wid*2+1){
sx-=10;
if(sx< -(wid*2+1))
sx=-(wid*2+1);
}
if( input==KEY_F(1) || input=='?')
help();
if( input==KEY_F(2) )
gameplay();
if( input==KEY_MOUSE )
mouseinput(sy,sx);
if( (input=='k' || input==KEY_UP) && py>0)
py--;
if( (input=='j' || input==KEY_DOWN) && py<len-1)
py++;
if( (input=='h' || input==KEY_LEFT) && px>0)
px--;
if( (input=='l' || input==KEY_RIGHT) && px<wid-1)
px++;
if( input=='q')
sigint_handler(0);
if(!board[py][px] && (input=='s'||input=='S'||input=='o'||input=='O') ){
if(input=='s'||input=='S')
board[py][px]='S';
else
board[py][px]='O';
score[t]+=did_sos(board,py,px);
color_sos(board,colored,py,px,t);
goto Turn;
}
}
End:
if( score[1] == score[0])
mvprintw(sy+len+5,sx+0,"Draw!!");
else
mvprintw(sy+len+5,sx+0,"Player %d won the game!",(score[1]>score[0]) +1);
printw(" Wanna play again?(y/n)");
curs_set(1);
flushinp();
input=getch();
curs_set(0);
if(input != 'N' && input != 'n' && input!='q')
goto Start;
endwin();
return EXIT_SUCCESS;
}

441
sources/sudoku.c Normal file
View File

@ -0,0 +1,441 @@
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> //to seed random
#include <limits.h>
#include <signal.h>
#include <math.h>
/*
_
(_
_)UDOKU
copyright Hossein Bakhtiarifar 2018 (c)
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
NOTE: This program is only made for entertainment porpuses. The puzzles are generated by randomly clearing tiles on the table and are guaranteed to have a solution , but are not guaranteed to have only one unique solution.
*/
typedef signed char byte;
byte wait=0, waitcycles=0;
byte size,s;//s=size*size
byte py,px;
byte diff;
unsigned int filled;
chtype colors[6]={0};
void cross(byte sy,byte sx,chtype start,chtype middle,chtype end){ //to simplify drawing tables. doesn't draw a cross (why did I choose that name?)
mvaddch(sy,sx,start);
byte f = 2*size;
for(char n=1;n<size;n++){
mvaddch(sy,sx+f,middle);
f+=2*size;
}
mvaddch(sy,sx+f,end);
}
void table(byte sy,byte sx){ //empty table
byte l;//line
for(l=0;l<=size;l++){
for(byte y=0;y<=s+size;y++)
mvaddch(sy+y,sx+l*size*2,ACS_VLINE);
for(byte x=0;x<=s*2;x++)
mvaddch(sy+(size+1)*l,sx+x,ACS_HLINE);
}
cross(sy,sx,ACS_ULCORNER,ACS_TTEE,ACS_URCORNER);
for(l=1;l<size;l++)
cross(sy+l*size+l,sx,ACS_LTEE,ACS_PLUS,ACS_RTEE);
cross(sy+l*size+l,sx,ACS_LLCORNER,ACS_BTEE,ACS_LRCORNER);
}
byte sgn2int(char sgn){
if('0'<sgn && sgn <='9')
return sgn-'0';
if('a'<=sgn && sgn <='z')
return sgn-'a'+10;
if('A'<=sgn && sgn <= 'Z')
return sgn-'A'+36;
return 0;
}
char int2sgn(byte num){// convert integer to representing sign
if(0< num && num <= 9)
return num+'0';
else if(10<=num && num <=35)
return num-10+'a';
else if(36<=num && num <=51)
return num-36+'A';
return 0;
}
bool isvalid(byte ty,byte tx,char board[s][s]){ //is it allowed to place that char there?
char t= board[ty][tx];
if(!t)
return 0;
byte y,x;
for(y=0;y<s;y++){
if(board[y][tx] == t && y!=ty)
return 0;
}
for(x=0;x<s;x++){
if(board[ty][x] == t && x!= tx)
return 0;
}
byte sy=size*(ty/size);//square
byte sx=size*(tx/size);
for(y=0;y<size;y++){
for(x=0;x<size;x++){
if(board[sy+y][sx+x]==t && sy+y != ty && sx+x != tx)
return 0;
}
}
return 1;
}
void genocide(char board[s][s],char victim){
for(byte y=0;y<s;y++)
for(byte x=0;x<s;x++)
if(board[y][x]==victim)
board[y][x]=0;
}
bool fill_with(char board[s][s],char fillwith){//returns 1 on failure
byte firstx,x,tries=0;
Again:
tries++;
if (tries>s)
return 1;
for(byte y=0;y<s;y++){//there should be only one occurence of a number in a row, and this function makes use of this fact to improve generation speed
firstx=x=random()%s;
while(1){
if(!board[y][x]){
board[y][x]=fillwith;
if(isvalid(y,x,board)){
break;
}
else{
board[y][x]=0;
goto Next;
}
}
else{
Next:
x++;
if(x==s)
x=0;
if(x==firstx){
genocide(board,fillwith);
goto Again;
}
}
}
}
refresh();
return 0;
}
void fill(char board[s][s]){
for(byte num=1;num<=s;num++){//it fills random places in the board with 1s, then random places in the remaining space with 2s and so on...
if(num==4){//something that randomly happens
wait=(wait+1)%60;
if(!wait && waitcycles<3)
waitcycles++;
}
if ( fill_with(board,int2sgn(num) ) ){
memset(board,0,s*s);
num=0;
mvaddstr(0,0,"My algorithm sucks, so you need to wait a bit ");//with animated dots to entertain the waiter
if(waitcycles==3)
mvaddstr(2,0,"(You can set SUDOKU_FASTGEN if you just want to see if it works)");
move(0,45);
for(byte b=0;b<wait;b+=10)
addch('.');
}
}
}
void swap(char board[s][s],char A,char B){
byte y,x;
for(y=0;y<s;y++){
for(x=0;x<s;x++){
if(board[y][x]==A)
board[y][x]=B;
else if(board[y][x]==B)
board[y][x]=A;
}
}
}
void justfill(char board[s][s]){//sometimes fill() gets too much , and you just want a 49x49 sudoku puzzle of any quality
byte y,x,k;//k is here to minimize calls to isvalid()
for(y=0;y<s;y++){//fill with 1,2,3,4...
k=1;
for(x=0;x<s;x++){
board[y][x]=int2sgn(k);
while(!isvalid(y,x,board)){
board[y][x]=int2sgn(k=k+1);
if(k>s)
board[y][x]=int2sgn(k=1);
}
k++;
if(k>s)
k=1;
}
}
for(byte n=0;n<s*2;n++)//randomize
swap(board,int2sgn(1+(random()%s)),int2sgn(1+(random()%s)) );
}
void mkpuzzle(char board[s][s],char empty[s][s],char game[s][s]){//makes a puzzle to solve
byte y,x;
for(y=0;y<s;y++){
for(x=0;x<s;x++){
if( !(random()%diff) ){
empty[y][x]=board[y][x];
game[y][x]=board[y][x];
}
}
}
}
void header(byte sy,byte sx){
mvaddch(sy, sx+1, '_');
mvprintw(sy+1,sx,"(_ Solved:%d/%d",filled,s*s);
mvprintw(sy+2,sx," _)UDOKU Left :%d/%d",s*s-filled,s*s);
}
void draw(byte sy,byte sx,char empty[s][s],char game[s][s]){
chtype attr;
table(sy,sx);
filled=0;
for(byte y=0;y<s;y++){
for(byte x=0;x<s;x++){
attr=A_NORMAL;
if(x==px && y==py)
attr |= A_STANDOUT;
if(empty[y][x])
attr |= A_BOLD;
if(game[y][x]){
if(!isvalid(y,x,game))
attr |= colors[5];
else{
attr |= colors[game[y][x]%5];
filled++;
}
mvaddch(sy+y+y/size+1,sx+x*2+1,attr|game[y][x]);
}
else
mvaddch(sy+y+y/size+1,sx+x*2+1,attr|' ');
}
}
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(int sy, int sx){
MEVENT m;
getmouse(&m);
if( m.y < (3+1+size+s)-sy && m.x<(2*s+1)-sx ){//it's a shame to include math.h only for round() but it was the only moral way to make gcc shut up
py= round( (float)(size*(m.y-4-sy))/(size+1) );//these are derived from the formulas in draw() by simple algebra
px=(m.x-1-sx)/2;
}
else
return;
if(m.bstate & BUTTON1_CLICKED)
ungetch('\n');
if(m.bstate & (BUTTON2_CLICKED|BUTTON3_CLICKED) )
ungetch(' ');
}
void help(void){
erase();
header(0,0);
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
mvprintw(13,0,"YOU CAN ALSO USE THE MOUSE!");
attroff(A_BOLD);
mvprintw(4,0,"1 - %c : Enter number/character",int2sgn(s));
mvprintw(5,0,"SPACE : Clear tile");
mvprintw(6,0,"ARROW KEYS : Move cursor");
mvprintw(7,0,"q : Quit");
mvprintw(8,0,"n : New board");
mvprintw(9,0,"r : Restart");
if(size>4)
printw(" (some of these alphabet controls maybe overrided in certain sizes)");
mvprintw(10,0,"? : Hint (not like in other games)");
mvprintw(11,0,"F1 & F2: Help on controls & gameplay");
mvprintw(12,0,"PgDn,PgUp,<,> : Scroll");
mvprintw(15,0,"Press a key to continue");
refresh();
getch();
erase();
}
void gameplay(void){
erase();
header(0,0);
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
move(4,0);
printw("Fill the table with digits");
if(size>3)
printw(" (and characters) \n");
else
addch('\n');
printw("so that all the rows, columns and smaller subregions \n");
printw("contain all of the digits from 1 to ");
if(size<=3){
addch(int2sgn(s));
addch('.');
}
if(size>3){
addch('9');
printw(" and all\nthe alphabet letters from 'a' to '%c'.",int2sgn(s));
}
printw("\n\nPress a key to continue.");
refresh();
getch();
erase();
}
int main(int argc,char** argv){
signal(SIGINT,sigint_handler);
if(argc>4 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [size [ difficulty]] \n",argv[0]);
return EXIT_FAILURE;
}
if(argc>1 ){
if(strlen(argv[1])>1 || argv[1][0]-'0'>7 || argv[1][0]-'0'< 2){
printf("2 <= size <= 7\n");
return EXIT_FAILURE;
}
else
size = *argv[1]-'0';
}
else
size=3;
if(argc>2){
if (strlen(argv[2])>1 || argv[2][0]-'0'>4 || argv[2][0]-'0'<= 0 ){
printf("1 <= diff <=4\n");
return EXIT_FAILURE;
}
else
diff = *argv[2]-'0'+1;
}
else
diff=2;
bool fastgen= !(!getenv("SUDOKU_FASTGEN"));
initscr();
mousemask(ALL_MOUSE_EVENTS,NULL);
noecho();
cbreak();
keypad(stdscr,1);
srandom(time(NULL)%UINT_MAX);
if( has_colors() ){
start_color();
use_default_colors();
init_pair(1,COLOR_YELLOW,-1);
init_pair(2,COLOR_GREEN,-1);
init_pair(3,COLOR_BLUE,-1);
init_pair(4,COLOR_CYAN,-1);
init_pair(5,COLOR_MAGENTA,-1);
init_pair(6,COLOR_RED,-1);
for(byte b=0;b<6;b++){
colors[b]=COLOR_PAIR(b+1);
}
}
s= size*size;
char board[s][s];
char empty[s][s];
char game[s][s];
int input=0;
int sy,sx;
Start:
sy=sx=0;
erase();
curs_set(0);
filled =0;
memset(board,0,s*s);
memset(empty,0,s*s);
memset(game,0,s*s);
if(fastgen)
justfill(board);
else
fill(board);
mkpuzzle(board,empty,game);
py=px=0;
while(1){
erase();
draw(sy+3,sx+0,empty,game);
header(sy+0,sx+0);
refresh();
if(filled == s*s)
break;
input = getch();
if( input==KEY_PPAGE && LINES< s+size+3){//the board starts in 3
sy+=10;
if(sy>0)
sy=0;
}
if( input==KEY_NPAGE && LINES< s+size+3){
sy-=10;
if(sy< -(s+size+3) )
sy=-(s+size+3);
}
if( input=='<' && COLS< s*2){
sx+=10;
if(sx>0)
sx=0;
}
if( input=='>' && COLS< s*2){
sx-=10;
if(sx< -(s*2))
sx=-(s*2);
}
if(input == KEY_F(1))
help();
if(input == KEY_F(2))
gameplay();
if(input == KEY_MOUSE)
mouseinput(sy,sx);
if(input == KEY_UP && py)
py--;
if(input == KEY_DOWN && py<s-1)
py++;
if(input == KEY_LEFT && px)
px--;
if(input == KEY_RIGHT && px<s-1)
px++;
if(!empty[py][px]){
if(input == ' ' )
game[py][px]=0;
else if(input<=CHAR_MAX && sgn2int(input) && sgn2int(input)<=s )
game[py][px]=input;
}
if( (input=='q' && size<= 5) || input=='Q')
sigint_handler(EXIT_SUCCESS);
if(input=='n'&& size <= 4)
goto Start;
if(input=='r'&& size <= 5){
byte y,x;
for(y=0;y<s;y++)
for(x=0;x<s;x++)
game[y][x]=empty[y][x];
}
if(input=='?')
game[py][px]=board[py][px];
if(input == 'X' && getch()=='Y' && getch()=='Z' && getch()=='Z' && getch()=='Y'){
byte y,x;
for(y=0;y<s;y++)
for(x=0;x<s;x++)
game[y][x]=board[y][x];
}
}
mvprintw(sy+s+size+4,sx+0,"Yay!! Wanna play again?(y/n)");
curs_set(1);
input=getch();
if(input != 'N' && input != 'n' && input != 'q')
goto Start;
endwin();
return EXIT_SUCCESS;
}