Tuesday, February 12, 2013

LCD Game Part 5 - Back in Order

Hey, Digisparklers, we're back. And as you can see in the photo, the digits are all in order.

In Part 4 we made a few changes to our code so that we could check the state of a push button while the numbers were marching left across the display.

In this post, we are going to add a function that will reverse the order of the selected digits. To do that we get to use our swap() function again.

We will start by adding only one line to our Loop () function. I show it highlighted below so you can get it in the right place. Remember, this only happens when the button is pressed.


    lcd.setCursor(0,1);
    lcd.print(char(tick+48));
    lcd.setCursor(2,0);
    lcd.print(' ');
    flip();
    delay(1000);

Now we need that new function, flip(). I'm not passing a value to it, which doesn't sit real well with me, but we have been using a global variable, tick, which tells us all we need to know.


void flip(){
  int i=0;
  tick--;
  do {  
    swap(i,tick-i);
    i++;
  } while (i<=(tick/2));

  displayWorkingString();
  tick= 0;
  myTime = millis();
}

The last thing we do in slideLeft() is bump up the value of tick++. Here we undo that with the instruction: tick-- . In our do loop, i starts at the beginning of our character array and get's one larger with each pass. tick-i is the end of the section we want to swap and because we are subtracting a value that is getting larger, it get's smaller. The two values are approaching each other. Notice that we run this loop  while (i<=(tick/2)). So if you want to flip 8 digits, we only do it 4 times. What? Think about that. If we flipped every one of the digits, when we got done, they would be back in order.


What about odd numbers? Not a problem. If we only want to flip 3 digits, we only need to flip the first one with the third one. The middle digit doesn't move.


You will need to reboot Sparky after you solve the puzzle. And it doesn't stop running just because you get the digits in order. These are still on our to-do list. In the next post we will add those and well as some scoring. We will  also make the game more challenging by increasing the speed as you solve more and more puzzles. After that, we will add some scoring routines.

As always, here is the full sketch. Copy it and try it yourself. C U next time.


/* ATtiny85 as an I2C Master   Ex2        BroHogan                           1/21/11
 * Modified for Digistump - Digispark LCD Shield by Erik Kettenburg 11/2012
 * SETUP:
 * ATtiny Pin 1 = (RESET) N/U                      ATtiny Pin 2 = (D3) N/U
 * ATtiny Pin 3 = (D4) to LED1                     ATtiny Pin 4 = GND
 * ATtiny Pin 5 = SDA on DS1621  & GPIO            ATtiny Pin 6 = (D1) to LED2
 * ATtiny Pin 7 = SCK on DS1621  & GPIO            ATtiny Pin 8 = VCC (2.7-5.5V)
 * NOTE! - It's very important to use pullups on the SDA & SCL lines!
 * PCA8574A GPIO was used wired per instructions in "info" folder in the LiquidCrystal_I2C lib.
 * This ex assumes A0-A2 are set HIGH for an addeess of 0x3F
 * LiquidCrystal_I2C lib was modified for ATtiny - on Playground with TinyWireM lib.
 * TinyWireM USAGE & CREDITS: - see TinyWireM.h
 */

// Number Flip-Flop by Budd Churchward, WB7FHC, @barnacleBudd 



//#define DEBUG
#include <TinyWireM.h>                  // I2C Master lib for ATTinys which use USI - comment this out to use with standard arduinos
#include <LiquidCrystal_I2C.h>          // for LCD w/ GPIO MODIFIED for the ATtiny85

#define GPIO_ADDR     0x27             // (PCA8574A A0-A2 @5V) typ. A0-A3 Gnd 0x20 / 0x38 for A - 0x27 is the address of the Digispark LCD modules.


LiquidCrystal_I2C lcd(GPIO_ADDR,16,2);  // set address & 16 chars / 2 lines

String winner ="0123456789";            // a test string to easily see game is over
String workingString = "0123456789";    // all the digits that we will scramble at the beginning of the game
int rnd;     // will hold a random number for us.
int myButton = 5; // our button hooks up here
int btnPress;     // is it down or not
byte tick = 0;
unsigned long myTime;
boolean stillRolling = true;

void setup(){
  TinyWireM.begin();                    // initialize I2C lib - comment this out to use with standard arduinos
  lcd.init();                           // initialize the lcd 
  lcd.clear();
  lcd.backlight();
  pinMode (myButton, INPUT);
  pinMode(1, OUTPUT); //LED on Model A
  
  scramblePrompt();
  scrambleString();
  displayWorkingString();
  delay(1000);
  myTime = millis();
}

void loop()  {
  btnPress = digitalRead(myButton);
  if (btnPress==1){
    digitalWrite(1,1);
    lcd.setCursor(0,1);
    lcd.print(char(tick+48));
    lcd.setCursor(2,0);
    lcd.print(' ');
    flip();
    delay(1000);
  }else{
    digitalWrite(1,0);
  }
  if(millis() - myTime > 1000){
    shiftLeft();
    myTime = millis();
  }
}

void flip(){
  int i=0;
  tick--;
  do {  
    swap(i,tick-i);
    i++;
  } while (i<=(tick/2));
  //lcd.clear();
  displayWorkingString();
  tick= 0;
  myTime = millis();
}


void shiftLeft(){
if (tick < 10){
    //delay(1000);
    lcd.setCursor(tick + 2,0);   
    lcd.print(workingString[tick]);
    lcd.print(' ');
    tick++;

  }
}

void scramblePrompt(){
  lcd.noCursor();
  lcd.print("NUMBER FLIP-FLOP");
  lcd.setCursor(0,1);
  lcd.print("Press Button Now");
  
  do {
    rnd=random(9);
  } while (!digitalRead(myButton));
 }



void scrambleString() {
  lcd.clear();
  lcd.print("NUMBER FLIP-FLOP");
  
  for (int i=0; i<10; i++){
    rnd=random(9);
    swap(i,rnd);
  }
  delay(1000);
  lcd.clear();
   
}

void swap(int x, int y){
  byte hold=workingString[x];
  workingString[x]=workingString[y];
  workingString[y]=hold;
}
  

void displayWorkingString(){
  lcd.setCursor(3,0);
  lcd.print(workingString);
  lcd.noCursor();
}

 

No comments:

Post a Comment