Linux 數獨小遊戲 curses cs50 作業

來源:互聯網
上載者:User

本程式還有兩個bin檔案提供數獨資料,可以在我的資源裡面下載.下面是makefile 標頭檔 和 源檔案....

## Makefile## Computer Science 50# Problem Set 4#sudoku: Makefile sudoku.c sudoku.hgcc -ggdb -std=c99 -Wall -Werror -Wformat=0 -Wno-unused-but-set-variable -o sudoku sudoku.c -lncurses -gclean:rm -f *.o a.out core log.txt sudoku

/**************************************************************************** * sudoku.h * * Computer Science 50 * Problem Set 4 * * Compile-time options for the game of Sudoku. ***************************************************************************/// game's author#define AUTHOR "Sam Brown"// game's title#define TITLE "Sudoku"// banner's colors#define FG_BANNER COLOR_CYAN#define BG_BANNER COLOR_BLACK// grid's colors#define FG_GRID COLOR_WHITE#define BG_GRID COLOR_BLACK// border's colors#define FG_BORDER COLOR_WHITE#define BG_BORDER COLOR_RED// logo's colors#define FG_LOGO COLOR_YELLOW#define BG_LOGO COLOR_BLACK// nicknames for pairs of colorsenum { PAIR_BANNER = 1, PAIR_GRID, PAIR_BORDER, PAIR_LOGO, PAIR_WRONG, PAIR_PICE };

