// TellyMateShield_Wanderers.pde // // 26 characters wander aimlessly around the screen without colliding // into themselves or the walls. // // Requires TellyMate Shield (1.1) as it reads characters from the TellyMate. // // Possibly useful as the start of a game? // Angband on an Arduino? ;o) #define BAUD_RATE 57600 #define CHAR_ESC "\x1B" // character 27 is #define CHAR_WALL '\xDB' // solid block // core setup and loop functions: void setup() { Serial.begin( BAUD_RATE ) ; // set to 57600 baud tellymate_cursor_show( false ) ; // hide the cursor tellymate_screen_clear() ; tellymate_enabletransmit() ; // allow the tellymate to control the Arduino's RX pin delay(10); // give the RX line time to clear. Serial.flush(); // ensure there's no junk left in the receive buffer wander_paintbackground(); // draw the border and 'maze' wander_people_init(); // teleport some players onto the screen } void loop() { wander_people_move(); delay(5) ; } // routines specific to this sketch void wander_paintbackground(){ tellymate_cursor_move( 0, 0 ) ; // draw the outer border... for( byte col = 0 ; col < 38 ; col++ ) { Serial.print( CHAR_WALL ) ; } for( byte row = 1 ; row < 24 ; row++ ) { tellymate_cursor_move( row , 0 ) ; Serial.print( CHAR_WALL ) ; tellymate_cursor_move( row , 37 ) ; Serial.print( CHAR_WALL ) ; } tellymate_cursor_move( 24, 0 ) ; for( byte col = 0 ; col < 38 ; col++ ) { Serial.print( CHAR_WALL ) ; } // sprinkle random blocks within the walls for some interest (woo!) for( int count = 0 ; count < 200 ; count++ ) { tellymate_cursor_move( random( 1, 24) , random( 1 , 37)) ; Serial.print( CHAR_WALL ) ; } } #define PERSON_COUNT 26 byte person_x[ PERSON_COUNT ] ; byte person_y[ PERSON_COUNT ] ; void wander_people_init(){ for( byte person_index = 0 ; person_index < PERSON_COUNT ; person_index++ ) { int c = CHAR_WALL ; // force this person to be re-positioned by the following while loop... // keep trying different places to teleport this person until a blank spot is found... // A blank is either a space or a (0). // (When the tellymate screen is cleared, it fills the screen with s, so they // may be returned by the cursor read function.) while( !((c == 0) || (c == ' ')) ) { person_x[ person_index ] = random(1 , 37) ; person_y[ person_index ] = random(1 , 23) ; tellymate_cursor_move( person_y[ person_index ] , person_x[ person_index ] ) ; c = tellymate_cursor_read() ; } // a blank spot has been found, so place the character here... Serial.print( (char)('A' + person_index) ) ; } } void wander_people_move(){ // move every player... for( byte person_index = 0 ; person_index < PERSON_COUNT ; person_index++ ) { byte x = person_x[ person_index ] ; byte y = person_y[ person_index ] ; tellymate_cursor_move( y , x ) ; // now move the cursor (using A-D) to where the person would like to move to... switch( random(1,5) ) { case 1: // attempt to move this player up... Serial.print( CHAR_ESC "A" ) ; y -= 1 ; break; case 2: // attempt to move this player down... Serial.print( CHAR_ESC "B" ) ; y += 1 ; break; case 3: // attempt to move this player right... Serial.print( CHAR_ESC "C" ) ; x += 1 ; break; case 4: // attempt to move this player left... Serial.print( CHAR_ESC "D" ) ; x -= 1 ; break; } int under_foot = tellymate_cursor_read() ; if ((under_foot == 0) || (under_foot == ' ')) { // the new position is clear! Put the person there... Serial.print( (char)('A' + person_index) ) ; // And then go and rub-out where the player *was*. tellymate_cursor_move( person_y[ person_index ] , person_x[ person_index ] ) ; Serial.print(' ') ; // now store the person's new position... person_x[ person_index ] = x ; person_y[ person_index ] = y ; } } } // tellymate helper routines... int tellymate_cursor_read() { // | Serial.print( CHAR_ESC "|" ); return( tellymate_get_response() ) ; } int tellymate_get_response() { // The tellymate has been asked to send back some data. // This routine waits up to 50 bit durations for a response. // (enough for the tellymate to receive the instruction and send the byte back) // // Note that because the Arduino has a large serial receive buffer, make sure that it's empty // before asking for data, otherwise this routine will pick up previously received characters. // (which can be very confusing!) for( uint8_t i = 0 ; i < 50 ; i++ ) { if (Serial.available() > 0) return ( Serial.read() ) ; // If a character was received, return it. delayMicroseconds( 1000000 / BAUD_RATE ) ; // wait for approximately one bit duration } return -1 ; // no character was received in the time limit. Return -1 (as per Serial.read() when there is no data) } void tellymate_enabletransmit() { // ~~~~ // care should be taken not to embed the whole 'enable-transmit' code in the compiled sketch // (otherwise the TellyMate may become 'transmit enabled' during the upload verification process) // (see 'Retrieving data from the TellyMate' in the User Guide) // The code below is suitable, and will not cause any problems during sketch upload. Serial.print( CHAR_ESC ) ; for( byte i = 0 ; i < 4 ; i++ ){ Serial.print( '~' ) ; } } void tellymate_cursor_move( uint8_t row , uint8_t col ) { // Yrc Serial.print( CHAR_ESC "Y" ) ; Serial.print((char)(32 + row)) ; Serial.print((char)(32 + col)) ; } void tellymate_cursor_show( bool show ) { // e or f Serial.print( CHAR_ESC ) ; Serial.print( show?'e':'f' ) ; } void tellymate_screen_clear( void ) { // E Serial.print( CHAR_ESC "E" ); }