Just wrote my first Curses program

This is a discussion on Just wrote my first Curses program within the Linux Programming forums, part of the Platform Specific Boards category; Technically this is PDCurses and technically it's on a windows environment, but I expect if it still works in Unix ...

  1. #1
    Registered User guesst's Avatar
    Join Date
    Feb 2008
    Location
    Lehi, UT
    Posts
    179

    Just wrote my first Curses program

    Technically this is PDCurses and technically it's on a windows environment, but I expect if it still works in Unix I've accomplished my goal.

    Also, is there a better board for this sort of thing?

    Comments, critique, and suggestions would be welcome:
    Code:
    // Gocart Race by Joseph Larson Ver 18-Mar-2008
    #include <curses.h>
    #include <time.h>
    #define XSIZE 79
    #define YSIZE 24
    #define SPEED 50
    
    char track[] = "3)1+?!*?&1+?!(1@!`3!!O*~}$tlv!0O'p0x!,?)pnw&3+7*plw&3+7*plw.3-"
    "3`1,q,r.3-3`1,v+7Py.7*{&7,3`1,~1/3\"7*~o/3\"7*~o/3#?)~o/3`z'~O/3hz'~O/3`y%~70"
    "3!!!-3!-1!'3!.7!'?!.O!(q!0O";
    int car[4] = {ACS_UARROW, ACS_RARROW, ACS_DARROW, ACS_LARROW};
    char buf[YSIZE][XSIZE];
    
    int init() { // Setup Curses the way we want it.
      initscr ();
      if ((LINES < YSIZE) || (COLS < XSIZE)) {
        endwin();
        return (1);
      }
      raw (); nodelay(stdscr,1); noecho(); curs_set(0); nonl(); keypad(stdscr,1);
      start_color();
      init_pair (1, COLOR_RED, COLOR_WHITE); // Track
      init_pair (2, COLOR_BLACK, COLOR_YELLOW);// Finish
      init_pair (3, COLOR_BLUE, COLOR_WHITE); // Car
      init_pair (4, COLOR_RED, COLOR_BLACK); // Red Light
      init_pair (5, COLOR_YELLOW, COLOR_BLACK); // Yellow Light
      init_pair (6, COLOR_GREEN, COLOR_BLACK); // Green Light
      return 0;
    }
    
    void draw_track () {
      int x, y, c, pl, cur, tr;
    
      for (x = 0; x <= XSIZE ; x++) mvaddch(0, x, ACS_BOARD|COLOR_PAIR(1));
      c = pl = 0; cur = track[0] - 33;
      for (y = 1; y < YSIZE; y++) {
        mvaddch (y, 0, ACS_BOARD|COLOR_PAIR(1));
        for (x = 1; x < XSIZE; x++) {
          if (pl == 6) {cur = track[++c] - 33; pl = 0;}
          if (cur < 15) {cur++; tr = 0;}
          else if (cur > 78) {cur--; tr = 1;}
          else tr = ((cur - 15) & (1 << pl++));
          buf[y][x] = !tr;
          tr = (tr) ? ACS_BOARD : ' ';
          mvaddch (y, x, tr | COLOR_PAIR (1));
          refresh();
        }
        mvaddch (y, XSIZE, ACS_BOARD|COLOR_PAIR (1));
      }
      for (x = 0; x <= XSIZE; x++) mvaddch(YSIZE, x, ACS_BOARD|COLOR_PAIR(1));
      for (y = 1; y <= 3; y++) mvaddch(y, 37, ACS_DIAMOND|COLOR_PAIR(2));
    }
    
    void play () {
      int x, y, ch, dir;
      double secs;
      clock_t start, timer;
    
      draw_track ();
      x = 41, y = 2; dir = 1;
      mvaddch (y, x, car[dir]|COLOR_PAIR(3));
      refresh ();
      for (ch = 0; ch < 3; ch++)
        mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch));
      refresh();
      for (ch = 0; ch < 3; ch++) {
        napms (1000);
        mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch)|A_BOLD); refresh();
        beep();
        if (ch < 2) mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch));
      }
      start = clock();
      do {
        timer = clock ();
        secs = (double)(timer - start) / CLOCKS_PER_SEC;
        mvprintw (YSIZE, 37, "%.2f", secs);
        mvaddch (y, x, ' '|COLOR_PAIR(1));
        ch = getch();
        switch (ch) {
          case KEY_UP    : dir = 0; break;
          case KEY_RIGHT : dir = 1; break;
          case KEY_DOWN  : dir = 2; break;
          case KEY_LEFT  : dir = 3; break;
        }
        switch (dir) {
          case 0 : y--; break;
          case 1 : x++; break;
          case 2 : y++; break;
          case 3 : x--; break;
        }
        mvaddch (y, x, car[dir]|COLOR_PAIR(3));
        refresh ();
        napms (SPEED);
      } while (buf[y][x]);
      if ((x == 37) && (y >= 1) && (y <= 3)) mvaddstr (10, 35, "You WIN!");
      else mvaddstr (10, 36, "CRASH!");
      mvaddstr (12, 34, "Total Time:");
      mvprintw (13, 37, "%.2f", secs);
    }
    
    int main () {
      if (init()) return 0;
      else {
        play();
      }
      mvaddstr(15, 27, "Press any key to quit...");
      while (getch() == ERR);
      endwin();
      return 0;
    }

  2. #2
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,249
    Quote Originally Posted by guesst View Post
    Comments, critique, and suggestions would be welcome:
    Sure thing. You can't directly initialize car[4] like that. The ACS_XXX macros are not guaranteed to be constant expressions, and in fact are not, on my installation of ncurses. You need to break the initialization out into explicit code in init() instead of an initializer list.

    Other than that, pretty cool. Is that car supposed to leave a trail behind it, or is it a bug?

    EDIT: Also, total time doesn't change when I play. Obviously a bug, but I don't have time to find it at the moment.

  3. #3
    Registered User
    Join Date
    Jan 2008
    Posts
    287
    Nice! I like it. I had to increase SLEEP to about 150 before I could make it through that narrow passage though.

    When does gocart 2 come out? Or maybe a package of additional tracks???

  4. #4
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Really nice, good job!

    How about putting the map in an external file, then the user could add their own?
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  5. #5
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    >Also, is there a better board for this sort of thing?

    If it's a game (as the comments suggest it is), then you can post it in the game programming form in the Sticky thread titled "Post your games here".

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,047
    It's very nice. I really like the red-yellow-green lights.

    I have one suggestion: make the user press a specific key to quit. I kept pressing a directional key, not realizing I'd crashed or whatever, and always missed the exit message.

    Total time never changes on my system, either. I'm not sure what was wrong with it, though I think that CLOCKS_PER_SEC may not apply to clock_ts. Also, the screen size was one line too tall for my 80x24 terminal. Anyway. This is the code I eventually used. I'm on a 64-bit Debian GNU/Linux system.
    Code:
    // Gocart Race by Joseph Larson Ver 18-Mar-2008
    #include <curses.h>
    #include <time.h>
    #define XSIZE 79
    #define YSIZE 24
    #define SPEED 50
    
    char track[] = "3)1+?!*?&1+?!(1@!`3!!O*~}$tlv!0O'p0x!,?)pnw&3+7*plw&3+7*plw.3-"
    "3`1,q,r.3-3`1,v+7Py.7*{&7,3`1,~1/3\"7*~o/3\"7*~o/3#?)~o/3`z'~O/3hz'~O/3`y%~70"
    "3!!!-3!-1!'3!.7!'?!.O!(q!0O";
    /*int car[4] = {ACS_UARROW, ACS_RARROW, ACS_DARROW, ACS_LARROW};*/
    int car[4];
    char buf[YSIZE][XSIZE];
    
    int init() { // Setup Curses the way we want it.
      initscr ();
      if ((LINES < YSIZE) || (COLS < XSIZE)) {
        endwin();
        return (1);
      }
      raw (); nodelay(stdscr,1); noecho(); curs_set(0); nonl(); keypad(stdscr,1);
      start_color();
      init_pair (1, COLOR_RED, COLOR_WHITE); // Track
      init_pair (2, COLOR_BLACK, COLOR_YELLOW);// Finish
      init_pair (3, COLOR_BLUE, COLOR_WHITE); // Car
      init_pair (4, COLOR_RED, COLOR_BLACK); // Red Light
      init_pair (5, COLOR_YELLOW, COLOR_BLACK); // Yellow Light
      init_pair (6, COLOR_GREEN, COLOR_BLACK); // Green Light
    
      car[0] = ACS_UARROW;
      car[1] = ACS_RARROW;
      car[2] = ACS_DARROW;
      car[3] = ACS_LARROW;
    
      return 0;
    }
    
    void draw_track () {
      int x, y, c, pl, cur, tr;
    
      for (x = 0; x <= XSIZE ; x++) mvaddch(0, x, ACS_BOARD|COLOR_PAIR(1));
      c = pl = 0; cur = track[0] - 33;
      for (y = 1; y < YSIZE; y++) {
        mvaddch (y, 0, ACS_BOARD|COLOR_PAIR(1));
        for (x = 1; x < XSIZE; x++) {
          if (pl == 6) {cur = track[++c] - 33; pl = 0;}
          if (cur < 15) {cur++; tr = 0;}
          else if (cur > 78) {cur--; tr = 1;}
          else tr = ((cur - 15) & (1 << pl++));
          buf[y][x] = !tr;
          tr = (tr) ? ACS_BOARD : ' ';
          mvaddch (y, x, tr | COLOR_PAIR (1));
          refresh();
        }
        mvaddch (y, XSIZE, ACS_BOARD|COLOR_PAIR (1));
      }
      for (x = 0; x <= XSIZE; x++) mvaddch(YSIZE, x, ACS_BOARD|COLOR_PAIR(1));
      for (y = 1; y <= 3; y++) mvaddch(y, 37, ACS_DIAMOND|COLOR_PAIR(2));
    }
    
    void play () {
      int x, y, ch, dir;
      double secs;
      /*clock_t*/ time_t start, timer;
    
      draw_track ();
      x = 41, y = 2; dir = 1;
      mvaddch (y, x, car[dir]|COLOR_PAIR(3));
      refresh ();
      for (ch = 0; ch < 3; ch++)
        mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch));
      refresh();
      for (ch = 0; ch < 3; ch++) {
        napms (1000);
        mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch)|A_BOLD); refresh();
        beep();
        if (ch < 2) mvaddch(0, 38 + ch, ACS_DIAMOND|COLOR_PAIR(4 + ch));
      }
      time(&start);
      do {
        time(&timer);
        /*secs = (double)(timer - start) / CLOCKS_PER_SEC;*/
        secs = difftime(timer, start);
        mvprintw (YSIZE - 1, 37, "%.2f", secs);
        mvaddch (y, x, ' '|COLOR_PAIR(1));
        ch = getch();
        switch (ch) {
          case KEY_UP    : dir = 0; break;
          case KEY_RIGHT : dir = 1; break;
          case KEY_DOWN  : dir = 2; break;
          case KEY_LEFT  : dir = 3; break;
        }
        switch (dir) {
          case 0 : y--; break;
          case 1 : x++; break;
          case 2 : y++; break;
          case 3 : x--; break;
        }
        mvaddch (y, x, car[dir]|COLOR_PAIR(3));
        refresh ();
        napms (SPEED);
      } while (buf[y][x]);
      if ((x == 37) && (y >= 1) && (y <= 3)) mvaddstr (10, 35, "You WIN!");
      else mvaddstr (10, 36, "CRASH!");
      mvaddstr (12, 34, "Total Time:");
      mvprintw (13, 37, "%.2f", secs);
    }
    
    int main () {
      if (init()) return 0;
      else {
        play();
      }
      mvaddstr(15, 27, "Press any key to quit...");
      while (getch() == ERR);
      endwin();
      return 0;
    }
    Modified lines are indicated with blue, of course. I didn't make only one key exit, though.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #7
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,249
    Quote Originally Posted by dwks View Post
    Total time never changes on my system, either. I'm not sure what was wrong with it, though I think that CLOCKS_PER_SEC may not apply to clock_ts.
    I gave this some more thought. See all those calls to napms()? I bet this program spends practically all of its time asleep. Which makes sense, otherwise it would be far too fast to play. And clock() does not increment during sleep, so you never see it changing.

    Your fix to call time() instead of clock() is the correct fix. If you wanted greater resolution, you could use gettimeofday(). But clock() isn't the right choice. Good fix.

  8. #8
    Registered User guesst's Avatar
    Join Date
    Feb 2008
    Location
    Lehi, UT
    Posts
    179
    Interesting. Everything works on mine okay, timeer, ACSXXX, everything. I would never have known these problems if not for your help. (That's why I posted it here).

    As for the track pack, the tracks are encoded using an encoding method that I'm going to be talking about later on my website. (I'm out of town right now) But it's the same as the depicter method. So changing the string for the track at the beginning will affect the map. The "map pack" as suggested will be in the comments for this program, when it gets featured in a few weeks.

    With that in mind, would DWKS mind if I posted the program pretty with the modifications you made pretty much exactly as shown? In truth, that's probably exactly how I would have done it.

    I've also changed it so that there's a "Press Q to quit, press R to retry" there at the end, tho I'm planning on changing the game so that a crash just causes you to spin in place for a bit before you can continue. I'm also debating having the controls be left/right (relative) and speed up/slow down. Meh, folks can figure that out for themselves I'll bet.

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,047
    Interesting. Everything works on mine okay, timeer, ACSXXX, everything. I would never have known these problems if not for your help. (That's why I posted it here).
    That's differences between platforms for you. pdcurses's implementation of sleep, or libc's implementation of clock(), must be different from my own. Or maybe clock() on Windows simply increments no matter what. Maybe it's implemented in terms of time(). Who knows.

    With that in mind, would DWKS mind if I posted the program pretty with the modifications you made pretty much exactly as shown? In truth, that's probably exactly how I would have done it.
    Hey, it's your program. My modifications to it are yours. You can whatever you wish with them. Good of you to ask, however.

    I've also changed it so that there's a "Press Q to quit, press R to retry" there at the end, tho I'm planning on changing the game so that a crash just causes you to spin in place for a bit before you can continue. I'm also debating having the controls be left/right (relative) and speed up/slow down. Meh, folks can figure that out for themselves I'll bet.
    I do prefer relative directions, but that's just me.

    BTW, your battleship game needed quite a few modifications to compile on my system. I never got it to run, actually, though I didn't try for very long.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    Win32's clock() indeed increments during sleeping.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User guesst's Avatar
    Join Date
    Feb 2008
    Location
    Lehi, UT
    Posts
    179
    Quote Originally Posted by dwks View Post
    BTW, your battleship game needed quite a few modifications to compile on my system. I never got it to run, actually, though I didn't try for very long.
    Really? See, this is why I wish I had 3 systems to try compiling on. I wonder why it didn't work.

    Hey, does RobotEscape work?

  12. #12
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,249
    Quote Originally Posted by guesst View Post
    Really? See, this is why I wish I had 3 systems to try compiling on. I wonder why it didn't work.
    If you're willing to license your code under an OSI-compliant license (there are many), you can host your code on Sourceforge and you get free access to their build/test farm, which is composed of about 70 different kinds of architectures (last time I checked).

  13. #13
    Registered User guesst's Avatar
    Join Date
    Feb 2008
    Location
    Lehi, UT
    Posts
    179
    Quote Originally Posted by brewbuck View Post
    If you're willing to license your code under an OSI-compliant license (there are many), you can host your code on Sourceforge and you get free access to their build/test farm, which is composed of about 70 different kinds of architectures (last time I checked).
    The problem is I have a program a week I'm putting out. I mean, that's a lot of testing.

    Dang, gettimeofday is linux specific. I guess we'll just go with one second intervals.

    The gocart program is ready, thanks to all your help, I'll let you know when I post it. It may be a week or two.
    Type-ins are back! Visit Cymon's Games at http://www.cymonsgames.com for a new game every week!

  14. #14
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,249
    Quote Originally Posted by guesst View Post
    Dang, gettimeofday is linux specific. I guess we'll just go with one second intervals.
    Who the heck told you that? gettimeofday() is POSIX standard. And you can write a wrapper for it on Windows -- Googling "Windows gettimeofday" turns up a bunch of examples.

  15. #15
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,047
    Hey, does RobotEscape work?
    Well, no, because it uses getche(). gcc doesn't have getche() on my system. I suppose I could convert it to use ncurses, but I don't really feel like it right now. [edit] Your link doesn't work for me. Iceweasel wants to save the page for some reason instead of display it. Strange, because it worked last time I tried it. [/edit]
    Last edited by dwks; 04-02-2008 at 10:57 AM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Can someome help me with a program please?
    By WinterInChicago in forum C++ Programming
    Replies: 3
    Last Post: 09-21-2006, 10:58 PM
  2. Replies: 2
    Last Post: 04-25-2005, 11:59 AM
  3. Replies: 3
    Last Post: 03-04-2005, 01:46 PM
  4. wrote a program; please review/comment
    By spirited in forum C++ Programming
    Replies: 4
    Last Post: 05-22-2003, 01:37 PM
  5. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21