/**************************************************************************** * sudoku.c * * Computer Science 50 * Problem Set 4 * * Implements the game of Sudoku. ***************************************************************************/#include "sudoku.h"#include <ctype.h>#include <ncurses.h>#include <signal.h>#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>// macro for processing control characters#define CTRL(x) ((x) & ~0140)// size of each int (in bytes) in *.bin files#define INTSIZE 4// wrapper for our game's globalsstruct{    // the current level    char *level;    // the game's board    int board[9][9];    // the board's number    int number;    // the board's top-left coordinates    int top, left;    // the cursor's current location between (0,0) and (8,8)    int y, x;} g;// prototypesvoid draw_grid(void);void draw_borders(void);void draw_logo(void);void draw_numbers(void);void hide_banner(void);bool load_board(void);void handle_signal(int signum);void log_move(int ch);void redraw_all(void);bool restart_game(void);void show_banner(char *b);void show_cursor(void);void shutdown(void);bool startup(void);void move_step( void );bool can_put( int key );/* * Main driver for the game. */int main(int argc, char *argv[]){    // define usage    const char *usage = "Usage: sudoku n00b|l33t [#]\n";    // ensure that number of arguments is as expected    if (argc != 2 && argc != 3)    {        fprintf(stderr, usage);        return 1;    }    // ensure that level is valid    if (strcmp(argv[1], "debug") == 0)        g.level = "debug";    else if (strcmp(argv[1], "n00b") == 0)        g.level = "n00b";    else if (strcmp(argv[1], "l33t") == 0)        g.level = "l33t";    else    {        fprintf(stderr, usage);        return 2;    }    // n00b and l33t levels have 1024 boards; debug level has 9    int max = (strcmp(g.level, "debug") == 0) ? 9 : 1024;    // ensure that #, if provided, is in [1, max]    if (argc == 3)    {        // ensure n is integral        char c;        if (sscanf(argv[2], " %d %c", &g.number, &c) != 1)        {            fprintf(stderr, usage);            return 3;        }        // ensure n is in [1, max]        if (g.number < 1 || g.number > max)        {            fprintf(stderr, "That board # does not exist!\n");            return 4;        }        // seed PRNG with # so that we get same sequence of boards        srand(g.number);    }    else    {        // seed PRNG with current time so that we get any sequence of boards        srand(time(NULL));        // choose a random n in [1, max]        g.number = rand() % max + 1;    }    // start up ncurses    if (!startup())    {        fprintf(stderr, "Error starting up ncurses!\n");        return 5;    }    // register handler for SIGWINCH (SIGnal WINdow CHanged)    signal(SIGWINCH, (void (*)(int)) handle_signal);    // start the first game    if (!restart_game())    {        shutdown();        fprintf(stderr, "Could not load board from disk!\n");        return 6;    }    redraw_all();    // let the user play!    int ch;    do    {        // refresh the screen        refresh();        // get user's input        ch = getch();        // capitalize input to simplify cases        ch = toupper(ch);        // process user's input        switch (ch)        {            // start a new game            case 'N':                 g.number = rand() % max + 1;                if (!restart_game())                {                    shutdown();                    fprintf(stderr, "Could not load board from disk!\n");                    return 6;                }                break;            // restart current game            case 'R':                 if (!restart_game())                {                    shutdown();                    fprintf(stderr, "Could not load board from disk!\n");                    return 6;                }                break;case KEY_LEFT:--g.x;if( g.x >= 0 && g.x <= 8 && g.y >= 0 && g.y <= 8 )move_step();else++g.x;break;case KEY_RIGHT:++g.x;if( g.x >= 0 && g.x <= 8 && g.y >= 0 && g.y <= 8 )move_step();else--g.x;break;case KEY_UP:--g.y;if( g.x >= 0 && g.x <= 8 && g.y >= 0 && g.y <= 8 )move_step();else++g.y;break;case KEY_DOWN:++g.y;if( g.x >= 0 && g.x <= 8 && g.y >= 0 && g.y <= 8 )move_step();else--g.y;break;case '1':if( !g.board[g.y][g.x] ){if( can_put( 1 ) ){g.board[g.y][g.x] = 1;printw( "1" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "1" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '2':if( !g.board[g.y][g.x] ){if( can_put(2) ){g.board[g.y][g.x] = 2;printw(  "2" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "2" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '3':if( !g.board[g.y][g.x] ){if( can_put(3) ){g.board[g.y][g.x] = 3;printw( "3" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "3" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '4':if( !g.board[g.y][g.x] ){if( can_put(4) ){g.board[g.y][g.x] = 4;printw( "4" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "4" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '5':if( !g.board[g.y][g.x]  ){if( can_put(5) ){g.board[g.y][g.x] = 5;printw( "5" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "5" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '6':if( !g.board[g.y][g.x] ){if( can_put(6) ){g.board[g.y][g.x] = 6;printw( "6" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "6" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '7':if( !g.board[g.y][g.x]  ){if( can_put(7) ){g.board[g.y][g.x] = 7;printw( "7" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "7" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '8':if( !g.board[g.y][g.x]   ){if( can_put(8) ){g.board[g.y][g.x] = 8;printw(  "8" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "8" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;case '9':if( !g.board[g.y][g.x]  ){if(  can_put(9) ){g.board[g.y][g.x] = 9;printw( "9" );move_step( );}else{attron( COLOR_PAIR(PAIR_WRONG) );printw( "9" );move_step();attroff( COLOR_PAIR(PAIR_WRONG) );}}break;            // let user manually redraw screen with ctrl-L            case CTRL('l'):                redraw_all();                break;        }        // log input (and board's state) if any was received this iteration        if (ch != ERR)            log_move(ch);    }    while (ch != 'Q');    // shut down ncurses    shutdown();    // tidy up the screen (using ANSI escape sequences)    printf("\033[2J");    printf("\033[%d;%dH", 0, 0);    // that's all folks    printf("\nkthxbai!\n\n");    return 0;}bool can_put( int key ){int i, j, m, k, y, x;for( i = 0; i < 9; i++ )if( g.board[i][g.x] == key || g.board[g.y][i] == key )return false;          if( g.y <= 2 && g.y >= 0 )y = 0;if( g.y <= 5 && g.y >= 3 )y = 3;if( g.y <= 8 && g.y >= 6 )y = 6;if( g.x <= 2 && g.x >= 0 )x = 0;if( g.x <= 5 && g.x >= 3 )x = 3;if( g.x <= 8 && g.x >= 6 )x = 6;//mvprintw( 2, 2, "i=j=%d   m=k=%d", i, m );for( i = j = y; i <= j+2; i++ )for( m = k = x; m <= k+2; m++ )if( g.board[i][m] == key )return false;return true;}void move_step( void ){show_cursor();}/* * Draw's the game's board. */void draw_grid(void){    // get window's dimensions    int maxy, maxx;    getmaxyx(stdscr, maxy, maxx);    // determine where top-left corner of board belongs     g.top = maxy/2 - 7;    g.left = maxx/2 - 30;    // enable color if possible    if (has_colors())        attron(COLOR_PAIR(PAIR_GRID));    // print grid    for (int i = 0 ; i < 3 ; ++i )    {        mvaddstr(g.top + 0 + 4 * i, g.left, "+-------+-------+-------+");        mvaddstr(g.top + 1 + 4 * i, g.left, "|       |       |       |");        mvaddstr(g.top + 2 + 4 * i, g.left, "|       |       |       |");        mvaddstr(g.top + 3 + 4 * i, g.left, "|       |       |       |");    }    mvaddstr(g.top + 4 * 3, g.left, "+-------+-------+-------+" );    // remind user of level and #    char reminder[maxx+1];    sprintf(reminder, "   playing %s #%d", g.level, g.number);    mvaddstr(g.top + 14, g.left + 25 - strlen(reminder), reminder);    // disable color if possible    if (has_colors())        attroff(COLOR_PAIR(PAIR_GRID));}/* * Draws game's borders. */void draw_borders(void){    // get window's dimensions    int maxy, maxx;    getmaxyx(stdscr, maxy, maxx);    // enable color if possible (else b&w highlighting)    if (has_colors())    {        attron(A_PROTECT);        attron(COLOR_PAIR(PAIR_BORDER));    }    else        attron(A_REVERSE);    // draw borders    for (int i = 0; i < maxx; i++)    {        mvaddch(0, i, ' ');        mvaddch(maxy-1, i, ' ');    }    // draw header    char header[maxx+1];    sprintf(header, "%s by %s", TITLE, AUTHOR);    mvaddstr(0, (maxx - strlen(header)) / 2, header);    // draw footer    mvaddstr(maxy-1, 1, "[N]ew Game   [R]estart Game");    mvaddstr(maxy-1, maxx-13, "[Q]uit Game");    // disable color if possible (else b&w highlighting)    if (has_colors())        attroff(COLOR_PAIR(PAIR_BORDER));    else        attroff(A_REVERSE);}/* * Draws game's logo.  Must be called after draw_grid has been * called at least once. */void draw_logo(void){    // determine top-left coordinates of logo    int top = g.top + 2;    int left = g.left + 30;    // enable color if possible    if (has_colors())        attron(COLOR_PAIR(PAIR_LOGO));    // draw logo    mvaddstr(top + 0, left, "               _       _          ");    mvaddstr(top + 1, left, "              | |     | |         ");    mvaddstr(top + 2, left, " ___ _   _  __| | ___ | | ___   _ ");    mvaddstr(top + 3, left, "/ __| | | |/ _` |/ _ \\| |/ / | | |");    mvaddstr(top + 4, left, "\\__ \\ |_| | (_| | (_) |   <| |_| |");    mvaddstr(top + 5, left, "|___/\\__,_|\\__,_|\\___/|_|\\_\\\\__,_|");    // sign logo    char signature[3+strlen(AUTHOR)+1];    sprintf(signature, "by %s", AUTHOR);    mvaddstr(top + 7, left + 35 - strlen(signature) - 1, signature);    // disable color if possible    if (has_colors())        attroff(COLOR_PAIR(PAIR_LOGO));}/* * Draw's game's numbers.  Must be called after draw_grid has been * called at least once. */void draw_numbers(void){int flag = 0;    // iterate over board's numbers    for (int i = 0; i < 9; i++)    {        for (int j = 0; j < 9; j++)        {            // determine char            char c = g.board[i][j];if( c == 0 )c = '.';else{ attron( COLOR_PAIR(PAIR_PICE ) ); c = g.board[i][j] + '0'; flag = 1;}            mvaddch(g.top + i + 1 + i/3, g.left + 2 + 2*(j + j/3), c);if( flag ){attroff( COLOR_PAIR(PAIR_PICE) );flag = 0;}            refresh();        }    }}/* * Designed to handles signals (e.g., SIGWINCH). */void handle_signal(int signum){    // handle a change in the window (i.e., a resizing)    if (signum == SIGWINCH)        redraw_all();    // re-register myself so this signal gets handled in future too   signal(signum, (void (*)(int)) handle_signal);}/* * Hides banner. */void hide_banner(void){    // get window's dimensions    int maxy, maxx;    getmaxyx(stdscr, maxy, maxx);    // overwrite banner with spaces    for (int i = 0; i < maxx; i++)        mvaddch(g.top + 16, i, ' ');}/* * Loads current board from disk, returning true iff successful. */bool load_board(void){    // open file with boards of specified level    char filename[strlen(g.level) + 5];    sprintf(filename, "%s.bin", g.level);    FILE *fp = fopen(filename, "rb");    if (fp == NULL)        return false;    // determine file's size    fseek(fp, 0, SEEK_END);    int size = ftell(fp);    // ensure file is of expected size    if (size % (81 * INTSIZE) != 0)    {        fclose(fp);        return false;    }    // compute offset of specified board    int offset = ((g.number - 1) * 81 * INTSIZE);    // seek to specified board    fseek(fp, offset, SEEK_SET);    // read board into memory    if (fread(g.board, 81 * INTSIZE, 1, fp) != 1)    {        fclose(fp);        return false;    }    // w00t    fclose(fp);    return true;}/* * Logs input and board's state to log.txt to facilitate automated tests. */void log_move(int ch){    // open log    FILE *fp = fopen("log.txt", "a");    if (fp == NULL)        return;    // log input    fprintf(fp, "%d\n", ch);    // log board    for (int i = 0; i < 9; i++)    {        for (int j = 0; j < 9; j++)            fprintf(fp, "%d", g.board[i][j]);        fprintf(fp, "\n");    }    // that's it    fclose(fp);}/* * (Re)draws everything on the screen. */void redraw_all(void){    // reset ncurses    endwin();    refresh();    // clear screen    clear();    // re-draw everything    draw_borders();    draw_grid();    draw_logo();    draw_numbers();    // show cursor    show_cursor();}/* * (Re)starts current game, returning true iff succesful. */bool restart_game(void){    // reload current game    if (!load_board())        return false;    // redraw board    draw_grid();    draw_numbers();    // get window's dimensions    int maxy, maxx;    getmaxyx(stdscr, maxy, maxx);    // move cursor to board's center    g.y = g.x = 4;    show_cursor();    // remove log, if any    remove("log.txt");    // w00t    return true;}/* * Shows cursor at (g.y, g.x). */void show_cursor(void){    // restore cursor's location    move(g.top + g.y + 1 + g.y/3, g.left + 2 + 2*(g.x + g.x/3));}/* * Shows a banner.  Must be called after show_grid has been * called at least once. */void show_banner(char *b){    // enable color if possible    if (has_colors())        attron(COLOR_PAIR(PAIR_BANNER));    // determine where top-left corner of board belongs     mvaddstr(g.top + 16, g.left + 64 - strlen(b), b);    // disable color if possible    if (has_colors())        attroff(COLOR_PAIR(PAIR_BANNER));}/* * Shuts down ncurses. */void shutdown(void){    endwin();}/* * Starts up ncurses.  Returns true iff successful. */bool startup(void){    // initialize ncurses    if (initscr() == NULL)        return false;    // prepare for color if possible    if (has_colors())    {        // enable color        if (start_color() == ERR || attron(A_PROTECT) == ERR)        {            endwin();            return false;        }        // initialize pairs of colors        if (init_pair(PAIR_BANNER, FG_BANNER, BG_BANNER) == ERR ||            init_pair(PAIR_GRID, FG_GRID, BG_GRID) == ERR ||            init_pair(PAIR_BORDER, FG_BORDER, BG_BORDER) == ERR ||            init_pair(PAIR_LOGO, FG_LOGO, BG_LOGO) == ERR ||init_pair(PAIR_WRONG, COLOR_RED, COLOR_BLACK) == ERR ||//init the wrong number's color  ref: can_put()init_pair(PAIR_PICE, COLOR_YELLOW, COLOR_BLACK) == ERR )        {            endwin();            return false;        }    }    // don't echo keyboard input    if (noecho() == ERR)    {        endwin();        return false;    }    // disable line buffering and certain signals    if (raw() == ERR)    {        endwin();        return false;    }    // enable arrow keys    if (keypad(stdscr, true) == ERR)    {        endwin();        return false;    }    // wait 1000 ms at a time for input    timeout(1000);    // w00t    return true;}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.