curses编程初步--汉诺塔游戏

/*************************************************

 *  run normally:       hanoi -n <steps>              *

 *  example:           hanoi -a <steps>              *

 *  help:           hanoi -h                     *

 *************************************************/

#include <curses.h>

#include <string.h>

#include <unistd.h>

#define EXIT_SUCCESS        0

#define EXIT_FAILURE        1

#define NPEGS           3

#define MINTILES            3

#define MAXTILES            6

#define DEFAULTTILES        7

#define TOPLINE         6

#define BASELINE            16

#define STATUSLINE      (LINES-3)

#define LEFTPEG         19

#define MIDPEG          39

#define RIGHTPEG            59

#define LENTOIND(x)     (((x)-1)/2)

#define OTHER(a,b)      (3-((a)+(b)))

struct Peg {

    size_t Length[MAXTILES];

    int Count;

};

static struct Peg Pegs[NPEGS];

static int PegPos[] =

{LEFTPEG, MIDPEG, RIGHTPEG};

static int TileColour[] =

{

    COLOR_RED,

    COLOR_GREEN,

    COLOR_YELLOW,

    COLOR_BLUE,

    COLOR_MAGENTA,

    COLOR_CYAN,

};

static int NMoves = 0;

static void InitTiles(int NTiles);

static void DisplayTiles(void);

static void MakeMove(int From, int To);

static void AutoMove(int From, int To, int Num);

static void Usage(void);

static int Solved(int NumTiles);

static int GetMove(int *From, int *To);

static int InvalidMove(int From, int To);

int

main(int argc, char **argv)

{

  int NTiles, FromCol, ToCol,opt;

  unsigned char AutoFlag = 0;

  if(argc<2 || argc>3){ Usage();exit(0);}

  while( (opt=getopt(argc,argv,"a:n:h") )!=-1)

    switch (opt)

    {

      case 'n':

	NTiles = atoi(optarg);

	if (NTiles > MAXTILES || NTiles < MINTILES)

	{   fprintf(stderr, "steps must be assigned between %d and %d/n", MINTILES, MAXTILES);

	return EXIT_FAILURE;

	}

	AutoFlag = FALSE;

	break;

      case 'a':

	NTiles = atoi(optarg);

	if (NTiles > MAXTILES || NTiles < MINTILES)

	{       fprintf(stderr, "steps must be assigned between %d and %d/n", MINTILES, MAXTILES);

	return EXIT_FAILURE;

	}

	AutoFlag = TRUE;

	break;

      case 'h':

      case '?':

      case ':':

	Usage();

	exit(0);

    }

  initscr();

  if (has_colors())

  {

    int i;

    int bg = COLOR_BLACK;

    start_color();

    if (use_default_colors() == OK)

      bg = -1;

    for (i = 0; i < sizeof(TileColour); i++)

      init_pair(i + 1, bg, TileColour[i]);

  }

  cbreak();

  /* LINES and COLS are local variables in curses.h, 

   * which are used to store the total lines and total columns of current terminal.

   */

  if (LINES < 24 || COLS < 80)          /* standard terminal is 24*80 */

  {

    endwin();

    fprintf(stderr, "current terminal is less than 24x80 /n");

    return EXIT_FAILURE;

  }

  if (AutoFlag)

  {

    curs_set(0);

    leaveok(stdscr, TRUE);

  }

  InitTiles(NTiles);

  DisplayTiles();

  if (AutoFlag) {

    do {

      noecho();

      AutoMove(0, 2, NTiles);

    } while (!Solved(NTiles));

    sleep(2);

  } 

  else {

    echo();

    for (;;) {

      if (GetMove(&FromCol, &ToCol))

	break;

      if (InvalidMove(FromCol, ToCol)) {

	mvaddstr(STATUSLINE, 0, "Invalid move !!");

	refresh();

	beep();

	sleep(2);

	continue;

      }

      MakeMove(FromCol, ToCol);

      if (Solved(NTiles)) {

	mvprintw(STATUSLINE, 0, "Congratulations: You Win! %d steps used.", NMoves);

	refresh();

	sleep(5);

	break;

      }

    }

  }

  endwin();

  return EXIT_SUCCESS;

}

static int

InvalidMove(int From, int To)

{

    if (From >= NPEGS)

    return TRUE;

    if (From < 0)

    return TRUE;

    if (To >= NPEGS)

    return TRUE;

    if (To < 0)

    return TRUE;

    if (From == To)

    return TRUE;

    if (!Pegs[From].Count)

    return TRUE;

    if (Pegs[To].Count &&

    Pegs[From].Length[Pegs[From].Count - 1] >

    Pegs[To].Length[Pegs[To].Count - 1])

    return TRUE;

    return FALSE;

}

