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

274 lines
5.5 KiB
C
Raw Normal View History

2019-05-13 09:58:19 -04:00
/*
2020-06-20 23:35:03 -04:00
.--
2019-05-13 09:58:19 -04:00
|__
| IFTEEN
2020-06-20 12:26:54 -04:00
Authored by abakh <abakh@tuta.io>
2019-05-13 09:58:19 -04:00
No rights are reserved and this software comes with no warranties of any kind to the extent permitted by law.
compile with -lncurses
*/
2020-06-20 12:26:54 -04:00
#include <curses.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <signal.h>
2020-09-12 06:38:45 -04:00
#include "config.h"
2020-06-21 03:02:36 -04:00
typedef signed char byte;
/* The Plan9 compiler can not handle VLAs */
2020-09-12 06:38:45 -04:00
#ifdef NO_VLA
#define size 4
2020-06-20 12:26:54 -04:00
#else
2019-05-13 09:58:19 -04:00
byte size;
#endif
2019-05-13 09:58:19 -04:00
byte py,px;
byte ey,ex; //the empty tile
chtype green=A_BOLD; //bold when there is no color
void rectangle(byte sy,byte sx){
2020-06-20 12:26:54 -04:00
for(byte y=0;y<=size+1;++y){
2019-05-13 09:58:19 -04:00
mvaddch(sy+y,sx,ACS_VLINE);
mvaddch(sy+y,sx+size*2,ACS_VLINE);
}
2020-06-20 12:26:54 -04:00
for(byte x=0;x<=size*2;++x){
2019-05-13 09:58:19 -04:00
mvaddch(sy,sx+x,ACS_HLINE);
mvaddch(sy+size+1,sx+x,ACS_HLINE);
}
mvaddch(sy,sx,ACS_ULCORNER);
mvaddch(sy+size+1,sx,ACS_LLCORNER);
mvaddch(sy,sx+size*2,ACS_URCORNER);
mvaddch(sy+size+1,sx+size*2,ACS_LRCORNER);
}
void logo(byte sy,byte sx){
2020-06-20 23:35:03 -04:00
mvaddstr(sy,sx, ".--");
2019-05-13 09:58:19 -04:00
mvaddstr(sy+1,sx,"|__");
mvaddstr(sy+2,sx,"| IFTEEN");
}
//convert integer to representing sign
char int2sgn(byte num){
if(!num)
return ' ';
2020-05-18 14:59:29 -04:00
else 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;
2019-05-13 09:58:19 -04:00
}
/*bool isinorder(byte board[size][size],byte y,byte x){ using check[][] is much cheaper
return (board[y][x] == y*size+x+1);
} */
//display
void draw(byte sy,byte sx,char board[size][size],char check[size][size]){
rectangle(sy,sx);
chtype prnt;
byte y,x;
2020-06-20 12:26:54 -04:00
for(y=0;y<size;++y){
for(x=0;x<size;++x){
2019-05-13 09:58:19 -04:00
prnt=board[y][x];
if(check[y][x]==board[y][x] && check[y][x] != ' ')
prnt |= green;
if(y==py && x==px)
prnt |= A_STANDOUT;
mvaddch(sy+1+y,sx+x*2+1,prnt);
}
}
}
void fill(char board[size][size]){
byte y,x;
2020-06-20 12:26:54 -04:00
for(y=0;y<size;++y){
for(x=0;x<size;++x){
2019-05-13 09:58:19 -04:00
board[y][x]= int2sgn(y*size+x+1);
}
}
board[size-1][size-1]=' ';
}
void slide_one(char board[size][size],byte y,byte x){
2020-06-20 23:35:03 -04:00
if( (y>=0 && y<size && x>=0 && x<size) && ((abs(y-ey)==1)^(abs(x-ex)==1)) ){
2019-05-13 09:58:19 -04:00
board[ey][ex]=board[y][x];
board[y][x]=' ';
2020-06-20 23:35:03 -04:00
ey=y;//ey/x moves one tile
2019-05-13 09:58:19 -04:00
ex=x;
}
}
void slide_multi(char board[size][size],byte y,byte x){
byte dy,dx;
2020-06-20 23:35:03 -04:00
dy=dx=0;
2019-05-13 09:58:19 -04:00
if( (ey==y) ^ (ex==x) ){
2020-06-20 23:35:03 -04:00
if(ey!=y)//d's are steps from ey/x to y/x
dy=(y-ey >0)? 1:-1;
2019-05-13 09:58:19 -04:00
if(ex!=x)
2020-06-20 23:35:03 -04:00
dx=(x-ex >0)? 1:-1;
while(ex!=x || ey!=y){
2019-05-13 09:58:19 -04:00
slide_one(board,ey+dy,ex+dx);//ey/x comes forth itself
2020-06-20 23:35:03 -04:00
}
2019-05-13 09:58:19 -04:00
ey=y;
ex=x;
}
}
bool issolved(char board[size][size],char check[size][size]){
byte y,x;
2020-06-20 12:26:54 -04:00
for(y=0;y<size;++y){
for(x=0;x<size;++x){
2019-05-13 09:58:19 -04:00
if(board[y][x]!=check[y][x])
return 0;
}
}
return 1;
}
void shuffle(char board[size][size]){
2020-09-12 06:38:45 -04:00
for(int m=0;m<10000;++m){
2019-07-30 14:13:10 -04:00
switch(rand()%4){
2019-05-13 09:58:19 -04:00
case 0:
2020-09-12 06:38:45 -04:00
addch('0');
2019-05-13 09:58:19 -04:00
slide_one(board,ey,ex+1);
break;
case 1:
2020-09-12 06:38:45 -04:00
addch('1');
2019-05-13 09:58:19 -04:00
slide_one(board,ey,ex-1);
break;
case 2:
2020-09-12 06:38:45 -04:00
addch('2');
2019-05-13 09:58:19 -04:00
slide_one(board,ey+1,ex);
break;
case 3:
2020-09-12 06:38:45 -04:00
addch('3');
2019-05-13 09:58:19 -04:00
slide_one(board,ey-1,ex);
2020-09-12 06:38:45 -04:00
break;
2019-05-13 09:58:19 -04:00
}
}
2020-09-12 06:38:45 -04:00
refresh();
getch();
2019-05-13 09:58:19 -04:00
}
//peacefully close when ^C is pressed
void sigint_handler(int x){
endwin();
puts("Quit.");
exit(x);
}
void mouseinput(void){
2020-09-12 06:38:45 -04:00
#ifndef NO_MOUSE
2019-05-13 09:58:19 -04:00
MEVENT minput;
2019-07-30 15:50:57 -04:00
#ifdef PDCURSES
nc_getmouse(&minput);
#else
2019-05-13 09:58:19 -04:00
getmouse(&minput);
2019-07-30 15:50:57 -04:00
#endif
2019-05-13 09:58:19 -04:00
if( minput.y-4<size && minput.x-1<size*2){
py=minput.y-4;
px=(minput.x-1)/2;
}
else
return;
if(minput.bstate & BUTTON1_CLICKED)
ungetch('\n');
2020-09-12 06:38:45 -04:00
#endif
2019-05-13 09:58:19 -04:00
}
void help(void){
2020-05-18 14:59:29 -04:00
erase();
2019-05-13 09:58:19 -04:00
logo(0,0);
2020-05-18 14:59:29 -04:00
attron(A_BOLD);
mvprintw(3,0," **** THE CONTROLS ****");
2019-05-13 09:58:19 -04:00
mvprintw(8,0,"YOU CAN ALSO USE THE MOUSE!");
2020-05-18 14:59:29 -04:00
attroff(A_BOLD);
2019-05-13 09:58:19 -04:00
mvprintw(4,0,"RETURN/ENTER : Slide");
2020-05-18 14:59:29 -04:00
mvprintw(5,0,"hjkl/ARROW KEYS : Move cursor");
mvprintw(6,0,"q : Quit");
2019-05-13 09:58:19 -04:00
mvprintw(7,0,"F1 & F2 : Help on controls & gameplay");
2020-05-18 14:59:29 -04:00
mvprintw(10,0,"Press a key to continue");
2019-05-13 09:58:19 -04:00
refresh();
2020-05-18 14:59:29 -04:00
getch();
2019-05-13 09:58:19 -04:00
erase();
}
void gameplay(void){
2020-05-18 14:59:29 -04:00
erase();
2019-05-13 09:58:19 -04:00
logo(0,0);
2020-05-18 14:59:29 -04:00
attron(A_BOLD);
mvprintw(3,0," **** THE GAMEPLAY ****");
attroff(A_BOLD);
2019-05-13 09:58:19 -04:00
mvprintw(4,0,"Slide the tiles until the numbers and characters are\n");
printw("in the right order.\n");
2020-05-18 14:59:29 -04:00
refresh();
getch();
erase();
2019-05-13 09:58:19 -04:00
}
int main(int argc, char** argv){
2020-09-12 06:38:45 -04:00
#ifndef NO_VLA
2019-05-13 09:58:19 -04:00
size=4;
if(argc==2){
if(!strcmp("help",argv[1])){
2020-05-18 14:59:29 -04:00
printf("Usage: %s [size]\n",argv[0]);
2019-05-13 09:58:19 -04:00
return EXIT_SUCCESS;
}
size=atoi(argv[1]);
if(size<3 || size>7){
fprintf(stderr,"3<=size<=7\n");
return EXIT_FAILURE;
}
}
2020-06-20 12:26:54 -04:00
#endif
2019-05-13 09:58:19 -04:00
signal(SIGINT,sigint_handler);
2019-07-30 14:13:10 -04:00
srand(time(NULL)%UINT_MAX);
2019-05-13 09:58:19 -04:00
initscr();
2020-09-12 06:38:45 -04:00
#ifndef NO_MOUSE
2020-05-18 14:59:29 -04:00
mousemask(ALL_MOUSE_EVENTS,NULL);
2020-09-12 06:38:45 -04:00
#endif
2020-05-18 14:59:29 -04:00
noecho();
cbreak();
keypad(stdscr,1);
if(has_colors()){
start_color();
use_default_colors();
init_pair(1,COLOR_GREEN,-1);
green=COLOR_PAIR(1);
}
char board[size][size];
2019-05-13 09:58:19 -04:00
char check[size][size];
fill(check);
2020-05-18 14:59:29 -04:00
int input;
2019-05-13 09:58:19 -04:00
Start:
py=px=0;
ey=ex=size-1;
curs_set(0);
fill(board);
shuffle(board);
while(1){
erase();
logo(0,0);
draw(3,0,board,check);
refresh();
if(issolved(board,check))
break;
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)
2020-06-20 12:26:54 -04:00
--py;
2019-05-13 09:58:19 -04:00
if( (input=='j' || input==KEY_DOWN) && py<size-1)
2020-06-20 12:26:54 -04:00
++py;
2019-05-13 09:58:19 -04:00
if( (input=='h' || input==KEY_LEFT) && px>0)
2020-06-20 12:26:54 -04:00
--px;
2019-05-13 09:58:19 -04:00
if( (input=='l' || input==KEY_RIGHT) && px<size-1)
2020-06-20 12:26:54 -04:00
++px;
2019-05-13 09:58:19 -04:00
if( input=='q')
sigint_handler(0);
2020-07-10 09:05:08 -04:00
if(input=='\n'||input==KEY_ENTER){
2019-05-13 09:58:19 -04:00
slide_multi(board,py,px);
}
}
mvprintw(size+5,0,"You solved it! Wanna play again?(y/n)");
curs_set(1);
input=getch();
if(input != 'N' && input != 'n' && input != 'q')
goto Start;
endwin();
return EXIT_SUCCESS;
}