/* Copyright (c) 2009, Keith Batten. Contactable at @batsocks.co.uk 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. Disclaimer This software is provided 'as is' without warranty of any kind. This software may not meet your requirements or expectations. This software may include mistakes, errors and inaccuracies. The copyright holder will not be liable for any damages arising from your use, or misuse, of this software. Use at your own risk. */ /* Batsocks Maze ============= A maze game for an Arduino with a transmit-capable TellyMate Shield. (Transmit-capable TellyMate shields are those labelled v1.1 or upwards, sold from 9th June 2009. They use firmware 1.0.9 or upward and have pin 3 of their processor connected to the Arduino's D0 pin) Verifying and uploading: ======================== This sketch uses the button debounce library. Download it from http://www.arduino.cc/playground/Code/Debounce Put the Debounce folder in "hardware\libraries\" of your Arduino directory. Input: ====== Buttons optional. The game will start moving the player's character automatically if no buttons are pressed after 15 seconds. However, if you want to interact and control your player, you need 4 buttons arranged as left/right/up/down, and two extras to control the brightness of your player's lamp. The pin assignments for the buttons were designed for use with the Batsocks 6 button shield, but can easily be adapted for use with buttons on other pins. Pins: Up, Down, Left, Right : D6, D3, D4, D5 Increase, Decrease brightness : D7, D3 The buttons are normally open and connect to ground when closed. Serial data is received on D0 (RX), sent from the TellyMate shield. Output: ======= Serial data is sent to the TellyMate shield on D1 (TX). The TellyMate Shield shows the results on a PAL or NTSC TV. Instructions: ============= Explore the maze and collect treasure. Watch out for the monster! If the monster bumps into you - it will steal a piece of treasure. After 15 seconds without a button press, the Arduino will get bored and move your player around itself. You can regain control at any time. The monster follows the right-hand wall. Other documentation: ==================== For documentation on all the control sequences that the TellyMate can use, please see... http://www.batsocks.co.uk/products/Other/TellyMate_UserGuide.htm */ #include "Debounce.h" // Information about a player typedef struct { int score; // treasure count byte posx; // column byte posy; // row byte facing; // direction they're heading boolean automove; // does this player need a computer to move it } t_player; // Two players. One human, one monster. #define HUMAN 0 #define MONSTER 1 // store the two players data here t_player players[2] ; // Directions // Clockwise from up #define DIR_UP 0 #define DIR_RIGHT 1 #define DIR_DOWN 2 #define DIR_LEFT 3 // Drawing stuff #define CHAR_WALL_BLACK '\xFF' #define CHAR_WALL_DGREY '\xB0' #define CHAR_WALL_MGREY '\xB1' #define CHAR_WALL_LGREY '\xB2' #define CHAR_WALL_WHITE '\xDB' #define CHAR_MONSTER1 'C' #define CHAR_MONSTER2 'c' #define CHAR_CRUMB '\x20' #define CHAR_TREASURE '\x0F' #define CHAR_STAIR '\xF0' #define CHAR_UPARROW '\x1E' #define CHAR_DOWNARROW '\x1F' #define CHAR_LEFTARROW '\x11' #define CHAR_RIGHTARROW '\x10' #define CHAR_PLAYER '\x01' #define CHAR_PATH ' ' // TellyMate stuff #define BAUD_RATE 57600 #define CHAR_ESC '\x1B' #define CHAR_DLE '\x10' #define CHAR_CURSORUP 'A' #define CHAR_CURSORDOWN 'B' #define CHAR_CURSORRIGHT 'C' #define CHAR_CURSORLEFT 'D' // Maze stuff // Leave a line for the scores at the top #define MAZE_MIN_Y 1 #define MAZE_MAX_Y 25 #define MAZE_MIN_X 0 #define MAZE_MAX_X 38 // Button stuff Debounce debounce_up = Debounce( 15, 6 ) ; Debounce debounce_down = Debounce( 15, 3 ) ; Debounce debounce_left = Debounce( 15, 4 ) ; Debounce debounce_right = Debounce( 15, 5 ) ; Debounce debounce_A = Debounce( 15, 7 ) ; Debounce debounce_B = Debounce( 15, 2 ) ; // Arrays related to directions static char cursormoves[4] = {CHAR_CURSORUP, CHAR_CURSORRIGHT, CHAR_CURSORDOWN, CHAR_CURSORLEFT} ; static char arrows[4] = {CHAR_UPARROW, CHAR_RIGHTARROW, CHAR_DOWNARROW, CHAR_LEFTARROW} ; // Find A Space stuff #define FAS_HUMAN HUMAN #define FAS_MONSTER MONSTER #define FAS_ITEM MONSTER+1 // Lighting stuff #define BRIGHTNESS_MAX 100 #define BRIGHTNESS_MIN 0 #define LIGHTER 1 #define DARKER 2 byte brightness = 36 ; // Game stuff int Level = 0 ; // How many milliseconds between each human step #define HUMAN_SPEED 100 // How many milliseconds between each monster step #define MONSTER_SPEED 173 // How many human steps to wait // before the arduino moves the human player #define AUTO_MOVE_DELAY 150 // So we can see if it's time to move the players long human_timeStamp = 0; long monster_timeStamp = 0; /* ################################# */ void setup() { init_tellymate() ; init_buttons() ; init_players(); init_new_level() ; } void loop() { // update the button debouncing debounce_up.update(); debounce_down.update(); debounce_left.update(); debounce_right.update(); debounce_A.update(); debounce_B.update(); if (millis() - human_timeStamp > HUMAN_SPEED) { human_timeStamp = millis(); // It's time for the human to move handle_input(); // read the keys and move if ( players[HUMAN].automove ) { // human player has gone to sleep. Move for them. follow_wall(HUMAN); } // make the monster chomp even though it may not be time for them to move if ( players[MONSTER].automove ){ cursor_move(players[MONSTER].posy,players[MONSTER].posx); show_player(MONSTER,DIR_UP); } } if (millis() - monster_timeStamp > MONSTER_SPEED) { monster_timeStamp = millis(); // It's time for the monster to move if ( players[MONSTER].automove ) { // make the monster run about. follow_wall(MONSTER); } } } /* ################################# */ void init_players() { players[HUMAN].score = 0; players[HUMAN].posx = 0; players[HUMAN].posy = 0; players[HUMAN].facing = 0; players[HUMAN].automove = false; players[MONSTER].score = 0; players[MONSTER].posx = 0; players[MONSTER].posy = 0; players[MONSTER].facing = 0; players[MONSTER].automove = true; } void init_tellymate() { // set up transmission Serial.begin(BAUD_RATE) ; // let the tellymate talk back to us // so we can see what a player steps on transmit_enable(); cursor_off(); screen_clear(); } void init_buttons() { pinMode( 2, INPUT ); pinMode( 3, INPUT ); pinMode( 4, INPUT ); pinMode( 5, INPUT ); pinMode( 6, INPUT ); pinMode( 7, INPUT ); // turn on pull-up resistors digitalWrite( 2, HIGH ); digitalWrite( 3, HIGH ); digitalWrite( 4, HIGH ); digitalWrite( 5, HIGH ); digitalWrite( 6, HIGH ); digitalWrite( 7, HIGH ); } void init_new_level() { screen_clear() ; if (Level++ == 0) { show_title(" Maze", 0) ; } else { show_title(" Level ", Level) ; } // hide the screen while we're drawing everything screen_show(false); { show_maze(); show_scores(); for (int i=0; i<13; i++) { // add some treasure find_a_space(FAS_ITEM); show_char( CHAR_TREASURE ); } find_a_space(FAS_ITEM); // for the stairs show_char( CHAR_STAIR ); find_a_space(FAS_MONSTER); // for the monster show_player(MONSTER,DIR_UP); players[MONSTER].automove = true ; // let it move find_a_space(FAS_HUMAN); // for the player show_player(HUMAN, DIR_UP); show_light(players[HUMAN].posx,players[HUMAN].posy); } // now it's all drawn, show the screen screen_show(true); } /* ################################# */ void handle_input() { boolean button_press = false; static int countdown_to_automove = AUTO_MOVE_DELAY; // is the up button pressed? if (debounce_up.read()==0) { player_move(HUMAN, DIR_UP) ; button_press = true ; } // is the down button pressed? if (debounce_down.read()==0) { player_move(HUMAN, DIR_DOWN) ; button_press = true ; } // is the left button pressed? if (debounce_left.read()==0) { player_move(HUMAN, DIR_LEFT) ; button_press = true ; } // is the right button pressed? if (debounce_right.read()==0) { player_move(HUMAN, DIR_RIGHT) ; button_press = true ; } // is the A button pressed? if (debounce_A.read()==0) { change_brightness(LIGHTER); // button_press = true ; } // is the B button pressed? if (debounce_B.read()==0) { change_brightness(DARKER); // button_press = true ; } if (button_press){ // reset the automove countdown countdown_to_automove = AUTO_MOVE_DELAY ; if (players[HUMAN].automove == true){ // turn automove off players[HUMAN].automove = false; show_auto(false) ; } } if (countdown_to_automove==0){ // We've waited long enough if (players[HUMAN].automove == false) { // turn automove on players[HUMAN].automove = true; show_auto(true); } } else { // automove is off. Wait some more. countdown_to_automove -= 1 ; } } #define TURN(x,y) ((x+y)&3) // from the direction x, make y right angle turns clockwise // so turn(0,-1) will turn from 0 one right angle anticlockwise. #define TURN_LEFT -1 #define TURN_RIGHT 1 #define TURN_BACK 2 void follow_wall(byte this_player) { byte try_dir ; byte old_dir = players[this_player].facing ; // HUMAN player follows the left hand wall. // MONSTER player follows the right hand wall. byte first_turn = (this_player==HUMAN) ? TURN_LEFT : TURN_RIGHT ; byte second_turn = (this_player==HUMAN) ? TURN_RIGHT : TURN_LEFT ; // Try first turn. try_dir = TURN(old_dir,first_turn); if ( !player_move( this_player, try_dir ) ){ // First turn didn't work. Try straight on. try_dir = old_dir ; //straight on if ( !player_move( this_player, try_dir ) ){ // Straight on didn't work. Try the second turn try_dir = TURN(old_dir,second_turn); if ( !player_move( this_player, try_dir ) ){ // The second turn didn't work. Only option is backwards. try_dir = TURN(old_dir,TURN_BACK); player_move( this_player, try_dir ) ; //if that didn't work, we're stuck in a hole! } } } players[this_player].facing = try_dir ; } void change_brightness(byte change) { if (change==LIGHTER) brightness = (brightness==BRIGHTNESS_MAX)?BRIGHTNESS_MAX:brightness+1; else brightness = (brightness==BRIGHTNESS_MIN)?BRIGHTNESS_MIN:brightness-1; } /* ################################# */ boolean player_move(byte this_player, byte direction) { // returns true if the player moves in the given direction char under_next_footstep = 0 ; boolean player_moved = false ; cursor_move(players[this_player].posy, players[this_player].posx); cursor_direction( direction ); under_next_footstep = (char)cursor_read(); if (under_next_footstep == CHAR_TREASURE) { players[this_player].score++; show_scores(); } if (under_next_footstep == CHAR_STAIR){ under_next_footstep = CHAR_WALL_BLACK; // stops a step taking place if ( this_player==HUMAN ) { init_new_level() ; } else { // this_player is a monster cursor_move(players[this_player].posy, players[this_player].posx); show_char(CHAR_CRUMB); //erase the monster players[MONSTER].automove = false; //stop the monster moving - removes it from this level player_moved = true; //well it has, hasn't it! } } if (is_a_player(under_next_footstep)){ // walking into a player. under_next_footstep = CHAR_WALL_BLACK; // stops a step taking place if ( this_player==MONSTER ) { // monsters steal treasure if ( players[HUMAN].score > 0 ){ players[HUMAN].score--; players[MONSTER].score++; show_scores(); } } } if ( !is_a_wall(under_next_footstep) ) { cursor_move(players[this_player].posy, players[this_player].posx); show_char(CHAR_CRUMB); // print breadcrumb player_moved = true ; } if (player_moved){ // update the player position switch ( direction ) { case 0: players[this_player].posy -= 1 ; break; case 1: players[this_player].posx += 1 ; break; case 2: players[this_player].posy += 1 ; break; case 3: players[this_player].posx -= 1 ; break; } show_player(this_player, direction); } return player_moved ; } boolean is_a_wall(char x) { //returns true if the char is any of the wall characters. switch( x ){ case CHAR_WALL_BLACK : case CHAR_WALL_DGREY : case CHAR_WALL_MGREY : case CHAR_WALL_LGREY : case CHAR_WALL_WHITE : // add extra case statements here if there are other wall characters... return(true); break; default: return(false); break; } return(false); } boolean is_a_player(char x) { //returns true if the char is any of the player characters. switch( x ){ case CHAR_UPARROW : case CHAR_DOWNARROW : case CHAR_LEFTARROW : case CHAR_RIGHTARROW : case CHAR_PLAYER : case CHAR_MONSTER1 : case CHAR_MONSTER2 : // add extra case statements here if there are other player characters... return(true); break; default: return(false); break; } return(false); } void find_a_space(byte item) { // find a space in the maze int try_here = CHAR_WALL_BLACK ; byte try_x = 0 ; byte try_y = 0 ; // keep trying different places until we find a space... while( !(try_here == CHAR_PATH) ) { try_x = random( MAZE_MIN_X+1,MAZE_MAX_X-1 ) ; try_y = random( MAZE_MIN_Y+1,MAZE_MAX_Y-1 ) ; cursor_move( try_y, try_x ); try_here = cursor_read() ; } if ( item == FAS_HUMAN ) { // update the player positions players[HUMAN].posx = try_x ; players[HUMAN].posy = try_y ; } if ( item == FAS_MONSTER ) { // update the player positions players[MONSTER].posx = try_x ; players[MONSTER].posy = try_y ; } } /* ################################# */ // helper functions to print stuff on the screen void show_char(char x) { if (x < 32) Serial.print(CHAR_DLE); Serial.print(x); } void show_player(int this_player, int direction) { static boolean chomp_toggle = true; if ( (this_player==MONSTER) and players[MONSTER].automove) { // only show the monster if it's being moved. // if it's not being moved, then it's left this level via the stairs. cursor_move( players[this_player].posy, players[this_player].posx ); if ( chomp_toggle ) { show_char( CHAR_MONSTER1 ); }else{ show_char( CHAR_MONSTER2 ); } chomp_toggle = !chomp_toggle; } if ( this_player==HUMAN ) { cursor_move( players[this_player].posy, players[this_player].posx ); if (players[HUMAN].automove) { show_char( arrows[direction] ) ; } else { show_char(CHAR_PLAYER); // print player } show_light( players[this_player].posx, players[this_player].posy ); } } // How far will the light shine. #define LAMP_DIA 7 #define LAMP_RAD 3 void show_light(int x, int y) { // illuminate the maze around x,y static byte distance [LAMP_DIA][LAMP_DIA] = {{25,25,25,25,25,25,25}, {25,23,18,16,18,23,25}, {25,18,11,8,11,18,25}, {25,16,8,0,8,16,25}, {25,18,11,8,11,18,25}, {25,23,18,16,18,23,25}, {25,25,25,25,25,25,25}} ; static unsigned char lamp [4] = {CHAR_WALL_WHITE,CHAR_WALL_LGREY,CHAR_WALL_DGREY,CHAR_WALL_BLACK} ; for ( byte lamp_x = 0 ; lamp_x < LAMP_DIA ; lamp_x ++ ) { for ( byte lamp_y = 0 ; lamp_y < LAMP_DIA ; lamp_y ++ ) { // for each point in the lamplight... // see if we're on the screen // move the cursor // if that char is a wall, then print the char from lamp if ( ( (x + lamp_x - LAMP_RAD) >= MAZE_MIN_X ) && ( (x + lamp_x - LAMP_RAD) <= MAZE_MAX_X ) && ( (y + lamp_y - LAMP_RAD) >= MAZE_MIN_Y ) && ( (y + lamp_y - LAMP_RAD) <= MAZE_MAX_Y ) ) { // Whew. (lamp_x, lamp_y) is on the screen. cursor_move( ( ( lamp_y - LAMP_RAD ) + y ), ( ( lamp_x - LAMP_RAD ) + x ) ); int this_block = cursor_read(); if ( is_a_wall( this_block ) ) { // it's a wall. So show display the char from lamp[]. int this_bright = map(distance[lamp_x][lamp_y],0,brightness,0,3); this_bright = constrain( this_bright, 0, 3 ); show_char( lamp[this_bright] ); } } } } } void show_maze() { cursor_move(MAZE_MIN_Y,MAZE_MIN_X) ; //there should be space for the scores printmaze(); } void show_title( char* title, int level ) { // shows a title cursor_move(7,0) ; Serial.print( CHAR_ESC ); Serial.print( "_4") ; // Large text, top half Serial.print( title ) ; if (level>0) Serial.print( level ) ; Serial.println(); Serial.print( CHAR_ESC ); Serial.print( "_5") ; // Large text, bottom half Serial.print( title ) ; if (level>0) Serial.println( level ) ; delay(1500) ; screen_clear(); } void show_scores() { // shows the scores cursor_move(0,0) ; Serial.print( "Player:"); Serial.print( players[HUMAN].score ); Serial.print(" "); cursor_move(0,12); Serial.print( "Monster:"); Serial.print( players[MONSTER].score ); Serial.print(" "); cursor_move(0,26); Serial.print( "MAZE"); } void show_auto(boolean show) { //shows 'Auto-move' at the top of the screen. Or not. cursor_move(0, 33) ; if ( show ) { Serial.print("Auto") ; } else { Serial.print(" ") ; } } /* ################################# */ // TellyMate helper functions void cursor_off( void ) { Serial.print( CHAR_ESC ) ; Serial.print( 'f' ) ; } void cursor_direction( char direction ) { Serial.print( CHAR_ESC ); Serial.print( cursormoves[direction] ); } int cursor_read( void ) { // read the character under the TellyMate's cursor int result ; result = -1 ; // default result. Serial.print( CHAR_ESC ); Serial.print( '|' ) ; // ask for character under cursor delayMicroseconds( 20 * (1000000 / BAUD_RATE )) ; // give the tellymate some time to reply for( uint8_t i = 0 ; i < 30 ; i++ ) { if (Serial.available() > 0) { result = Serial.read() ; break ; } delayMicroseconds( 1000000 / BAUD_RATE ) ; // approximately one bit duration } // If no character is received after 50 bit durations, the default value of -1 is returned. return result ; } void cursor_move( byte row , byte col ) { // moves the cursor Serial.print( CHAR_ESC ); Serial.print( 'Y' ) ; Serial.print((unsigned char)(32 + row)) ; Serial.print((unsigned char)(32 + col)) ; } void cursor_save() { // saves the current cursor position Serial.print( CHAR_ESC ); Serial.print( 'j') ; } void cursor_restore() { // restores a saved cursor postition Serial.print( CHAR_ESC ); Serial.print( 'k') ; } void screen_show( boolean choice ) { // shows or hides the screen Serial.print(CHAR_ESC); Serial.print( choice ? 'y' : 'x' ); Serial.print(':'); } void screen_clear() { //clears the screen Serial.print( CHAR_ESC ); Serial.print( 'E' ) ; } void transmit_enable() { // let the tellymate talk back to us Serial.print( CHAR_ESC ) ; for ( byte i = 0 ; i++ < 4 ; Serial.print( '~' ) ) Serial.flush() ; } /* ################################# */ // Maze functions #define MAZE_ROWCOUNT (((MAZE_MAX_Y - MAZE_MIN_Y)-2)/2) #define MAZE_COLCOUNT (((MAZE_MAX_X - MAZE_MIN_X)-2)/2) #define V_THRESHOLD 500 #define H_THRESHOLD 500 /* Crude maze drawing using Eller's Algorithm. See http://www.astrolog.org/labyrnth/algrithm.htm */ void printmaze( void ) { byte mazerow[ MAZE_COLCOUNT ] ; // initialise the mazerow to all 0s... for( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++ ){ mazerow[i] = 0; } ; // Top outer wall Serial.print( CHAR_WALL_BLACK ); // left outer wall for( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++){ show_char( CHAR_WALL_BLACK ) ; show_char( CHAR_WALL_BLACK ) ; } Serial.println(); for( uint8_t row = 0 ; row < ( MAZE_ROWCOUNT - 1 ) ; row++ ) { mazerow_normalise( mazerow ) ; mazerow_horizontaldrill( mazerow, false ) ; mazerow_verticaldrill( mazerow ) ; } // last row in the maze mazerow_normalise( mazerow ) ; mazerow_horizontaldrill( mazerow, true ) ; // Bottom outer wall show_char( CHAR_WALL_BLACK ); // left outer wall for( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++){ show_char( CHAR_WALL_BLACK ) ; show_char( CHAR_WALL_BLACK ) ; } } void mazerow_verticaldrill( byte maze[] ) { // left-hand wall show_char( CHAR_WALL_BLACK ); for ( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++ ) { uint8_t thiscell = maze[i] ; uint8_t setsize = 0; // count how many cells are in this set... for( uint8_t ii = 0 ; ii < MAZE_COLCOUNT ; ii++ ) { if (maze[ii] == thiscell) setsize++ ; } if (setsize == 1) { // there is only one cell in this set. it MUST drill down to the next row. show_char( CHAR_PATH ) ; show_char( CHAR_WALL_BLACK ) ; } else { if (random(1000) > V_THRESHOLD) { // we're drilling down. show_char( CHAR_PATH) ; show_char( CHAR_WALL_BLACK ) ; } else { // we're not drilling down. show_char( CHAR_WALL_BLACK ) ; show_char( CHAR_WALL_BLACK ) ; maze[i] = 0 ; // put this cell in a 'special' set. // note that doing this has the side effect that if no cells in a set // have been drilled down, then the last cell will have a setsize of 1, hence // will be drilled down. This has a right-wards bias, but it does mean all // sections of the maze will be accessible. // Future improvements might make this 'must drill down' more evenly spread. } } } // the right-hand wall will already have been output. Serial.println(""); } void mazerow_horizontaldrill( byte maze[], boolean lastrow ) { // draw left hand wall show_char( CHAR_WALL_BLACK ) ; for ( uint8_t i = 0 ; i < (MAZE_COLCOUNT - 1) ; i++ ) { byte thiscell = maze[i]; byte nextcell = maze[i+1]; if (thiscell == nextcell) { // the next cell is already in the same set. I cannot drill through to it, as it would create a loop in the maze. show_char( CHAR_PATH ) ; show_char( CHAR_WALL_BLACK ) ; } else { // the next cell is in a different set - should they be joined? if ( (lastrow == true) || (random(1000) > H_THRESHOLD)) { // YES! drill through the rock... thiscell and nextcell should be merged into being the same set! for ( uint8_t ii = 0 ; ii < (MAZE_COLCOUNT) ; ii++ ) { if (maze[ii]==thiscell) maze[ii] = nextcell ; } show_char( CHAR_PATH ) ; show_char( CHAR_PATH ) ; } else { // NO, fate has determined that these sets shouldn't be joined here... show_char( CHAR_PATH ) ; show_char( CHAR_WALL_BLACK ) ; } } } // draw right-hand wall show_char( CHAR_PATH ); show_char( CHAR_WALL_BLACK ); Serial.println(); } void mazerow_normalise( byte maze[] ) { // clear the top bit of every cell... for ( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++ ){ maze[i] &= 0b01111111 ; } // I'm using the top bit to mark a cell as 'renumbered' for ( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++ ) { if ( maze[i]==0) { // 0 indicates that this is a new set. maze[i] = (i + 1) | 0b10000000 ; } else { // has this cell already been renumbered? if (!( maze[i] & 0b10000000)) { // this cell needs renumbering // and renumber any other cells in the same set... for (uint8_t ii = i + 1 ; ii < MAZE_COLCOUNT ; ii++ ) { if ( maze[ii] == maze[i] ) { maze[ii] = (i+1) | 0b10000000 ; } } maze[i] = (i+1) | 0b10000000 ; } } } // clear the top bit of every cell again - they've all been renumbered... // only the numbers 1 to MAZE_COLCOUNT are now used in the array. for ( uint8_t i = 0 ; i < MAZE_COLCOUNT ; i++ ){ maze[i] &= 0b01111111; } }