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

first commit

This commit is contained in:
abdulrahman 2018-09-21 20:12:39 +04:30
commit e67121e495
8 changed files with 2461 additions and 0 deletions

39
README.md Normal file
View File

@ -0,0 +1,39 @@
# New BSD Games
The TUI games i made for NetBSD ( If they accept these ).
These include:
Jewels (A game with a gameplay similiar to that of Tetris, NOT my invention)
Sudoku
Mines (Minesweeper)
Reversi
Checkers
Battleship
### Prerequisites
ALL you need is a C compiler with C99 enabled , the standard library and libncurses (the dev package if you are on debian).
### How to run
Just download them somehow and compile them with ncurses being linked.
Normally:
```
cc "address_to_sourcefiles/game_name.c" -lncurses -o "address_to_binaries/game_name"
```
I am too lazy to write a script for this.
### How do these look like
![Screenshot including the checkers game and the battleship one] (screenshot.png)
### License
Public Domain.
I am living outside the Berne convention , This would be public domain anyway.

560
games/battleship.c Normal file
View File

@ -0,0 +1,560 @@
#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 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=='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
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 -1;
}
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 some isolated tiles being unshot (with their ships being shot before).
a human will *very easily* find the tiles with logical thinking, but the computer is random 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 this variables
byte y,x,r;
Again:
if( firstinrowy == NOTHING ){
if( score[!side] > 13 && 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;
x= firstinrowx;
MID(&y,&x,goindirection);
r= shoot(side,y,x);
if( r != 1 ){
goindirection = (goindirection+1)%4;
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);
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;
}
}
}
int main(int argc , char** argv){
initscr();
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=='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=='y' || input=='Y' ){
curs_set(0);
goto Start;
}
endwin();
return 0;
}

604
games/checkers.c Normal file
View File

@ -0,0 +1,604 @@
#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
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);
}
}
}
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;
}
}
}
}
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;
}
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;
}
bool can_move(byte side){//would be much faster than applying moves() on every tile
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;
}
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;
}
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;
}
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;
}
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 in the center, movements to all of the board would be in the game tree horizon(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;
}
double decide(byte side,byte depth,byte s){
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;
else if(!depth){
if(s==IMAGINARY || s==NORMAL)
adv=advantage(side);
else
adv=posadvantage(side);
}
else{
if(nextturn==side)
adv=decide(nextturn,depth,nexts);
else{
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 ){
if(wrstadv == WIN){//the randomization in the algorithm may cause an illusion of inevitable win
if(depth > 1)
decide(side,depth-1,NORMAL);
else
goto Move;
}
else
decide(side,depth,ALT_NRM);
}
else{
Move:
cmove(besty,bestx,besttoy,besttox);
kinged=king(besttoy,besttox);
if(!kinged && can_jump(besttoy,besttox) ){
jumpagainy = besttoy;
jumpagainx = besttox;
}
else
jumpagainy=jumpagainx=-1;
}
}
return bestadv;
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
int main(int argc,char** argv){
dpt=3;
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();
noecho();
cbreak();
keypad(stdscr,1);
int input ;
printw("Black plays first.\n Choose type of the black 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 white 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 gained advantage 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=='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 black side has won the game.");
break;
case 0:
printw("Draw.");
break;
case 1:
printw("The white side has won the game.");
break;
case 2:
printw("You resigned.");
}
printw(" Wanna rematch?(y/N)");
curs_set(1);
input=getch();
if(input=='y' || input=='Y'){
byte b=computer[0];
computer[0]=computer[1];
computer[1]=b;
goto Start;
}
endwin();
return EXIT_SUCCESS;
}

365
games/jewels.c Normal file
View File

