2016-09-07 29 views
-1
/** 
* fifteen.c 
* 
* Computer Science 50 
* Problem Set 3 
* 
* Implements Game of Fifteen (generalized to d x d). 
* 
* Usage: fifteen d 
* 
* whereby the board's dimensions are to be d x d, 
* where d must be in [DIM_MIN,DIM_MAX] 
* 
* Note that usleep is obsolete, but it offers more granularity than 
* sleep and is simpler to use than nanosleep; `man usleep` for more. 
*/ 

#define _XOPEN_SOURCE 500 

#include <cs50.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

// constants 
#define DIM_MIN 3 
#define DIM_MAX 9 

// board 
int board[DIM_MAX][DIM_MAX]; 
int b; 

// dimensions 
int d; 

// prototypes 
void clear(void); 
void greet(void); 
void init(void); 
void draw(void); 
bool move(int tile); 
bool won(void); 

int main(int argc, string argv[]) 
{ 
    // ensure proper usage 
    if (argc != 2) 
    { 
     printf("Usage: fifteen d\n"); 
     return 1; 
    } 

    // ensure valid dimensions 
    d = atoi(argv[1]); 
    if (d < DIM_MIN || d > DIM_MAX) 
    { 
     printf("Board must be between %i x %i and %i x %i, inclusive.\n", 
      DIM_MIN, DIM_MIN, DIM_MAX, DIM_MAX); 
     return 2; 
    } 

    // open log 
    FILE* file = fopen("log.txt", "w"); 
    if (file == NULL) 
    { 
     return 3; 
    } 

    // greet user with instructions 
    greet(); 

    // initialize the board 
    init(); 

    // accept moves until game is won 
    while (true) 
    { 
     // clear the screen 
     clear(); 

     // draw the current state of the board 
     draw(); 

     // log the current state of the board (for testing) 
     for (int i = 0; i < d; i++) 
     { 
      for (int j = 0; j < d; j++) 
      { 
       fprintf(file, "%i", board[i][j]); 
       if (j < d - 1) 
       { 
        fprintf(file, "|"); 
       } 
      } 
      fprintf(file, "\n"); 
     } 
     fflush(file); 

     // check for win 
     if (won()) 
     { 
      printf("ftw!\n"); 
      break; 
     } 

     // prompt for move 
     printf("Tile to move: "); 
     int tile = GetInt(); 

     // quit if user inputs 0 (for testing) 
     if (tile == 0) 
     { 
      break; 
     } 

     // log move (for testing) 
     fprintf(file, "%i\n", tile); 
     fflush(file); 

     // move if possible, else report illegality 
     if (!move(tile)) 
     { 
      printf("\nIllegal move.\n"); 
      usleep(500000); 
     } 

     // sleep thread for animation's sake 
     usleep(500000); 
    } 

    // close log 
    fclose(file); 

    // success 
    return 0; 
} 

/** 
* Clears screen using ANSI escape sequences. 
*/ 
void clear(void) 
{ 
    printf("\033[2J"); 
    printf("\033[%d;%dH", 0, 0); 
} 

/** 
* Greets player. 
*/ 
void greet(void) 
{ 
    clear(); 
    printf("WELCOME TO GAME OF FIFTEEN\n"); 
    usleep(2000000); 
} 

/** 
* Initializes the game's board with tiles numbered 1 through d*d - 1 
* (i.e., fills 2D array with values but does not actually print them). 
*/ 
void init(void) 
{ 
    for(int i = 0, j = 0, k = ((d*d)-1); i < d; j++, k--) 
    { 
     if(j == d) 
     { 
      i = i + 1; 
      j = 0; 
     } 
     board[i][j] = k; 
    } 
    if((d*d)%2 == 0) 
    { 
     board[(d-1)][(d-2)] = 2; 
     board[(d-1)][(d-3)] = 1; 
    } 
    board[(d-1)][(d-1)] = 0; 
    b = board[(d-1)][(d-1)]; 


} 

