#include #include #include #include #include #include #define DESIRED_WIDTH 70 #define DESIRED_HEIGHT 25 WINDOW * g_mainwin; int g_oldcur, g_score = 0, g_width, g_height; typedef struct { int x; int y; } pos; pos fruit; // 2D array of all spaces on the board. bool *spaces; // -------------------------------------------------------------------------- // Queue stuff // Queue implemented as a doubly linked list struct s_node { pos *position; // **TODO: make this a void pointer for generality. struct s_node *prev; struct s_node *next; } *front=NULL, *back=NULL; typedef struct s_node node; // Returns the position at the front w/o dequeing pos* peek( ) { return front == NULL ? NULL : front->position; } // Returns the position at the front and dequeues pos* dequeue( ) { node *oldfront = front; front = front->next; return oldfront->position; } // Queues a position at the back void enqueue( pos position ) { pos *newpos = (pos*) malloc( sizeof( position ) ); node *newnode = (node*) malloc( sizeof( node ) ); newpos->x = position.x; newpos->y = position.y; newnode->position = newpos; if( front == NULL && back == NULL ) front = back = newnode; else { back->next = newnode; newnode->prev = back; back = newnode; } } // End Queue stuff // Snake stuff // Writes text to a coordinate void snake_write_text( int y, int x, char* str ) { mvwaddstr( g_mainwin, y , x, str ); //add a string of characters to a curses window and advance cursor } // Draws the borders void snake_draw_board( ) { int i; for( i=0; inext; free( n ); } endwin(); exit(0); } // Is the current position in bounds? bool snake_in_bounds( pos position ) { return position.y < g_height - 1 && position.y > 0 && position.x < g_width - 1 && position.x > 0; } // 2D matrix of possible positions implemented with a 1D array. This maps // the x,y coordinates to an index in the array. int snake_cooridinate_to_index( pos position ) { return g_width * position.y + position.x; } // Similarly this functions maps an index back to a position pos snake_index_to_coordinate( int index ) { int x = index % g_width; int y = index / g_width; return (pos) { x, y }; } // Draw the fruit somewhere randomly on the board void snake_draw_fruit( ) { attrset( COLOR_PAIR( 3 ) );//curses character and window attribute control routines int idx; do { idx = rand( ) % ( g_width * g_height ); fruit = snake_index_to_coordinate( idx ); } while( spaces[idx] || !snake_in_bounds( fruit ) ); snake_write_text( fruit.y, fruit.x, "F" ); } // Handles moving the snake for each iteration bool snake_move_player( pos head ) { attrset( COLOR_PAIR( 1 ) ) ; // Check if we ran into ourself int idx = snake_cooridinate_to_index( head ); if( spaces[idx] ) snake_game_over( ); spaces[idx] = true; // Mark the space as occupied enqueue( head );//Inserting at the end of a linked list, returning head of list g_score += 10; // Check if we're eating the fruit if( head.x == fruit.x && head.y == fruit.y ) { snake_draw_fruit( ); g_score += 1000; } else { // Handle the tail pos *tail = dequeue( ); spaces[snake_cooridinate_to_index( *tail )] = false; snake_write_text( tail->y, tail->x, " " ); } // Draw the new head snake_write_text( head.y, head.x, "S" ); // Update scoreboard char buffer[25]; sprintf( buffer, "%d", g_score ); attrset( COLOR_PAIR( 2 ) ); snake_write_text( g_height+1, 9, buffer ); return true; } int main( int argc, char *argv[] ) { int key = KEY_RIGHT; if( ( g_mainwin = initscr() ) == NULL ) {//initscr-создает окно курсес perror( "error initialising ncurses" );// для вывода ошибок exit( EXIT_FAILURE ); } // Set up srand( time( NULL ) ); noecho( ); curs_set( 2 ); halfdelay( 1 ); keypad( g_mainwin, TRUE ); g_oldcur = curs_set( 0 ); start_color( ); init_pair( 1, COLOR_RED, COLOR_BLACK ); init_pair( 2, COLOR_GREEN, COLOR_BLACK ); init_pair( 3, COLOR_YELLOW, COLOR_BLACK ); init_pair( 4, COLOR_BLUE, COLOR_BLACK ); init_pair( 5, COLOR_CYAN, COLOR_BLACK ); init_pair( 6, COLOR_MAGENTA, COLOR_BLACK ); init_pair( 7, COLOR_WHITE, COLOR_BLACK ); getmaxyx( g_mainwin, g_height, g_width );//Robot with colors g_width = g_width < DESIRED_WIDTH ? g_width : DESIRED_WIDTH; g_height = g_height < DESIRED_HEIGHT ? g_height : DESIRED_HEIGHT; // Set up the 2D array of all spaces spaces = (bool*) malloc( sizeof( bool ) * g_height * g_width );//memory allocation snake_draw_board( ); snake_draw_fruit( ); pos head = { 5,5 }; enqueue( head ); // Event loop while( 1 ) { int in = getch( ); if( in != ERR ) key = in; switch( key ) { case KEY_DOWN: case 'j': case 'J': case 's': case 'S': head.y++; break; case KEY_RIGHT: case 'l': case 'L': case 'd': case 'D': head.x++; break; case KEY_UP: case 'k': case 'K': case 'w': case 'W': head.y--; break; case KEY_LEFT: case 'h': case 'H': case 'a': case 'A': head.x--; break; } if( !snake_in_bounds( head ) ) snake_game_over( ); else snake_move_player( head ); } snake_game_over( ); }