@ -0,0 +1,365 @@
#include <curses.h>
#include <time.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#define LEN 17
#define WID 19
#define DELAY 2
#define SAVE_TO_NUM 10
#define DEF_ADDRESS "JewelScores"
/*
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];
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(DEF_ADDRESS,"r")) ){
deforno=1;
}
else{
deforno=0;
if( !(scorefile = fopen(getenv("JW_SCORES"),"r")) ){
printf("\nNo accessible score files found.\n");
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(DEF_ADDRESS,"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****CONRAGULATIONS!***\n");
printf(" _____ You bet the\n");
printf(" .' | previous\n");
printf(" .' | record\n");
printf(" | .| | of\n");
printf(" |.' | |%11ld\n",formerscore);
printf(" | | held by\n");
printf(" ___| |___%8s\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(void){
bool ret =0;
chtype c,uc;
byte n;
byte y,x;
for(y=0;y<LEN;y++){
c=uc=n=0;
for(byte x=0;x<WID;x++){
uc = c;
c = board[y][x];
if(c && c == uc)
n++;
else
n=0;
if(n==3){
ret=1;
for(;n>=0;n--)
board[y][x-n]=0;
n=0;
score+=30;
}
}
}
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++;
else
n=0;
if(n==3){
ret=1;
for(;n>=0;n--)
board[y-n][x]=0;
n=0;
score+=30;
}
}
}
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);
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);
int input;
bool falls;
byte stop=0;
char jwstr[] = {'*','^','~','"','$','V'};
chtype colors[6]={0};
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<5;n++){
colors[n] = COLOR_PAIR(n+1);
}
}
srandom(time(NULL)%UINT_MAX);
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;
byte ran1= random()%5;
byte ran2= random()%5;
board[jy][jx]=colors[ran1]|jwstr[ran1];
board[jy+ky][jx+kx]=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')
jmove(0,+1);
else if(input=='j')
jmove(0,-1);
else if(input=='k')
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();
}
while(explode()){ // explode, fall, explode, fall until nothing is left
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;
}

266
games/mines.c Normal file
View File

@ -0,0 +1,266 @@
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
/*
|\/|
| |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;
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);
}
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);
}
}
}
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,'*');
}
}
}
}
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)
return 0;
if(board[ty][tx]<0 || board[ty][tx]>8){//untouched
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]){
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);
}
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 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);
Start:
initscr();
curs_set(0);
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);
}
}
py=px=0;
untouched=len*wid;
int flags=0;
byte board[len][wid];
bool mines[len][wid];
char result[70];
int input;
memset(board,-1,len*wid);
memset(mines,false,len*wid);
mine(mines);
while(1){
erase();
mvprintw(1,0,"|\\/| Flags:%d\n",flags);
mvprintw(2,0,"| |INES Mines:%d\n",mscount);
draw(3,0,board);
refresh();
if(untouched<=mscount){
strcpy(result,"You won!");
break;
}
input = getch();
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]){
strcpy(result,"You lost The Game.");
break;
}
click(board,mines,py,px);
}
if(input==' '){
if(board[py][px] == -1){
board[py][px]=9;//flag
flags++;
}
else if(board[py][px] == 9){
board[py][px]=10;//unclear
flags--;
}
else if(board[py][px] == 10)
board[py][px]=-1;
}
}
drawmines(3,0,board,mines);
mvprintw(len+5,0,"%s Wanna play again?(y/n)",result);
curs_set(1);
input=getch();
if(input == 'Y' || input == 'y')
goto Start;
endwin();
return EXIT_SUCCESS;
}

340
games/reversi.c Normal file
View File

@ -0,0 +1,340 @@
#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){//buse
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 do a move 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)//infinite
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){
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]){
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;
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
int main(int argc , char** argv){
int depth=3;
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
else{
printf("That should be a number from 1 to 127.\n");
return EXIT_FAILURE;
}
}
signal(SIGINT,sigint_handler);
initscr();
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;
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)
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=='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')
sigint_handler(0);
if(input=='\n'){
if(can_reverse(py,px,game,piece[turn])){
reverse(py,px,game,piece[turn]);
goto Turn;
}
}
}
}
End:
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(input == 'Y' || input == 'y')
goto Start;
endwin();
return EXIT_SUCCESS;
}

287
games/sudoku.c Normal file
View File

@ -0,0 +1,287 @@
#include <curses.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> //to seed random
#include <limits.h>
#include <signal.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
*/
typedef unsigned char byte;
byte size,s,ds;//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
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<=ds;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){//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 legal 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++){
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++){
if ( fill_with(board,int2sgn(num) ) ){
memset(board,0,s*s);
num=0;
}
}
}
void mkpuzzle(char board[s][s],char empty[s][s],char game[s][s]){//makes a puzzle to solve
for(byte y=0;y<s;y++){
for(byte 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 board[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(board[y][x]){
if(!isvalid(y,x,board))
attr |= colors[5];
else{
attr |= colors[board[y][x]%5];
filled++;
}
mvaddch(sy+y+y/size+1,sx+x*2+1,attr|board[y][x]);
}
else
mvaddch(sy+y+y/size+1,sx+x*2+1,attr|' ');
}
}
}
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
int main(int argc,char** argv){
signal(SIGINT,sigint_handler);
if(argc>3 || (argc==2 && !strcmp("help",argv[1])) ){
printf("Usage: %s [size [ diff]]\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;
Start:
initscr();
noecho();
cbreak();
keypad(stdscr,1);
curs_set(0);
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);
}
}
filled =0;
s=size*size;
ds=s+size;
char board[s][s];
char empty[s][s];
char game[s][s];
memset(board,0,s*s);
memset(empty,0,s*s);
memset(game,0,s*s);
int input=0 ;
fill(board);
mkpuzzle(board,empty,game);
py=px=0;
while(1){
erase();
draw(3,0,empty,game);
header(0,0);
refresh();
if(filled == s*s)
break;
input = getch();
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)
sigint_handler(EXIT_SUCCESS);
if(input == 'x' && getch()=='y' && getch()=='z' && getch()=='z' && getch()=='y')
game[py][px]=board[py][px];
}
mvprintw(ds+4,0,"YAY!! Wanna play again?(y/n)");
curs_set(1);
input=getch();
if(input == 'Y' || input == 'y')
goto Start;
endwin();
return EXIT_SUCCESS;
}

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB