training

Code I wrote during training
git clone git://git.bitsmanent.org/training
Log | Files | Refs | README

commit 1b195e5460cb4e090fca849e0c2bd968a4f18fa1
parent 44ba1c22f3de9059cc82a86096c361b8209f4cce
Author: Claudio Alessi <smoppy@gmail.com>
Date:   Fri, 26 Oct 2012 19:50:22 +0200

Initial commit.

Diffstat:
Amazegen.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aworm2.1.c | 472+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 720 insertions(+), 0 deletions(-)

diff --git a/mazegen.c b/mazegen.c @@ -0,0 +1,248 @@ +/* + * Maze generator - Implements the Deep-First Search algorithm + * + * Copyright (C) 2007-2010 Claudio M. Alessi + * All rights are reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#define N (1<<3) /* North */ +#define S (1<<2) /* South */ +#define W (1<<1) /* West */ +#define E (0x01) /* East */ +#define A (N|S|W|E) /* All the above */ + +#define BORDERS 12 /* Unused */ +#define WALLS 8 +#define SOLUTION 4 /* Unused */ +#define BACKTICK 0 /* Unused */ + +#define ROWS 20 +#define COLS 20 + +#define ISSET(C, W) (W == (C & W)) + +/* globals */ +int rows, cols; + +/* function declarations */ +void maze_gen(short int *grid, int TotalCells); +void maze_open(short int *grid); +int nextcell(short int *grid, int cell); +void pulldown(short int *grid, int CurrentCell, int cell); +void push(int *stack, int *top, int cell); +int pop(int *stack, int *top); +void maze_show(short int *grid); + +/* function implementations */ +int +main(int argc, char *argv[]) { + short int *grid; + int c; + + rows = ROWS; + cols = COLS; + + while((c = getopt(argc, argv, "c:r:hv")) != -1) { + switch(c) { + case 'v': + printf("© 2007-2010 Claudio M. Alessi\n"); + return 0; + break; + case 'c': + cols = atoi(optarg); + break; + case 'r': + rows = atoi(optarg); + break; + case 'h': + printf( + "Usage: %s -<hV> [-c cols] [-r rows]\n" + "\nOptions\n" + " -r rows\t: set the rows (default: %d)\n" + " -c cols\t: set the columns (default: %d)\n" + " -h\t: show this help\n" + " -V\t: show the version and exit\n" + "\n", + argv[0], ROWS, COLS); + return 1; + break; + default: + printf("Usage: %s -<hV> [-c cols] [-r rows]\n", argv[0]); + return 1; + } + } + + if(rows <= 0|| cols <= 0) { + fprintf(stderr, "%s: invalid maze size (columns or rows)\n", argv[0]); + return 1; + } + + if((grid = malloc(rows * cols * sizeof(short int))) == NULL) { + fprintf(stderr, "Sorry, there is not enough memory available.\n"); + return 1; + } + + srandom(time(NULL)); + memset(grid, '\0', rows * cols); + + maze_gen(grid, rows * cols); + maze_open(grid); + maze_show(grid); + + free(grid); + + return 0; +} + +void +maze_open(short int *grid) { + int i; + + for(i = 0; i < 2; i++) { + switch(1 + random() % 4) { + case 1: /* north */ + grid[random() % cols] ^= N << WALLS; + break; + case 2: /* south */ + grid[cols * (rows - 1) + (random() % cols)] ^= S << WALLS; + break; + case 3: /* east */ + grid[(random() % rows) * cols + (cols - 1)] ^= E << WALLS; + break; + case 4: /* west */ + grid[(random() % rows) * cols] ^= W << WALLS; + break; + } + } +} + +void +push(int *stack, int *top, int cell) { + stack[(*top)++] = cell; +} + +int +pop(int *stack, int *top) { + if(! *top) { + printf("The stack is empty.\n"); + return 0; + } + + return stack[--(*top)]; +} + +void +maze_gen(short int *grid, int TotalCells) { + int CurrentCell = random() / (RAND_MAX / TotalCells + 1); + int VisitedCells = 1; + int AdCell; /* Adiacent cell */ + int *stack, top = 0; + int i; + + if(! (stack = malloc(sizeof(int) * TotalCells))) + return; + + for(i = 0; i < rows * cols; i++) + grid[i] = A << WALLS; + + while(VisitedCells < TotalCells) { + if((AdCell = nextcell(grid, CurrentCell)) != -1) { + pulldown(grid, CurrentCell, AdCell); + + push(stack, &top, CurrentCell); + CurrentCell = AdCell; + ++VisitedCells; + } + else + CurrentCell = pop(stack, &top); + } +} + +int +nextcell(short int *grid, int cell) { + int idx = 0, cells[4] = {0}; + + /* TODO: cleanup this code */ + + if(cell % cols && cell - 1 >= 0 && ISSET(grid[cell - 1], A << WALLS)) + cells[idx++] = cell - 1; + + if((cell % cols) != (cols - 1) && + cell + 1 < rows * cols && ISSET(grid[cell + 1], A << WALLS)) + cells[idx++] = cell + 1; + + if(cell - cols >= 0 && ISSET(grid[cell - cols], A << WALLS)) + cells[idx++] = cell - cols; + + if(cell + cols < rows * cols && ISSET(grid[cell + cols], A << WALLS)) + cells[idx++] = cell + cols; + + return ! idx ? -1 : cells[random() / (RAND_MAX / idx + 1)]; +} + +void +pulldown(short int *grid, int CurrentCell, int cell) { + + /* Note: I have to pull down the walls in both CurrentCell and cell in + * order be make showmaze() works properly. */ + + if(CurrentCell == cell - 1) { + grid[CurrentCell] ^= E << WALLS; + grid[cell] ^= W << WALLS; + } + + else if(CurrentCell == cell + 1) { + grid[CurrentCell] ^= W << WALLS; + grid[cell] ^= E << WALLS; + } + + else if(CurrentCell < cell) { + grid[CurrentCell] ^= S << WALLS; + grid[cell] ^= N << WALLS; + } + + else if(CurrentCell > cell) { + grid[CurrentCell] ^= N << WALLS; + grid[cell] ^= S << WALLS; + } + +} + +void +maze_show(short int *grid) { + int i; + + printf(" "); + for(i = 0; i < cols; i++) + printf("%c%c", ISSET(grid[i], N << WALLS) ? + '_' : ' ', (i == cols - 1 ? ' ' : '_')); + + for(i = 0; i < rows * cols; i++) { + if(!(i % cols)) { + printf("\n%c", ISSET(grid[i], W << WALLS) ? '|' : ' '); + } + + printf("%c%c", + ISSET(grid[i], S << WALLS) ? '_' : ' ', + ISSET(grid[i], E << WALLS) ? '|' : '_'); + } + + printf("\n"); + +} diff --git a/worm2.1.c b/worm2.1.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2006 + * Claudio M. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * TODO + * o fix: eat the numbers with the body too + * o fix: eat the numbers from any digit + * o fix: the numbers with 2 digits are out of borders + * o Create the '?' key which show the help and the commands + * o Ehm.. ehm.. Add the colors :-) Any volunteer? +*/ + +#include <stdio.h> +#include <curses.h> +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define HEAD 'o' /* normal head */ +#define WORM 'w' /* worm's body */ +#define EATH 'O' /* eating head */ + +#define MINROW 21 +#define MINCOL 80 + +#define LEVEAT 5 /* Food eated befor to increment the level */ +#define LEVMAX 9 /* Max speed (to preserve the refresh delay in auto-mode) */ + +/* Recursive list */ +typedef struct list_t { + int x; + int y; + struct list_t *next; +} List; + +/* Routes */ +enum { R_UP = 1, R_LEFT, R_DOWN, R_RIGHT } route; + +/* + * Prototypes +*/ +void newnode(List **listp, int y, int x); +void wormshow(List *worm, char ch, char chhead); +void moveworm(List **worm, int way); +int isout(List *worm); +int isbite(List *worm); +int iseat(List *worm, int row, int col); +void killworm(List **worm); + +/* The main function */ +int main(int argc, char **argv) +{ + int ch = 0, n, eating, trick = 0; + int erow, ecol; /* eat position */ + int level, tricks, moves, score; + + WINDOW *wstat, *wpos, *wepos; /* Status and positions windows */ + List *worm = NULL, *current; /* THe LiST */ + + int auto_mode = 0; /* Play without user interaction */ + + level = tricks = moves = score = 0; + srand( time(NULL) ); + + /* check the flag for auto-mode */ + if( argc == 2 && argv[1][0] == '-' && argv[1][1] == 'a' ) + auto_mode = 1; + + initscr(); /* start of session */ + curs_set(0); /* hide the cursor */ + keypad(stdscr, TRUE); /* enable the function keys */ + cbreak(); + noecho(); + nodelay(stdscr, TRUE); /* unlock getch(3) */ + + /* Check the terminal size */ + if( LINES < MINROW || COLS < MINCOL ) { + endwin(); + printf("This game require a terminal size of %dx%d pixel.\n", + MINROW, MINCOL); + printf("Your terminal size is: %dx%d\n", LINES, COLS); + return -1; + } + + /* Create the windows */ + wstat = subwin(stdscr, 3, COLS - COLS / 3, 2, COLS / 6); /* status */ + wpos = subwin(stdscr, 3, 9, 2, 3); /* worm position */ + wepos = subwin(stdscr, 3, 9, 2, COLS - 9 - 3); /* eat position */ + + /* Add the first position */ + newnode(&worm, 1 + rand() % (COLS - 2), 6 + rand() % (LINES - 7)); + + /* start point for the eat */ + erow = 6 + rand() % (LINES - 7); + ecol = 1 + rand() % (COLS - 2); + + /* choose a random route */ + route = 1 + rand() % 4; + + wormshow(worm, WORM, HEAD); /* put the first WORM */ + mvprintw(erow, ecol, "%d", n = 1); /* put the first eat */ + + /* main loop */ + while( (auto_mode ? getch() : (ch = getch())) != 'q' ) { + /* + * Auto-mode play + * + * NOTE: the worm can to bite himself losing the + * game which will be auto-restarted again. + * + */ + if( auto_mode ) { + ch = 0; /* don't touch the user moves */ + + /* choose the route, if needed */ + if( worm->x < erow ) { + if( route != R_DOWN ) + ch = 'j'; + } + else if( worm->x > erow ) { + if( route != R_UP ) + ch = 'k'; + } + else if( worm->y < ecol ) { + if( route != R_RIGHT ) + ch = 'l'; + } + else { + if( route != R_LEFT ) + ch = 'h'; + } + } + + switch(ch) { + case 'h': + case KEY_LEFT: + route = R_LEFT; + ++moves; + break; + case 'j': + case KEY_DOWN: + route = R_DOWN; + ++moves; + break; + case 'k': + case KEY_UP: + route = R_UP; + ++moves; + break; + case 'l': + case KEY_RIGHT: + route = R_RIGHT; + ++moves; + break; + case 'p': + case ' ': /* space bar */ + /* Pause */ + nodelay(stdscr, FALSE); /* lock the getch() */ + + mvprintw(LINES / 2, COLS / 2, "Pause!"); + while( (ch = getch()) ) { + if( ch == 'p' || ch == ' ' ) + break; + + clear(); + mvprintw(LINES / 2, COLS / 2, "Pause!"); + } + + nodelay(stdscr, TRUE); /* unlock the getch() */ + clear(); + + break; + case 't': /* Tricks */ + if( trick ) { + nodelay(stdscr, TRUE); + trick = 0; + } + else { + nodelay(stdscr, FALSE); + trick = 1; + ++tricks; + } + break; + case KEY_RESIZE: /* Terminal resize */ + nodelay(stdscr, FALSE); + + /* Check the terminal size */ + while( LINES < MINROW || COLS < MINCOL ) { + clear(); + mvprintw(LINES / 2, COLS / 2 - 12, "Terminal size too small!"); + mvprintw(LINES / 2 + 1, COLS / 2 - 16, + "Please, enlarge it and press a key"); + getch(); + } + + nodelay(stdscr, TRUE); + clear(); + + break; + } /* eof switch() */ + moveworm(&worm, route); /* move the worm */ + + /* + * Check if the "new" position is already + * busy or it's out of the window. + */ + if( isout(worm) || isbite(worm) || (auto_mode && level >= LEVMAX) ) { + + if( level >= LEVMAX ) + mvprintw(LINES / 2, COLS / 2 - 5, "Too fast!"); + else + mvprintw(LINES / 2, COLS / 2 - 5, "You lose!"); + + mvprintw(LINES / 2 + 1, COLS / 2 - 10, "Your scores are: %.3d", score); + + if( auto_mode ) { + mvprintw(LINES / 2 + 3, COLS / 2 - 6, "Restarting.."); + refresh(); + + /* reset the game */ + killworm(&worm); + newnode(&worm, 1 + rand() % (COLS - 2), 6 + rand() % (LINES - 7)); + erow = 6 + rand() % (LINES - 7); + ecol = 1 + rand() % (COLS - 2); + score = level = eating = tricks = moves = 0; + n = 1; + + sleep(2); /* leave that the user tastes the messsage :-) */ + continue; + } + else { + mvprintw(LINES / 2 + 2, COLS / 2 - 10, "Press a key to exit.."); + + nodelay(stdscr, FALSE); + getch(); /* wait for input */ + + break; + } + } + + eating = n; /* needed for the wormshow() call */ + + /* If it's eating */ + while( iseat(worm, erow, ecol) ) { + /* Add a node on the top of worm (new head) */ + current = worm; + while( current->next != NULL ) + current = current->next; + newnode(&current->next, worm->y, worm->x); + + /* Change the eat's position */ + erow = 6 + rand() % (LINES - 7); + ecol = 1 + rand() % (COLS - 2); + ++n; /* Change the eat's number */ + + score += level + 1; /* increment the points */ + + /* Increase the level */ + if( !(n % LEVEAT) ) { + ++level; + } + } + + erase(); /* clear the screen */ + box(stdscr, ACS_VLINE, ACS_HLINE); /* create the borders */ + mvprintw(erow, ecol, "%d", n); /* draw the eat */ + + /* Show the status window (and its elemets) */ + mvwprintw(stdscr, 1, COLS / 2 - 37 / 2, /* Copy */ + "The Hermit worm - (C) 2006 Claudio M."); /* left */ + box(wstat, ACS_VLINE, ACS_HLINE); /* status box */ + mvwhline(stdscr, 5, 1, ACS_HLINE, COLS - 2); /* new top limit */ + + /* Show the worm position */ + box(wepos, ACS_VLINE, ACS_HLINE); /* status box */ + mvwprintw(stdscr, 1, 3, "Worm Curs"); + mvwprintw(wepos, 1, 2, "%.2dx%.2d", erow, ecol); + + /* Show the eat position */ + box(wpos, ACS_VLINE, ACS_HLINE); /* status box */ + mvwprintw(stdscr, 1, COLS - 12, "Eat Curs"); + mvwprintw(wpos, 1, 2, "%.2dx%.2d", worm->x, worm->y); + + /* Show the informations */ + mvwprintw(wstat, 1, 3, + "TS:%.2dx%.2d | " /* Terminal size */ + "SL:%.2d | " /* Speed level */ + "EM:%.2d | " /* Eats missing */ + "UM:%.3d | " /* User moves */ + "UT:%.2d | " /* User tricks */ + "Ss:%.3d", /* Scores */ + LINES, COLS, level + 1, LEVEAT - (n % LEVEAT), + moves, tricks, score); + + /* + * Show the whole "new" worm + * NOTE: this statement is not optimized - trash statement :-) + */ + if( iseat(worm, erow + 1, ecol) || iseat(worm, erow - 1, ecol) || + iseat(worm, erow, ecol + 1) || iseat(worm, erow, ecol - 1) ) { + wormshow(worm, WORM, EATH); + } + else + wormshow(worm, WORM, HEAD); + + usleep( 100000 - level * 10000 ); + } + + endwin(); /* end of session */ + + puts("\nEnd of game."); + + return 0; +} /* E0F main */ + +/* + * Returns if the worm is out of the window +*/ +int isout(List *worm) +{ + if( worm->x <= 5 || !worm->y || worm->x >= LINES - 1 || worm->y >= COLS - 1) + return 1; + + return 0; +} /* eof isout() */ + +/* + * Return if the worm is eating +*/ +int iseat(List *worm, int row, int col) +{ + return (worm->x == row && worm->y == col); +} /* eof iseat() */ + +/* + * Check if the worm is biting itself +*/ +int isbite(List *worm) +{ + List *current = worm; + + while( (current = current->next) != NULL ) { + if( worm->x == current->x && worm->y == current->y ) + return 1; + } + + return 0; +} /* eof isbite() */ + +/* + * Show the worm (call refresh(3)) +*/ +void wormshow(List *worm, char ch, char chhead) +{ + List *current = worm->next; + + /* show the worm */ + while( current != NULL ) { + mvprintw(current->x, current->y, "%c", ch); + current = current->next; + } + mvprintw(worm->x, worm->y, "%c", chhead); /* show the head */ + + refresh(); /* print the changes */ + +} /* eof wormshow() */ + +/* + * Add a new node to the list +*/ +void newnode(List **listp, int y, int x) +{ + List *newPtr; + + /* Allocate the memory */ + if( (newPtr = malloc( sizeof(List) )) == NULL ) { + printf("Not enough memory to allocate the \"%d.%d\" element\n", x, y); + return; + } + newPtr->next = *listp; + newPtr->x = x; + newPtr->y = y; + + *listp = newPtr; + +} /* eof newnode() */ + +/* + * Move the whole worm +*/ +void moveworm(List **worm, int way) +{ + List *current = *worm; + int n = 1, i; + + /* count the nodes */ + while( (current = current->next) != NULL ) + ++n; + + current = *worm; /* come back to the start point */ + while( --n ) { + + current = *worm; + i = n; + + while( --i ) + current = current->next; + + /* update the position */ + current->next->x = current->x; + current->next->y = current->y; + } + + /* move the head */ + switch(way) { + case R_UP: + --( *worm )->x; + break; + case R_LEFT: + --( *worm )->y; + break; + case R_DOWN: + ++( *worm )->x; + break; + case R_RIGHT: + ++( *worm )->y; + break; + } + +} /* eof moveworm() */ + +/* + * Kill the worm: free the whole worm's memory +*/ +void killworm(List **worm) +{ + List *current; + + while(*worm != NULL) { + current = *worm; + *worm = (*worm)->next; + free(current); + } + +} /* eof killworm() */ +