/** 
* Prints the board in its current state. 
*/ 
void draw(void) 
{ 
    for(int i = 0, j = 0; i !=(d-1) || j!=d; j++) 
    { 
     if(j == d) 
     { 
      i = i + 1; 
      j = 0; 
      printf("\n"); 
     } 
     if(board[i][j] == 0) //b used to be 99 
     { 
      printf(" _"); 
     } 
     else 
     { 
      printf(" %2d", board[i][j]); 
     } 
    } 
    printf("\n"); 
} 

/** 
* If tile borders empty space, moves tile and returns true, else 
* returns false. 
*/ 
bool move(int tile) 
{ 
    //find tile 
    for(int i = 0, j = 0; i !=(d-1) || j!=d; j++) 
    { 
     if(j == d) 
     { 
      i = i + 1; 
      j = 0; 
     } 
     if (board[i][j] == tile) 
     { 
      //check if tile position is in valid perimeter of blank space 
      if (board[i+1][j] == b) 
      { 
       board[i+1][j] = tile; 
       board[i][j] = 0; 
       b = board[i][j]; 
       return true; 
      } 
      if (board[i-1][j] == b) 
      { 
       board[i-1][j] = tile; 
       board[i][j] = 0; 
       b = board[i][j]; 
       return true; 
      } 
      if (board[i][j+1] == b) 
      { 
       board[i][j+1] = tile; 
       board[i][j] = 0; 
       b = board[i][j]; 
       return true; 
      } 
      if (board[i][j-1] == b) 
      { 
       printf("%i", board[i][j-1]); 
       board[i][j-1] = tile; 
       board[i][j] = 0; 
       b = board[i][j]; 
       return true; 
      } 
     } 
    } 
    return false; 
} 

/** 
* Returns true if game is won (i.e., board is in winning configuration), 
* else false. 
*/ 
bool won(void) 
{ 
    for(int i = 0, j = 0, k = 1; i !=(d-1) || j!=d; j++) 
    { 
     if(j == d) 
     { 
      i = i + 1; 
      j = 0; 
     } 
     if (k == (d*d)-1) 
     { 
      return true; 
     } 
     if (board[i][j] == k) 
     { 
      k = k + 1; 
     } 
    } 
    return false; 
} 

我本來爲什麼array [i] [ - 1] == 0?如何避免使用未定義的變量?

board[(d-1)][(d-1)] = 0; 

等於99與移動功能查找99.對於我的問題集,我應該使用0。一旦我改變了99比0,由於某種原因,0是沿如果board [i] [j-1]被發現,即使這意味着board [2] [ - 1]。爲什麼這允許/爲什麼等於0?以及如何禁用此功能?

+0

禁用C語言中的某些東西是不可能的,那就是語言背後的全部理念是,您最好知道您在做什麼 –

回答

2

您有int board[DIM_MAX][DIM_MAX];其中#define DIM_MIN 3和爲元素分配的內存是連續的,因此通常您將通過使用board[2][-1]訪問board[1][2]。但是,這是未定義的行爲,它允許發生任何事情,你不能使用它。

N1570 J.2未定義行爲引用:

數組下標超出範圍,即使對象是與所述給定 顯然標訪問(如在左值表達式[1] [ 7]給出了聲明int a [4] [5])(6.5.6)。

2

board [2] [ - 1]。爲什麼允許

C確實允許您訪問數組的範圍。但它是未定義的行爲

爲什麼這等於0?

意外。這是未定義的行爲,它可能是任何東西

+0

謝謝。如何防止訪問未定義的行爲? – KevJpg

+0

@KevJpg通過學習語言的規則,然後不寫違反規則的代碼。 –

+0

@KevJpg用你所有的編譯器警告編譯你的代碼,希望這會在編譯階段被捕獲,而不是運行時。根據你的編譯器,你可以試試'-Wall' – NoseKnowsAll

相關問題