Optimizing a few lines of code

For the most part, I can code what I want my Core to do. However, I’m often faced with code like the following, which sets some NeoPixel colors based on dates in the year. Surely there must be a way to optimize code like this so it doesn’t take up so many lines when I simply want to check a handful of dates during the year and set some LED colors for each date. Can anyone point out a more efficient way to do this, and help me learn to write code at a little higher level? And finally, is this just something you learn to optimize over time?

Example:

    if (atoi(rtc.monthString(currentTime)) == 7 && atoi(rtc.dayString(currentTime)) == 4){
            // Fourth of July Colors
            for(int i=0;i<8;i++){ 
                strip.setPixelColor(i, strip.Color(200,0,0));
            }
            for (int j=8;j<16;j++){
                strip.setPixelColor(j, strip.Color(0,0,200));
            }
            for(int k=16;k<24;k++){
                strip.setPixelColor(k, strip.Color(200,0,0));
            }
            for (int l=8;l<16;l++){
                strip.setPixelColor(l, strip.Color(0,0,200));
            }
            strip.show();
        	}
else if (atoi(rtc.monthString(currentTime)) == 2 && atoi(rtc.dayString(currentTime)) == 14){
            // Valentine's Day Colors
            for(int i=0;i<8;i++){ 
                strip.setPixelColor(i, strip.Color(255,102,255));
            }
            for (int j=8;j<16;j++){
                strip.setPixelColor(j, strip.Color(153,0,153));
            }
            for(int k=16;k<24;k++){
                strip.setPixelColor(k, strip.Color(255,102,255));
            }
            for (int l=8;l<16;l++){
                strip.setPixelColor(l, strip.Color(153,0,153));
            }
            strip.show();
        	}
else if [... AND THE CODE CONTINUES REPEATING FOR EVERY DATE]

How about an array of dates with a pointer to a function?

struct Date {
  int month, day;
  void(*colorFunction)();
};

const int num_holidays = 3;

Date holidays[num_holidays] = {
  {1, 1, newYear},
  {2, 14, valentine},
  {7, 4, fourthOfJuly}
};

Date today = {13, 32, everyday};

void setup()
{
  Serial.begin(9600);
  today.month = 1;
  today.day = 2;
  bool holiday = false;
  for (int i = 0; i < num_holidays; i++)
  {
    if (holidays[i].month == today.month && holidays[i].day == today.day)
    {
      holidays[i].colorFunction();
      holiday = true;
    }
  }
  if (!holiday)
  {
    today.colorFunction();
  }
  Serial.println("finished setup");
}

void loop()
{

}

void newYear(void)
{
  Serial.println("Happy New Year!!");
}

void valentine(void)
{
  Serial.println("Happy St Valentines Day!!");
}

void fourthOfJuly(void)
{
  Serial.println("Happy Birthday USA!!");
}

void everyday()
{
  Serial.println("Just any old day");
}

Looks interesting! I’ve used some arrays, but never with dates. How does the use of a period work? For example, this line:

if (holidays[i].month == today.month && holidays[i].day == today.day)

I understand calling the array element, but how does the “today.month” part and “today.day” part work?

each instance of the struct will have three members:

struct Date {
  int month, day;
  void(*colorFunction)();
};

Date myDate;

which will be:

myDate.month
myDate.day
and a pointer to a function called myDate.colorFunction()

just assign your month and day to the "today" object, sort of like this:

today.month = atoi(rtc.monthString(currentTime);
today.day = atoi(rtc.dayString(currentTime);

but you don't need to use the today object, I just used it in a way as to make a default daily colorFunction

Or a lookup table, with dates and colours, if you are not comfortable with pointers to functions just yet.

You can keep the table in flash by specifying that it is a const.

Extra credit for sequencing the table so you do not have to traverse the entire table to figure out the date is not special and should get handled by default colours.

Extra extra credit for creating the table contents programatically instead of manually. It can be an offline app that you simply cut & paste the resulting table into the web ide if you are using that.

Ohhh! I'm starting to understand. "Struct" is a struct resource, used for holding items of different types that I can define. Cool! I've never used that. I understand how you referenced the items individually, but why state this:

Why not simply say:

 Date.month

to get the month from the struct? I also think I understand why you created the "today" object. It appears to be the way to hold today's day and month so you can compare them to the objects you pull from the struct, correct?


AndyW, I'm not familiar with a lookup table other than simply using an array. Is that the same thing? I might be able to work out the first extra credit portion, but the second one will be challenging...

Thanks to all - I can work my way to a solution in my code about 99% of the time, but I'm starting to try to learn enough to optimize it. Speed of execution is becoming more important in some of my projects.

@Alligator,

Think of a struct as a datatype which you define as a bucket of datatypes:

for example:

struct Date {
  int month, day;
  void(*colorFunction)();
};

Creates a new datatype called Date. Date is a bucket containing two ints (month and day) and a pointer to a function.

Date myDate;

creates an instance of the Date datatype called myDate.

like any other datatype, you can create an array of structs:

Date holidays[num_holidays] = {
  {1, 1, newYear},
  {2, 14, valentine},
  {7, 4, fourthOfJuly}
};

creates num_holidays sized array of Date called holidays.

yes, I used another instance of Date called today to contain today's month and day. In retrospect, I didn't really need to do that but I thought it may be easier to see the logic if you saw comparable datatypes, sorry if that served only to confuse you.