From 3c68f39d271e0ad42a50d4a75921fff1c6a1e004 Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 18:02:14 +0200 Subject: [PATCH 01/16] fix stray STX messing with `m', `f', `t' --- mines.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mines.c b/mines.c index 32b33f8..321c529 100644 --- a/mines.c +++ b/mines.c @@ -173,10 +173,10 @@ int minesviiper(void) { case 'g': move_hi (0, g.p[1] ); break; case 'G': move_hi (f.h-1, g.p[1] ); break; case 'z': move_hi (f.h/2, f.w/2); break; - case 'm': set_mark(); break; //TODO: turn off SIGALRM while waiting for key + case 'm': set_mark(); break; case'\'': /* fallthrough */ - case '`': jump_mark(); break; //TODO: turn off SIGALRM while waiting for key - case 'f': find(getch_wrapper(), '>'); break; //TODO: turn off SIGALRM while waiting for key + case '`': jump_mark(); break; + case 'f': find(getch_wrapper(), '>'); break; case 'F': find(getch_wrapper(), '<'); break; case 't': till(getch_wrapper(), '>'); break; case 'T': till(getch_wrapper(), '<'); break; @@ -708,7 +708,9 @@ compatible with the ncurses implementation of same name */ int getch_wrapper (void) { unsigned char mouse[3]; - int c = getch(mouse); + int c; + /*skip over ASCII_STX=0x02 that gets sent when returning from SIGALRM:*/ + while ( (c = getch(mouse)) == 0x02); if (c == CTRSEQ_MOUSE_LEFT || c == CTRSEQ_MOUSE_RIGHT) { if (clicked_emoticon(mouse)) -- 2.39.3 From b42822a0ad9a910fe91f9fdc0fbe56bd216bf8ef Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 18:27:29 +0200 Subject: [PATCH 02/16] -pedantic improvements; less noise in tests --- Makefile | 5 +++-- mines.c | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 9e6b34e..b2611d2 100644 --- a/Makefile +++ b/Makefile @@ -12,11 +12,12 @@ clean: define TESTS echo -e '\033[7mTODOs:\033[0m' - grep -ni --color=always 'xxx\|note\|warn\|todo\|[^:]\/\/' *.c *.h + grep -ni --color=always 'xxx\|todo\|[^:]\/\/' *.c *.h + # grep -ni --color=always 'note\|warn' *.c *.h echo -e '\n\033[7m>80:\033[0m' for myFILE in *.c *.h - do sed 's/\t/ /g' < $$myFILE|grep -En --color=always '.{81}'|sed "s/^/\x1B[35m$$myFILE:/" + do sed 's/\t/ /g' < $$myFILE|grep -En --color=always '.{81}'|sed "s/^/\x1B[35m$$myFILE\x1B[36m:/" done echo -e '\n\033[7m-Wall:\033[0m' diff --git a/mines.c b/mines.c index 321c529..63e3f4c 100644 --- a/mines.c +++ b/mines.c @@ -237,7 +237,7 @@ int wait_mouse_up (int l, int c) { /* TODO: should not take minefield-coords but /* ignore mouse wheel events: */ if (mouse2[0] & 0x40) continue; - else if (mouse2[0]&3 == 3) level--; /* release event */ + else if((mouse2[0]&3) == 3) level--; /* release event */ else level++; /* another button pressed */ } } @@ -422,20 +422,21 @@ void to_next_boundary (int l, int c, char direction) { for (int c = g.p[1]+plusminus; c >= 0 && c < f.w; c+=plusminus) \ if (CONDITION) { \ move_hi (g.p[0], c); \ - return 1; \ + return 1; /* NOTE: break didn't work */ \ } \ + return 0; \ } while(0) int find (int what, char direction) { switch (what) { - case ' ': what = '0'; /* numbers, opened; fallthrough */ + case ' ': what = '0'; /* fallthrough */ case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': + case '6': case '7': case '8': /* numbers, opened */ FIND_WHAT(CELL.o && CELL.n == what-'0', direction); - case 'f': case 'i': FIND_WHAT(CELL.f==FLAG, direction); /* is flagged */ case 'o': FIND_WHAT(CELL.o, direction); /* any opened */ - case '?': FIND_WHAT(CELL.f==QUESM, direction);/* questioned */ case 'c': FIND_WHAT(!CELL.o, direction); /* any closed */ + case 'f': case 'i': FIND_WHAT(CELL.f==FLAG, direction); /* is flagged */ + case '?': FIND_WHAT(CELL.f==QUESM, direction);/* questioned */ } return 0; -- 2.39.3 From fe63823ba6549b07c7480b60bd2b0952687a1a94 Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 18:36:08 +0200 Subject: [PATCH 03/16] find, till, after x --- README.md | 2 +- mines.c | 8 +++++++- mines.h | 6 +++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 10a2915..417d80d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Complete documentation and screenshots can be found on the | `i` | flag / unflag | | `o` | open / chord | | space | modeful, either open or flag | -| `a` | toggle mode for space (open/flag) | +| `e` | toggle mode for space (open/flag) | | `r` | restart game | | Ctrl-L | redraw screen | | `q` | quit | diff --git a/mines.c b/mines.c index 63e3f4c..22a7a06 100644 --- a/mines.c +++ b/mines.c @@ -136,7 +136,7 @@ int minesviiper(void) { if (g.s == MODE_FLAG) goto flag_cell; if (g.s == MODE_QUESM) goto quesm_cell; break; - case 'a': + case 'e': g.s = (g.s+1)%(op.mode+1); show_minefield (g.c?SHOWMINES:NORMAL); break; @@ -180,6 +180,8 @@ int minesviiper(void) { case 'F': find(getch_wrapper(), '<'); break; case 't': till(getch_wrapper(), '>'); break; case 'T': till(getch_wrapper(), '<'); break; + case 'a': after(getch_wrapper(),'>'); break; + case 'A': after(getch_wrapper(),'<'); break; case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; case 'q': return GAME_QUIT; @@ -448,6 +450,10 @@ void till (int what, char direction) { /* if we found what we were looking for move one cell back */ if (find (what, direction)) move_hi(g.p[0], g.p[1]-(direction-'=')); } +void after (int what, char direction) { + /* if we found what we were looking for move one more cell */ + if (find (what, direction)) move_hi(g.p[0], g.p[1]+(direction-'=')); +} char* cell2schema (int l, int c, int mode) { struct minecell cell = f.c[l][c]; diff --git a/mines.h b/mines.h index ac2d78f..d0b20cd 100644 --- a/mines.h +++ b/mines.h @@ -22,9 +22,12 @@ " o: open/choord\n" \ " i: flag/unflag\n" \ " space:modeful cursor (either open or flag)\n" \ - " a: toggle mode for space (open/flag)\n" \ + " e: toggle mode for space (open/flag)\n" \ " mX: set a mark for letter X\n" \ " `X: move to mark X (aliased to ')\n" \ + " f/F x:find forward/backward [012345678 ocf?]\n" \ + " t/T x:'til forward/backward [012345678 ocf?]\n" \ + " a/A x:after forward/backward [012345678 ocf?]\n" \ " r: start a new game\n" \ " q: quit\n" @@ -67,6 +70,7 @@ void move_hi (int, int); void to_next_boundary (int, int, char); int find (int, char); void till (int, char); +void after(int, char); int getch (unsigned char*); int getch_wrapper (void); int getctrlseq (unsigned char*); -- 2.39.3 From 401f3cbefe80cfcbf75e28b0d43bd0616e6fe396 Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 19:08:59 +0200 Subject: [PATCH 04/16] alias fq for f?, macros renamed --- mines.c | 26 +++++++++++++------------- mines.h | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mines.c b/mines.c index 22a7a06..88a3f53 100644 --- a/mines.c +++ b/mines.c @@ -395,7 +395,7 @@ void move_hi (int l, int c) { /* to_next_boundary(): move into the supplied direction until a change in open- state or flag-state is found and move there. falls back to BIG_MOVE. */ -#define FIND_NEXT(X, L, C, L1, C1, MAX, OP) do {\ +#define FIND_BOUND(X, L, C, L1, C1, MAX, OP) do {\ new_ ## X OP ## = BIG_MOVE;\ for (int i = X OP 1; i > 0 && i < f.MAX-1; i OP ## OP)\ if (((f.c[L ][C ].o<<2) + f.c[L ][C ].f) \ @@ -408,18 +408,18 @@ void to_next_boundary (int l, int c, char direction) { int new_l = l; int new_c = c; switch (direction) { - case '>': FIND_NEXT(c, l, i, l, i+1, w, +); break; - case '<': FIND_NEXT(c, l, i, l, i-1, w, -); break; - case '^': FIND_NEXT(l, i, c, i-1, c, h, -); break; - case 'v': FIND_NEXT(l, i, c, i+1, c, h, +); break; + case '>': FIND_BOUND(c, l, i, l, i+1, w, +); break; + case '<': FIND_BOUND(c, l, i, l, i-1, w, -); break; + case '^': FIND_BOUND(l, i, c, i-1, c, h, -); break; + case 'v': FIND_BOUND(l, i, c, i+1, c, h, +); break; } move_hi (new_l, new_c); } -#undef FIND_NEXT +#undef FIND_BOUND #define CELL f.c[g.p[0]][c] -#define FIND_WHAT(CONDITION, DIRECTION) do {\ +#define FIND_NEXT(CONDITION, DIRECTION) do {\ int plusminus = DIRECTION-'='; /* -1 if '<', 1 if '>' */ \ for (int c = g.p[1]+plusminus; c >= 0 && c < f.w; c+=plusminus) \ if (CONDITION) { \ @@ -434,16 +434,16 @@ int find (int what, char direction) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': /* numbers, opened */ - FIND_WHAT(CELL.o && CELL.n == what-'0', direction); - case 'o': FIND_WHAT(CELL.o, direction); /* any opened */ - case 'c': FIND_WHAT(!CELL.o, direction); /* any closed */ - case 'f': case 'i': FIND_WHAT(CELL.f==FLAG, direction); /* is flagged */ - case '?': FIND_WHAT(CELL.f==QUESM, direction);/* questioned */ + FIND_NEXT(CELL.o && CELL.n == what-'0', direction); + case 'o': FIND_NEXT(CELL.o, direction); /* any opened */ + case 'c': FIND_NEXT(!CELL.o, direction); /* any closed */ + case 'f': case 'i': FIND_NEXT(CELL.f==FLAG, direction); /* is flagged */ + case 'q': case '?': FIND_NEXT(CELL.f==QUESM, direction);/* questioned */ } return 0; } -#undef FIND_WHAT +#undef FIND_NEXT #undef CELL void till (int what, char direction) { diff --git a/mines.h b/mines.h index d0b20cd..60a31c0 100644 --- a/mines.h +++ b/mines.h @@ -25,9 +25,9 @@ " e: toggle mode for space (open/flag)\n" \ " mX: set a mark for letter X\n" \ " `X: move to mark X (aliased to ')\n" \ - " f/F x:find forward/backward [012345678 ocf?]\n" \ - " t/T x:'til forward/backward [012345678 ocf?]\n" \ - " a/A x:after forward/backward [012345678 ocf?]\n" \ + " f/F x:find forward/backward [012345678 ocfq]\n" \ + " t/T x:'til -\"-\n" \ + " a/A x:after -\"-\n" \ " r: start a new game\n" \ " q: quit\n" -- 2.39.3 From b97da8afaa4df6c5d60835ecaa5c14278a42a7c6 Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 19:15:12 +0200 Subject: [PATCH 05/16] quit warning --- mines.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mines.c b/mines.c index 88a3f53..4ea10ac 100644 --- a/mines.c +++ b/mines.c @@ -184,7 +184,12 @@ int minesviiper(void) { case 'A': after(getch_wrapper(),'<'); break; case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; - case 'q': return GAME_QUIT; + case 'q': + move_ph (f.h-1+LINE_OFFSET+LINES_AFTER, 0); + printf ("quit game? [Y/n]"); + if (getch_wrapper() != 'n') return GAME_QUIT; + redraw_cell (g.p[0], g.p[1], HIGHLIGHT); + break; case CTRL_'L': screen_setup(1); show_minefield (NORMAL); -- 2.39.3 From 78be6c8a7b0b237d35a3b93b419bc743720fa033 Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 22:13:14 +0200 Subject: [PATCH 06/16] fix -d maxwidth --- mines.c | 2 +- schemes.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mines.c b/mines.c index 4ea10ac..bea6a6c 100644 --- a/mines.c +++ b/mines.c @@ -752,7 +752,7 @@ void clamp_fieldsize (void) { if (f.h < 1) f.h = 1; if (COL_OFFSET + f.w*CW + COL_OFFSET > w.ws_col) - f.w = (w.ws_col - COL_OFFSET - COL_OFFSET)/CW; //TODO: does not work in `-d' (in xterm) + f.w = (w.ws_col - COL_OFFSET - COL_OFFSET)/op.scheme->display_width; if (LINE_OFFSET + f.h + LINES_AFTER > w.ws_row) f.h = w.ws_row - (LINE_OFFSET+LINES_AFTER); if (COL_OFFSET + f.w*CW > MOUSE_MAX) diff --git a/schemes.h b/schemes.h index e9c7370..435ce45 100644 --- a/schemes.h +++ b/schemes.h @@ -54,6 +54,7 @@ struct minescheme { char* border[5][3]; int cell_width; + int display_width; char* init_seq; char* reset_seq; }; @@ -77,6 +78,7 @@ struct minescheme symbols_mono = { {"╚═","══","═╝"}}, .cell_width = 2, + .display_width = 2, }; struct minescheme symbols_col1 = { @@ -106,6 +108,7 @@ struct minescheme symbols_col1 = { {"╚═","══","═╝"}}, .cell_width = 2, + .display_width = 2, }; struct minescheme symbols_doublewidth = { @@ -140,6 +143,7 @@ struct minescheme symbols_doublewidth = { {"\033#6\x6d","\x71","\x6a"}}, .cell_width = 1, + .display_width = 2, .init_seq = "\033P0;1;0;4;1;1{P" /*config for DRCS "P": 7x10,erase-all*/ "??~^^^^/??N????\033\\" /* flag at '!' resembling ▕▀ */ "\033(0\033*B\033+P" /* G0=Graphics,G2=ASCII,G3="P" */ -- 2.39.3 From f3dd162304975b0feec45f4ddbc112b6155304da Mon Sep 17 00:00:00 2001 From: girst Date: Sun, 20 May 2018 22:25:33 +0200 Subject: [PATCH 07/16] less noisey `make test' --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b2611d2..5404dc2 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ define TESTS echo -e '\n\033[7m>80:\033[0m' for myFILE in *.c *.h - do sed 's/\t/ /g' < $$myFILE|grep -En --color=always '.{81}'|sed "s/^/\x1B[35m$$myFILE\x1B[36m:/" + do sed 's/\t/ /g' < $$myFILE|sed 's|//.*$$||'|grep -En --color=always '.{81}'|sed "s/^/\x1B[35m$$myFILE\x1B[36m:/" done echo -e '\n\033[7m-Wall:\033[0m' -- 2.39.3 From bc98e4af411b64026d9a6e90408f9d260c6f0d85 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 24 May 2018 11:41:18 +0200 Subject: [PATCH 08/16] clear status line after dismissing quit dialog --- mines.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mines.c b/mines.c index bea6a6c..d4f0b68 100644 --- a/mines.c +++ b/mines.c @@ -188,6 +188,8 @@ int minesviiper(void) { move_ph (f.h-1+LINE_OFFSET+LINES_AFTER, 0); printf ("quit game? [Y/n]"); if (getch_wrapper() != 'n') return GAME_QUIT; + move_ph (f.h-1+LINE_OFFSET+LINES_AFTER, 0); + printf("\033[2K"); fflush(stdout); /* clear line */ redraw_cell (g.p[0], g.p[1], HIGHLIGHT); break; case CTRL_'L': -- 2.39.3 From 847ed8b7df324125953856e7692d79e19542bb8a Mon Sep 17 00:00:00 2001 From: girst Date: Wed, 24 Oct 2018 16:07:32 +0200 Subject: [PATCH 09/16] on win: show all flags the original minesweeper sets all mines to flags when won. this also helps distinguishing wins from losses (that previously only differed in emoticon) --- mines.c | 11 ++++++++--- mines.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mines.c b/mines.c index d4f0b68..c0edcbb 100644 --- a/mines.c +++ b/mines.c @@ -101,7 +101,8 @@ newgame: } timer_setup(0); /* stop timer */ - show_minefield (SHOWMINES); + int show_how = g.o==GAME_WON?SHOWFLAGS:SHOWMINES; + show_minefield (show_how); for(;;) { switch(getch_wrapper()) { case WRAPPER_EMOTICON: @@ -109,7 +110,7 @@ newgame: case 'q': goto quit; case CTRL_'L': //TODO: updates the timer (fix in show_minefield()) screen_setup(1); - show_minefield (SHOWMINES); + show_minefield (show_how); break; case CTRL_'R': interactive_resize(); @@ -472,7 +473,11 @@ char* cell2schema (int l, int c, int mode) { cell.m == DEATH_MINE ? op.scheme->mine_death: cell.o == CLOSED ? op.scheme->field_closed: /*.......................*/ op.scheme->number[f.c[l][c].n]); - else return ( + else if (mode == SHOWFLAGS) return ( + /* on win (everything opened, only correct flags left) */ + cell.m == STD_MINE ? op.scheme->field_flagged: + /*.......................*/ op.scheme->number[f.c[l][c].n]); + else return ( cell.f == FLAG ? op.scheme->field_flagged: cell.f == QUESM ? op.scheme->field_question: cell.o == CLOSED ? op.scheme->field_closed: diff --git a/mines.h b/mines.h index 60a31c0..95506c9 100644 --- a/mines.h +++ b/mines.h @@ -110,6 +110,7 @@ enum modes { NORMAL, REDUCED, SHOWMINES, + SHOWFLAGS, HIGHLIGHT, RESIZEMODE, }; -- 2.39.3 From 0dbac4e95fc1bc8e4649363d44d56d6177bb5689 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 08:47:55 +0200 Subject: [PATCH 10/16] first draft of ex mode / colon commands --- mines.c | 39 +++++++++++++++++++++++++++++++++++---- mines.h | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/mines.c b/mines.c index c0edcbb..4911f16 100644 --- a/mines.c +++ b/mines.c @@ -1,5 +1,5 @@ /******************************************************************************* - minesviiper 0.4 + minesviiper 0.5 By Tobias Girstmair, 2015 - 2018 ./minesviiper 16x16x40 @@ -47,6 +47,7 @@ #define BORDER(l, c) op.scheme->border[B_ ## l][B_ ## c] #define CW op.scheme->cell_width /* for brevity */ #define HI_CELL f.c[g.p[0]][g.p[1]] +#define LINE_BELOW LINE_OFFSET+f.h-1+LINES_AFTER #define CTRL_ 0x1F & #define AR_CELL f.c[ROW][COL] /* helper for AROUND() */ @@ -55,6 +56,9 @@ for (int COL = MAX(c-1, 0); COL <= MIN(c+1, f.w-1); COL++) \ if (!(ROW == l && COL == c)) /* skip itself */ +#define PAUSE_TIMER \ + for (int _break=(timer_setup(0),1); _break; _break=0, timer_setup(g.t)) + struct minefield f; struct game g; struct opt op; @@ -185,11 +189,20 @@ int minesviiper(void) { case 'A': after(getch_wrapper(),'<'); break; case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; - case 'q': - move_ph (f.h-1+LINE_OFFSET+LINES_AFTER, 0); + case ':': + switch (ex_cmd()) { + case 'q': return GAME_QUIT; + default: + fprintf (stdout, "\rinvalid command"); //stderr does not work? + PAUSE_TIMER ungetc(getchar(), stdin); + printf("\033[2K"); //fflush(stdout);/*clear line*/ + } + break; + case 'q': //TODO: redefine `q' as macro functionality + move_ph (LINE_BELOW, 0); printf ("quit game? [Y/n]"); if (getch_wrapper() != 'n') return GAME_QUIT; - move_ph (f.h-1+LINE_OFFSET+LINES_AFTER, 0); + move_ph (LINE_BELOW, 0); printf("\033[2K"); fflush(stdout); /* clear line */ redraw_cell (g.p[0], g.p[1], HIGHLIGHT); break; @@ -343,6 +356,24 @@ int do_uncover (int* is_newgame, int actor) { return GAME_INPROGRESS; } +int ex_cmd(void) { + //TODO:currently returns the first letter entered, but should in the future return an enum value + char what[256]; + timer_setup(0); /* timer spams ASCII STX (0x02) chars -- NOTE: maybe also 0xff? */ + PAUSE_TIMER { + move_ph(LINE_BELOW, 0); + putchar(':'); /* prompt */ + + raw_mode(0); /* use cooked mode, so we get line editing for free */ + scanf(" %s", what); //TODO: cancel on ^G, ESC, ^C, ... + getchar();//get 0x10 char left in buffer by scanf + raw_mode(1); + + move_ph(LINE_BELOW, 0); + printf ("\033[0J"); //clear from here to the end of the screen + } + return what[0]; +} void set_mark(void) { int mark = tolower(getch_wrapper()); if (mark < 'a' || mark > 'z') return; /*out of bound*/ diff --git a/mines.h b/mines.h index 95506c9..4f4a7d0 100644 --- a/mines.h +++ b/mines.h @@ -86,6 +86,7 @@ void flag_square (int, int); void quesm_square (int, int); int choord_square (int, int); int do_uncover (int*, int); +int ex_cmd(void); void set_mark(void); void jump_mark(void); void interactive_resize(void); -- 2.39.3 From c96d15f2d86309def08218c674ab4cef3c3c39cf Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 11:36:58 +0200 Subject: [PATCH 11/16] clean up ex mode --- mines.c | 40 +++++++++++++++++++++------------------- mines.h | 31 +++++++++++++++++++------------ 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/mines.c b/mines.c index 4911f16..e84812c 100644 --- a/mines.c +++ b/mines.c @@ -82,7 +82,7 @@ int main (int argc, char** argv) { case 'd': op.scheme = &symbols_doublewidth; break; case 'h': default: - fprintf (stderr, SHORTHELP LONGHELP, argv[0]); + fprintf (stderr, SHORTHELP LONGHELP KEYHELP, argv[0]); return !(optget=='h'); } } if (optind < argc) { /* parse Fieldspec */ @@ -141,7 +141,7 @@ int minesviiper(void) { if (g.s == MODE_FLAG) goto flag_cell; if (g.s == MODE_QUESM) goto quesm_cell; break; - case 'e': + case 'e': //TODO: e should be endword; use 's'? g.s = (g.s+1)%(op.mode+1); show_minefield (g.c?SHOWMINES:NORMAL); break; @@ -191,20 +191,17 @@ int minesviiper(void) { case 'r': timer_setup(0); return GAME_NEW; case ':': switch (ex_cmd()) { - case 'q': return GAME_QUIT; + case EX_QUIT: return GAME_QUIT; + case EX_HELP: + fprintf (stdout, KEYHELP); + break; default: - fprintf (stdout, "\rinvalid command"); //stderr does not work? + printf ("\rinvalid command"); PAUSE_TIMER ungetc(getchar(), stdin); - printf("\033[2K"); //fflush(stdout);/*clear line*/ + printf("\033[2K"); /* clear line */ } break; case 'q': //TODO: redefine `q' as macro functionality - move_ph (LINE_BELOW, 0); - printf ("quit game? [Y/n]"); - if (getch_wrapper() != 'n') return GAME_QUIT; - move_ph (LINE_BELOW, 0); - printf("\033[2K"); fflush(stdout); /* clear line */ - redraw_cell (g.p[0], g.p[1], HIGHLIGHT); break; case CTRL_'L': screen_setup(1); @@ -240,7 +237,7 @@ int everything_opened (void) { return 1; } -int wait_mouse_up (int l, int c) { /* TODO: should not take minefield-coords but absolute ones */ +int wait_mouse_up (int l, int c) { unsigned char mouse2[3]; int level = 1; int l2, c2; @@ -357,22 +354,27 @@ int do_uncover (int* is_newgame, int actor) { } int ex_cmd(void) { - //TODO:currently returns the first letter entered, but should in the future return an enum value char what[256]; - timer_setup(0); /* timer spams ASCII STX (0x02) chars -- NOTE: maybe also 0xff? */ - PAUSE_TIMER { + printf ("\033[?9l\033[?25h"); /* disable mouse, show cursor */ + PAUSE_TIMER { /* timer spams ASCII STX (0x02) chars */ move_ph(LINE_BELOW, 0); putchar(':'); /* prompt */ - raw_mode(0); /* use cooked mode, so we get line editing for free */ + raw_mode(0);/*use cooked mode, so we get line editing for free*/ scanf(" %s", what); //TODO: cancel on ^G, ESC, ^C, ... - getchar();//get 0x10 char left in buffer by scanf + getchar(); /* discard 0x10 char left in buffer by scanf */ raw_mode(1); move_ph(LINE_BELOW, 0); - printf ("\033[0J"); //clear from here to the end of the screen + printf ("\033[0J"); /* clear to the end of the screen */ + } + printf ("\033[?1000h\033[?25l"); /* enable mouse, hide cursor */ + + switch (what[0]) { //TODO: urgh. + case 'q': return EX_QUIT; + case 'h': return EX_HELP; + default: return EX_INVALID; } - return what[0]; } void set_mark(void) { int mark = tolower(getch_wrapper()); diff --git a/mines.h b/mines.h index 4f4a7d0..8e61131 100644 --- a/mines.h +++ b/mines.h @@ -13,23 +13,25 @@ "FIELDSPEC:\n" \ " WxH[xM] (width 'x' height 'x' mines)\n" \ " defaults to 30x16x99; mines default to ~20%%\n" \ - "\n" \ + "\n" +#define KEYHELP \ "Keybindings:\n" \ - " hjkl: move left/down/up/right\n" \ - " bduw: move to next boundary\n" \ - " ^Gg$: move to the left/bottom/top/right\n" \ - " z: center cursor on minefield\n" \ - " o: open/choord\n" \ - " i: flag/unflag\n" \ + " hjkl :move left/down/up/right\n" \ + " bduw :move to next boundary\n" \ + " ^Gg$ :move to the left/bottom/top/right\n" \ + " z :center cursor on minefield\n" \ + " o :open/choord\n" \ + " i :flag/unflag\n" \ " space:modeful cursor (either open or flag)\n" \ - " e: toggle mode for space (open/flag)\n" \ - " mX: set a mark for letter X\n" \ - " `X: move to mark X (aliased to ')\n" \ + " e :toggle mode for space (open/flag)\n" \ + " mX :set a mark for letter X\n" \ + " `X :move to mark X (aliased to ')\n" \ " f/F x:find forward/backward [012345678 ocfq]\n" \ " t/T x:'til -\"-\n" \ " a/A x:after -\"-\n" \ - " r: start a new game\n" \ - " q: quit\n" + " r :start a new game\n" \ + " :h :help\n" \ + " :q :quit\n" struct minefield { struct minecell { @@ -157,6 +159,11 @@ enum actor { KEYBOARD, MOUSE, }; +enum colon { + EX_INVALID, + EX_QUIT, + EX_HELP, +}; enum mine_types { NO_MINE, STD_MINE, -- 2.39.3 From 7bcba7f4830631dc194459c03faadcb01324b34f Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 15:00:02 +0200 Subject: [PATCH 12/16] resize mode and ex mode improvements, backword also some minor refactoring --- mines.c | 57 ++++++++++++++++++++++++++++++++++----------------------- mines.h | 4 +++- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/mines.c b/mines.c index e84812c..3fa81f4 100644 --- a/mines.c +++ b/mines.c @@ -46,6 +46,7 @@ #define EMOT(e) op.scheme->emoticons[EMOT_ ## e] #define BORDER(l, c) op.scheme->border[B_ ## l][B_ ## c] #define CW op.scheme->cell_width /* for brevity */ +#define DW op.scheme->display_width /* ditto. */ #define HI_CELL f.c[g.p[0]][g.p[1]] #define LINE_BELOW LINE_OFFSET+f.h-1+LINES_AFTER #define CTRL_ 0x1F & @@ -93,10 +94,10 @@ int main (int argc, char** argv) { } signal_setup(); - screen_setup(1); atexit (*quit); newgame: + screen_setup(1); switch (minesviiper()) { case GAME_NEW: goto newgame; case GAME_WON: g.o = GAME_WON; break; @@ -141,7 +142,7 @@ int minesviiper(void) { if (g.s == MODE_FLAG) goto flag_cell; if (g.s == MODE_QUESM) goto quesm_cell; break; - case 'e': //TODO: e should be endword; use 's'? + case 's': g.s = (g.s+1)%(op.mode+1); show_minefield (g.c?SHOWMINES:NORMAL); break; @@ -172,12 +173,14 @@ int minesviiper(void) { case 'b': to_next_boundary (g.p[0], g.p[1], '<'); break; case 'u': to_next_boundary (g.p[0], g.p[1], '^'); break; case 'd': to_next_boundary (g.p[0], g.p[1], 'v'); break; + case 'e': to_next_boundary (g.p[0], g.p[1], '>'); + move_hi(g.p[0],g.p[1]-1); break; /* endword */ case '0': /* fallthrough */ - case '^': move_hi (g.p[0], 0 ); break; - case '$': move_hi (g.p[0], f.w-1 ); break; - case 'g': move_hi (0, g.p[1] ); break; - case 'G': move_hi (f.h-1, g.p[1] ); break; - case 'z': move_hi (f.h/2, f.w/2); break; + case '^': move_hi (g.p[0], 0 ); break; + case '$': move_hi (g.p[0], f.w-1 ); break; + case 'g': move_hi (0, g.p[1]); break; + case 'G': move_hi (f.h-1, g.p[1]); break; + case 'z': move_hi (f.h/2, f.w/2 ); break; case 'm': set_mark(); break; case'\'': /* fallthrough */ case '`': jump_mark(); break; @@ -187,14 +190,26 @@ int minesviiper(void) { case 'T': till(getch_wrapper(), '<'); break; case 'a': after(getch_wrapper(),'>'); break; case 'A': after(getch_wrapper(),'<'); break; +#if 0 + case 'H': /* left*/ //TODO + case 'J': /* down*/ + case 'K': /* up*/ + case 'L': /* right*/ + case CTRL_'H': /* topright*/ + case CTRL_'J': /* bottomright*/ + case CTRL_'K': /* bottomleft*/ + case CTRL_'L': /* topleft*/ break; +#endif case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; case ':': switch (ex_cmd()) { case EX_QUIT: return GAME_QUIT; - case EX_HELP: - fprintf (stdout, KEYHELP); - break; + case EX_HELP: printf (KEYHELP); break; + case EX_RESZ: + timer_setup(0); + interactive_resize(); + return GAME_NEW; default: printf ("\rinvalid command"); PAUSE_TIMER ungetc(getchar(), stdin); @@ -207,10 +222,6 @@ int minesviiper(void) { screen_setup(1); show_minefield (NORMAL); break; - case CTRL_'R': - timer_setup(0); - interactive_resize(); - return GAME_NEW; case '\\': if (g.n == GAME_NEW) break; /* must open a cell first */ g.c = !g.c; @@ -361,8 +372,7 @@ int ex_cmd(void) { putchar(':'); /* prompt */ raw_mode(0);/*use cooked mode, so we get line editing for free*/ - scanf(" %s", what); //TODO: cancel on ^G, ESC, ^C, ... - getchar(); /* discard 0x10 char left in buffer by scanf */ + fgets(what, 256, stdin); //TODO: cancel on ^G, ESC, ^C, ... raw_mode(1); move_ph(LINE_BELOW, 0); @@ -373,6 +383,7 @@ int ex_cmd(void) { switch (what[0]) { //TODO: urgh. case 'q': return EX_QUIT; case 'h': return EX_HELP; + case 'r': return EX_RESZ; default: return EX_INVALID; } } @@ -551,10 +562,7 @@ void show_minefield (int mode) { print_border(TOP, f.w); print_line(STATUS) { - if (mode == RESIZEMODE) printf ("%-*s", 2*half_spaces, - f.w*CW>53?"Resize Mode: HJKL to resize, Enter to set, Q to abort": - f.w*CW>25?"Resize Mode: HJKL/Enter/Q":"HJKL/Enter/Q"); - else printf("[%03d%c]%*s%s%*s[%03d]", + printf("[%03d%c]%*s%s%*s[%03d]", /* [ */ f.m - g.f, modechar[g.s], /* ] */ left_spaces,"", get_emoticon(), right_spaces,"", /* [ */ dtime /* ] */); @@ -619,6 +627,8 @@ void interactive_resize(void) { /* show the new field size in the corner: */ move_ph(f.h+LINE_OFFSET-1,COL_OFFSET); printf("%d x %d", f.w, f.h); + move_ph(LINE_BELOW, 0); + printf("Resize Mode: Enter to set, Q to abort"); free_field(); /* must free before resizing! */ switch (getctrlseq(buf)) { @@ -788,11 +798,12 @@ void clamp_fieldsize (void) { struct winsize w; ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - if (f.w < 1) f.w = 1; - if (f.h < 1) f.h = 1; + /* seven is the minimum width of the status bar */ + if (f.w < 7) f.w = 7; + if (f.h < 7) f.h = 7; if (COL_OFFSET + f.w*CW + COL_OFFSET > w.ws_col) - f.w = (w.ws_col - COL_OFFSET - COL_OFFSET)/op.scheme->display_width; + f.w = (w.ws_col - COL_OFFSET - COL_OFFSET)/DW; if (LINE_OFFSET + f.h + LINES_AFTER > w.ws_row) f.h = w.ws_row - (LINE_OFFSET+LINES_AFTER); if (COL_OFFSET + f.w*CW > MOUSE_MAX) diff --git a/mines.h b/mines.h index 8e61131..83a1e80 100644 --- a/mines.h +++ b/mines.h @@ -23,7 +23,7 @@ " o :open/choord\n" \ " i :flag/unflag\n" \ " space:modeful cursor (either open or flag)\n" \ - " e :toggle mode for space (open/flag)\n" \ + " s :toggle mode for space (open/flag)\n" \ " mX :set a mark for letter X\n" \ " `X :move to mark X (aliased to ')\n" \ " f/F x:find forward/backward [012345678 ocfq]\n" \ @@ -31,6 +31,7 @@ " a/A x:after -\"-\n" \ " r :start a new game\n" \ " :h :help\n" \ + " :r :resize\n" \ " :q :quit\n" struct minefield { @@ -163,6 +164,7 @@ enum colon { EX_INVALID, EX_QUIT, EX_HELP, + EX_RESZ, }; enum mine_types { NO_MINE, -- 2.39.3 From 7a52fb1f7d874f3ead75cefe93f299635f9ca9aa Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 15:05:36 +0200 Subject: [PATCH 13/16] simplify find/'til/after, backword --- mines.c | 40 +++++++++++++++------------------------- mines.h | 6 ++---- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/mines.c b/mines.c index 3fa81f4..a10f1f5 100644 --- a/mines.c +++ b/mines.c @@ -169,12 +169,11 @@ int minesviiper(void) { case 'k': move_hi (g.p[0]-1, g.p[1] ); break; case CTRSEQ_CURSOR_RIGHT: case 'l': move_hi (g.p[0], g.p[1]+1); break; - case 'w': to_next_boundary (g.p[0], g.p[1], '>'); break; - case 'b': to_next_boundary (g.p[0], g.p[1], '<'); break; - case 'u': to_next_boundary (g.p[0], g.p[1], '^'); break; - case 'd': to_next_boundary (g.p[0], g.p[1], 'v'); break; - case 'e': to_next_boundary (g.p[0], g.p[1], '>'); - move_hi(g.p[0],g.p[1]-1); break; /* endword */ + case 'w': to_next_boundary (g.p[0], g.p[1], '>', 1); break; + case 'b': to_next_boundary (g.p[0], g.p[1], '<', 1); break; + case 'u': to_next_boundary (g.p[0], g.p[1], '^', 1); break; + case 'd': to_next_boundary (g.p[0], g.p[1], 'v', 1); break; + case 'e': to_next_boundary (g.p[0], g.p[1], '>', 0); break; case '0': /* fallthrough */ case '^': move_hi (g.p[0], 0 ); break; case '$': move_hi (g.p[0], f.w-1 ); break; @@ -184,12 +183,12 @@ int minesviiper(void) { case 'm': set_mark(); break; case'\'': /* fallthrough */ case '`': jump_mark(); break; - case 'f': find(getch_wrapper(), '>'); break; - case 'F': find(getch_wrapper(), '<'); break; - case 't': till(getch_wrapper(), '>'); break; - case 'T': till(getch_wrapper(), '<'); break; - case 'a': after(getch_wrapper(),'>'); break; - case 'A': after(getch_wrapper(),'<'); break; + case 'f': find(getch_wrapper(), '>', 0); break; + case 'F': find(getch_wrapper(), '<', 0); break; + case 't': find(getch_wrapper(), '>',-1); break; + case 'T': find(getch_wrapper(), '<',-1); break; + case 'a': find(getch_wrapper(), '>',+1); break; + case 'A': find(getch_wrapper(), '<',+1); break; #if 0 case 'H': /* left*/ //TODO case 'J': /* down*/ @@ -452,11 +451,11 @@ state or flag-state is found and move there. falls back to BIG_MOVE. */ for (int i = X OP 1; i > 0 && i < f.MAX-1; i OP ## OP)\ if (((f.c[L ][C ].o<<2) + f.c[L ][C ].f) \ != ((f.c[L1][C1].o<<2) + f.c[L1][C1].f)) {\ - new_ ## X = i OP 1;\ + new_ ## X = i OP advance;\ break;\ }\ } while(0) -void to_next_boundary (int l, int c, char direction) { +void to_next_boundary (int l, int c, char direction, int advance) { int new_l = l; int new_c = c; switch (direction) { @@ -475,12 +474,12 @@ void to_next_boundary (int l, int c, char direction) { int plusminus = DIRECTION-'='; /* -1 if '<', 1 if '>' */ \ for (int c = g.p[1]+plusminus; c >= 0 && c < f.w; c+=plusminus) \ if (CONDITION) { \ - move_hi (g.p[0], c); \ + move_hi (g.p[0], c+(till_after*plusminus)); \ return 1; /* NOTE: break didn't work */ \ } \ return 0; \ } while(0) -int find (int what, char direction) { +int find (int what, char direction, int till_after) { switch (what) { case ' ': what = '0'; /* fallthrough */ case '0': case '1': case '2': @@ -498,15 +497,6 @@ int find (int what, char direction) { #undef FIND_NEXT #undef CELL -void till (int what, char direction) { - /* if we found what we were looking for move one cell back */ - if (find (what, direction)) move_hi(g.p[0], g.p[1]-(direction-'=')); -} -void after (int what, char direction) { - /* if we found what we were looking for move one more cell */ - if (find (what, direction)) move_hi(g.p[0], g.p[1]+(direction-'=')); -} - char* cell2schema (int l, int c, int mode) { struct minecell cell = f.c[l][c]; diff --git a/mines.h b/mines.h index 83a1e80..5917bc2 100644 --- a/mines.h +++ b/mines.h @@ -70,10 +70,8 @@ int minesviiper(void); void fill_minefield (int, int); void move_ph (int, int); void move_hi (int, int); -void to_next_boundary (int, int, char); -int find (int, char); -void till (int, char); -void after(int, char); +void to_next_boundary (int, int, char, int); +int find (int, char, int); int getch (unsigned char*); int getch_wrapper (void); int getctrlseq (unsigned char*); -- 2.39.3 From 38892e011125a54ee12fc7d6b157de72968fdd91 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 15:29:11 +0200 Subject: [PATCH 14/16] minor refactoring cannot reproduce "in `-d' mode if f.w is odd we are 1 char short in the status line" --- mines.c | 27 +++++++++------------------ mines.h | 5 +++-- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/mines.c b/mines.c index a10f1f5..2b0a6a4 100644 --- a/mines.c +++ b/mines.c @@ -74,11 +74,12 @@ int main (int argc, char** argv) { int optget; opterr = 0; /* don't print message on unrecognized option */ - while ((optget = getopt (argc, argv, "+hnfqcdx")) != -1) { + while ((optget = getopt (argc, argv, "+hnfqbcd")) != -1) { switch (optget) { case 'n': op.mode = NOFLAG; break; case 'f': op.mode = FLAG; break; /*default*/ case 'q': op.mode = QUESM; break; /*WARN:implicitly sets -f*/ + case 'b': op.scheme = &symbols_mono; break; case 'c': op.scheme = &symbols_col1; break; case 'd': op.scheme = &symbols_doublewidth; break; case 'h': @@ -98,13 +99,14 @@ int main (int argc, char** argv) { newgame: screen_setup(1); - switch (minesviiper()) { + switch (g.o = minesviiper()) { case GAME_NEW: goto newgame; - case GAME_WON: g.o = GAME_WON; break; - case GAME_LOST:g.o = GAME_LOST;break; + case GAME_WON: goto game_end; + case GAME_LOST:goto game_end; case GAME_QUIT:goto quit; } +game_end: timer_setup(0); /* stop timer */ int show_how = g.o==GAME_WON?SHOWFLAGS:SHOWMINES; show_minefield (show_how); @@ -113,7 +115,8 @@ newgame: case WRAPPER_EMOTICON: case 'r': goto newgame; case 'q': goto quit; - case CTRL_'L': //TODO: updates the timer (fix in show_minefield()) + case CTRL_'L': + /*WARN: updates the timer (would require fix in struct*/ screen_setup(1); show_minefield (show_how); break; @@ -189,16 +192,6 @@ int minesviiper(void) { case 'T': find(getch_wrapper(), '<',-1); break; case 'a': find(getch_wrapper(), '>',+1); break; case 'A': find(getch_wrapper(), '<',+1); break; -#if 0 - case 'H': /* left*/ //TODO - case 'J': /* down*/ - case 'K': /* up*/ - case 'L': /* right*/ - case CTRL_'H': /* topright*/ - case CTRL_'J': /* bottomright*/ - case CTRL_'K': /* bottomleft*/ - case CTRL_'L': /* topleft*/ break; -#endif case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; case ':': @@ -540,8 +533,6 @@ char* get_emoticon(void) { #define print_border(which, width) \ print_line(which) printm (width, BORDER(which,MIDDLE)) void show_minefield (int mode) { - //TODO: in `-d' mode if f.w is odd we are 1 char short in the status line - //TODO: in `-d' mode we need to specify a charset to print lowercase (-> resize mode) int dtime = difftime (time(NULL), g.t)*!!g.t; int half_spaces = f.w*op.scheme->cell_width/2; int left_spaces = MAX(0,half_spaces-7-(f.m-g.f>999)); @@ -572,7 +563,6 @@ void show_stomp (int enable, int l, int c) { if (AR_CELL.o == CLOSED && AR_CELL.f != FLAG) redraw_cell (ROW, COL, HIGHLIGHT); fflush(stdout); /* won't display without */ - } } else { AROUND(l, c) redraw_cell (ROW, COL, g.o?SHOWMINES:NORMAL); @@ -619,6 +609,7 @@ void interactive_resize(void) { printf("%d x %d", f.w, f.h); move_ph(LINE_BELOW, 0); printf("Resize Mode: Enter to set, Q to abort"); + //TODO: need escape seq. to print lowercase in `-d' mode! free_field(); /* must free before resizing! */ switch (getctrlseq(buf)) { diff --git a/mines.h b/mines.h index 5917bc2..4aca95b 100644 --- a/mines.h +++ b/mines.h @@ -7,8 +7,9 @@ "OPTIONS:\n" \ " -n(o flagging)\n" \ " -f(lagging)\n" \ - " -q(uestion marks)\n" \ - " -c(olored symbols)\n" \ + " -q(uestion marks; implies -f)\n" \ + " -b(land symbols)\n" \ + " -c(olorful symbols)\n" \ " -d(ec charset symbols)\n" \ "FIELDSPEC:\n" \ " WxH[xM] (width 'x' height 'x' mines)\n" \ -- 2.39.3 From 71e521ebaa665595eb0472ab5d1f948dca3bf327 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 25 Oct 2018 15:35:19 +0200 Subject: [PATCH 15/16] update readme keybindings --- README.md | 11 +++++++---- mines.c | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 417d80d..4501c22 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,12 @@ Complete documentation and screenshots can be found on the | `i` | flag / unflag | | `o` | open / chord | | space | modeful, either open or flag | -| `e` | toggle mode for space (open/flag) | +| `s` | toggle mode for space (open/flag) | | `r` | restart game | | Ctrl-L | redraw screen | -| `q` | quit | +| `:h` | show keybindings (Ctrl-L to hide) | +| `:r` | resize playfield | +| `:q` | quit | Use the left mouse button to open or chord a cell, and the right button to flag. @@ -36,8 +38,9 @@ A new game can be started by clicking on the `:D` icon. | `-n` | disable flagging | | `-f` | enable flagging (default) | | `-q` | enable question marks | -| `-c` | switch to the colored scheme | -| `-d` | switch to the DEC charset scheme | +| `-b` | use the bland (monospace) scheme (default) | +| `-c` | use the colored scheme | +| `-d` | use the DEC charset scheme | | *W*`x`*H*`x`*M* | Fieldspec, width \* height \* number of mines | ## Character Schemes diff --git a/mines.c b/mines.c index 2b0a6a4..14018f1 100644 --- a/mines.c +++ b/mines.c @@ -192,6 +192,7 @@ int minesviiper(void) { case 'T': find(getch_wrapper(), '<',-1); break; case 'a': find(getch_wrapper(), '>',+1); break; case 'A': find(getch_wrapper(), '<',+1); break; + //TODO: HJKL, ^H^J^K^L: up/down/left/right/45deg case WRAPPER_EMOTICON: case 'r': timer_setup(0); return GAME_NEW; case ':': -- 2.39.3 From 115acbee60c8dbd7e01e7cd2421af3ae98149362 Mon Sep 17 00:00:00 2001 From: girst Date: Thu, 1 Nov 2018 16:39:26 +0100 Subject: [PATCH 16/16] 'p': stomp adjacent stopgap feature for HJKL/^H^J^K^L; does the common action of choording around a cell after flagging it --- README.md | 1 + mines.c | 13 +++++++++++-- mines.h | 2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4501c22..c9481fa 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Complete documentation and screenshots can be found on the | `^`/`G`/`g`/`$` | move to the very left / bottom / top / right | | `i` | flag / unflag | | `o` | open / chord | +| `p` | chord all open adjacent cells | | space | modeful, either open or flag | | `s` | toggle mode for space (open/flag) | | `r` | restart game | diff --git a/mines.c b/mines.c index 14018f1..8cd384f 100644 --- a/mines.c +++ b/mines.c @@ -162,6 +162,7 @@ int minesviiper(void) { flag_cell: case CTRSEQ_MOUSE_RIGHT: case 'i': flag_square (g.p[0], g.p[1]); break; + case 'p':if(choord_around(g.p[0],g.p[1]))return GAME_LOST;break; quesm_cell: case '?':quesm_square (g.p[0], g.p[1]); break; case CTRSEQ_CURSOR_LEFT: @@ -278,7 +279,6 @@ int wait_mouse_up (int l, int c) { } int choord_square (int line, int col) { - if (uncover_square (line, col)) return 1; AROUND(line,col) if (AR_CELL.f != FLAG) { if (uncover_square (ROW, COL)) @@ -288,6 +288,15 @@ int choord_square (int line, int col) { return 0; } +int choord_around(int row, int col) { + AROUND(g.p[0], g.p[1]) { + if (AR_CELL.o == OPENED && get_neighbours (ROW, COL, 1) == 0) { + if (choord_square (ROW, COL)) return GAME_LOST; + } + } + return GAME_INPROGRESS; +} + int uncover_square (int l, int c) { if (f.c[l][c].o == OPENED) return 0; /* nothing to do */ @@ -340,7 +349,7 @@ int do_uncover (int* is_newgame, int actor) { timer_setup(1); } - if (HI_CELL.f == FLAG ) return GAME_INPROGRESS; + if (HI_CELL.f == FLAG ) return GAME_INPROGRESS; //TODO: could choord? if (HI_CELL.o == CLOSED) { if (uncover_square (g.p[0], g.p[1])) return GAME_LOST; } else if (get_neighbours (g.p[0], g.p[1], 1) == 0) { diff --git a/mines.h b/mines.h index 4aca95b..cc9924e 100644 --- a/mines.h +++ b/mines.h @@ -23,6 +23,7 @@ " z :center cursor on minefield\n" \ " o :open/choord\n" \ " i :flag/unflag\n" \ + " p :choord around\n" \ " space:modeful cursor (either open or flag)\n" \ " s :toggle mode for space (open/flag)\n" \ " mX :set a mark for letter X\n" \ @@ -87,6 +88,7 @@ int uncover_square (int, int); void flag_square (int, int); void quesm_square (int, int); int choord_square (int, int); +int choord_around(int, int); int do_uncover (int*, int); int ex_cmd(void); void set_mark(void); -- 2.39.3