static void

InitTiles(int NTiles)

{

    int Size, SlotNo;

    for (Size = NTiles * 2 + 1, SlotNo = 0; Size >= 3; Size -= 2)

    Pegs[0].Length[SlotNo++] = Size;

    Pegs[0].Count = NTiles;

    Pegs[1].Count = 0;

    Pegs[2].Count = 0;

}

static void

DisplayTiles(void)

{

    int Line, peg, SlotNo;

    char TileBuf[BUFSIZ];

    erase();

    init_pair(20,COLOR_MAGENTA,COLOR_BLACK);

    attrset(COLOR_PAIR(20)|A_BOLD);

    mvaddstr(1, 25,"Hanoi games!");

    attrset(A_NORMAL);

    mvprintw(18, 30, "current steps : ");

    init_pair(21,COLOR_RED,COLOR_BLACK);

    attrset(COLOR_PAIR(21)|A_BOLD);

    mvprintw(18,50,"%d",NMoves);

    attrset(A_NORMAL);

    attrset(A_REVERSE);

    mvaddstr(BASELINE, 8,

         "                                                               ");

    for (Line = TOPLINE; Line < BASELINE; Line++) {

    mvaddch(Line, LEFTPEG, ' ');

    mvaddch(Line, MIDPEG, ' ');

    mvaddch(Line, RIGHTPEG, ' ');

    }

    mvaddch(BASELINE, LEFTPEG, '1');

    mvaddch(BASELINE, MIDPEG, '2');

    mvaddch(BASELINE, RIGHTPEG, '3');

    attrset(A_NORMAL);

    

    for (peg = 0; peg < NPEGS; peg++) {

    for (SlotNo = 0; SlotNo < Pegs[peg].Count; SlotNo++) {

        memset(TileBuf, ' ', Pegs[peg].Length[SlotNo]);

        TileBuf[Pegs[peg].Length[SlotNo]] = '/0';

        if (has_colors())

        attrset(COLOR_PAIR(LENTOIND(Pegs[peg].Length[SlotNo])));

        else

        attrset(A_REVERSE);

        mvaddstr(BASELINE - (SlotNo + 1),

             (int) (PegPos[peg] - Pegs[peg].Length[SlotNo] / 2),

             TileBuf);

    }

    }

    attrset(A_NORMAL);

    refresh();

}

static int

GetMove(int *From, int *To)

{

    attrset(A_REVERSE);

    mvaddstr(LINES-1, 20,"<Q>/<q> quit       <1>-<3> move");

    attrset(A_NORMAL);

    mvaddstr(STATUSLINE, 0, "Next step: from ");

    clrtoeol();

    refresh();

    *From = getch();

    if ((*From == 'q')||(*From == 'Q') )return TRUE;

    *From -= ('0' + 1);

    addstr(" to ");

    clrtoeol();

    refresh();

    *To = getch();

    if ((*To == 'q') || (*To == 'Q'))return TRUE;

    *To -= ('0' + 1);

    refresh();

    napms(500);

    move(STATUSLINE, 0);

    clrtoeol();

    refresh();

    return FALSE;

}

static void

MakeMove(int From, int To)

{

    Pegs[From].Count--;

    Pegs[To].Length[Pegs[To].Count] = Pegs[From].Length[Pegs[From].Count];

    Pegs[To].Count++;

    NMoves++;

    DisplayTiles();

}

static void

AutoMove(int From, int To, int Num)

{

    if (Num == 1) {

    MakeMove(From, To);

    napms(500);

    return;

    }

    AutoMove(From, OTHER(From, To), Num - 1);

    MakeMove(From, To);

    napms(500);

    AutoMove(OTHER(From, To), To, Num - 1);

}

static int

Solved(int NumTiles)

{

    int i;

    for (i = 1; i < NPEGS; i++)

    if (Pegs[i].Count == NumTiles)

        return TRUE;

    return FALSE;

}

static void

Usage()

{

    fprintf(stderr, "/nhanoi/t[n]steps -- play games/n/

    /t[a]steps -- examples/n/t[h] /t-- help /n");

    printf("/e[0;33m Note: steps must be assigned between %d and %d./e[0m/n", MINTILES, MAXTILES);

}

/*----------------the end-----------------*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值