diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..954883d --- /dev/null +++ b/README.rst @@ -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). + + diff --git a/banner.png b/banner.png new file mode 100644 index 0000000..f92b736 Binary files /dev/null and b/banner.png differ diff --git a/linux_exec/battleship b/linux_exec/battleship new file mode 100755 index 0000000..c29b408 Binary files /dev/null and b/linux_exec/battleship differ diff --git a/linux_exec/checkers b/linux_exec/checkers new file mode 100755 index 0000000..dd25cf7 Binary files /dev/null and b/linux_exec/checkers differ diff --git a/linux_exec/jewels b/linux_exec/jewels new file mode 100755 index 0000000..481758e Binary files /dev/null and b/linux_exec/jewels differ diff --git a/linux_exec/mines b/linux_exec/mines new file mode 100755 index 0000000..d7e4e7c Binary files /dev/null and b/linux_exec/mines differ diff --git a/linux_exec/pipes b/linux_exec/pipes new file mode 100755 index 0000000..eb89dad Binary files /dev/null and b/linux_exec/pipes differ diff --git a/linux_exec/rabbithole b/linux_exec/rabbithole new file mode 100755 index 0000000..18bdb3b Binary files /dev/null and b/linux_exec/rabbithole differ diff --git a/linux_exec/reversi b/linux_exec/reversi new file mode 100755 index 0000000..4b31d5d Binary files /dev/null and b/linux_exec/reversi differ diff --git a/linux_exec/sos b/linux_exec/sos new file mode 100755 index 0000000..b24b4b4 Binary files /dev/null and b/linux_exec/sos differ diff --git a/linux_exec/sudoku b/linux_exec/sudoku new file mode 100755 index 0000000..ba9af21 Binary files /dev/null and b/linux_exec/sudoku differ diff --git a/screenshot.png b/screenshot.png index e823d4c..d486fd8 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/sources/Makefile b/sources/Makefile new file mode 100644 index 0000000..bf17752 --- /dev/null +++ b/sources/Makefile @@ -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) + diff --git a/sources/battleship.c b/sources/battleship.c new file mode 100644 index 0000000..a384762 --- /dev/null +++ b/sources/battleship.c @@ -0,0 +1,618 @@ +#include +#include +#include +#include +#include +#include +#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=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=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]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; +} diff --git a/sources/checkers.c b/sources/checkers.c new file mode 100644 index 0000000..01b564a --- /dev/null +++ b/sources/checkers.c @@ -0,0 +1,678 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#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= 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; +} diff --git a/sources/config.h b/sources/config.h new file mode 100644 index 0000000..0320d18 --- /dev/null +++ b/sources/config.h @@ -0,0 +1,3 @@ +#define PP_SCORES "PipesScores" +#define JW_SCORES "JewelsScores" +//for easier access diff --git a/sources/jewels.c b/sources/jewels.c new file mode 100644 index 0000000..eaf65dc --- /dev/null +++ b/sources/jewels.c @@ -0,0 +1,389 @@ +#include +#include +#include +#include +#include +#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=itreached || score>=scorebuff[location]) ){ + fprintf(scorefile,"%s : %ld\n",getenv("USER"),score); + ret=location; + wroteit=1; + } + if(location*>*>Top %d<*<*<\n",SAVE_TO_NUM); + while( rank>>"); + 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=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=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= 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; +} diff --git a/sources/mines.c b/sources/mines.c new file mode 100644 index 0000000..9d897be --- /dev/null +++ b/sources/mines.c @@ -0,0 +1,361 @@ +#include +#include +#include +#include +#include +#include +#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;y9) + 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=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=len) + break; + for (x=tx-1;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=len) + break; + for(x=tx-1;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 : 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) && py0) + px--; + if( (input=='l' || input==KEY_RIGHT) && px +#include +#include +#include +#include +#include +#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=itreached || score>=scorebuff[location]) ){ + fprintf(scorefile,"%s : %ld\n",getenv("USER"),score); + ret=location; + wroteit=1; + } + if(location0){ + 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>>"); + 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;y3 || (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=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) && py0 ) + px--; + if( (input=='l' || input==KEY_RIGHT) && px +#include +#include +#include +#include +#include +#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 : 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) && py0 && (board[py][px]&LEFT) ) + px--; + if( (input=='l' || input==KEY_RIGHT) && px +#include +#include +#include +/* + _ +|_) +| \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=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; +} diff --git a/sources/sos.c b/sources/sos.c new file mode 100644 index 0000000..80b2b7a --- /dev/null +++ b/sources/sos.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include +#include +#include +#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=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;y0) + 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 : 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) && py0) + px--; + if( (input=='l' || input==KEY_RIGHT) && pxscore[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; +} diff --git a/sources/sudoku.c b/sources/sudoku.c new file mode 100644 index 0000000..a4e9d81 --- /dev/null +++ b/sources/sudoku.c @@ -0,0 +1,441 @@ +#include +#include +#include +#include //to seed random +#include +#include +#include +/* + _ +(_ + _)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;ns) + return 1; + for(byte y=0;ys) + board[y][x]=int2sgn(k=1); + } + k++; + if(k>s) + k=1; + } + } + for(byte n=0;n4) + 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