Close

Optimization: Round 2

A project log for 1K Challange Laser

Draw the hackaday logo with a laser with less than 1K of data.

cyrille-gindreauCyrille Gindreau 12/09/2016 at 22:230 Comments

We were close, about 200 bytes away, it was time to get creative. The first thing we did was to flip our coordinates so that we were right side up. Second, we added the coordinates for where the laser should turn off (which actually brought our size count up to about 1500 bytes). Then we started experimenting a little bit. We broke up the logo into different sections: A wrench, the skull, one eye and the nose. The idea was that we could mirror the different pieces to save space. Our first take on the mirroring algorithm:


//lower left wrench
uint16_t wrench[] = {265, 635, 190, 710, 150, 705, 110, 710, 65, 745, 35, 780, 35, 850, 110, 780, 190, 880, 110, 945, 160, 955, 225, 935, 265, 880, 275, 850, 275, 815, 345, 745, 300, 700, 265, 635};
uint16_t wrenchLength = 36;

//Skull outer
uint16_t face[] = {320, 390, 510, 305, 700, 390, 750, 545, 700, 690, 650, 745, 620, 805, 585, 805, 560, 745, 550, 745, 525, 805, 485, 805, 470, 745, 460, 745, 435, 805, 395, 805, 375, 730, 320, 690, 270, 545, 320, 390};
uint16_t faceLength = 40;

//Left eye
uint16_t leftEye[] = {475, 525, 440, 480, 410, 475, 345, 545, 380, 605, 390, 595, 410, 570, 440, 555, 475, 525};
uint16_t eyeLength = 18;

//Nose
uint16_t nose[] = {510, 615, 520, 660, 535, 695, 510, 660, 485, 695, 500, 660, 510, 615};
uint16_t noseLength = 14;

uint16_t myIndex = 0;
uint16_t logoPart = 0;
uint16_t mirrorCount = 4;
uint16_t laserDelay;
uint16_t direction = 0;
while(1){
    switch(logoPart){
    //Draws the wrenches
    	case 0:
    	    if(mirrorCount > 0){
		if(myIndex < wrenchLength-3){
		    drawLine(wrench[myIndex], wrench[myIndex+1], wrench[myIndex+2], wrench[myIndex+3]);
		    myIndex = myIndex +2;
		} else {
		    for(laserDelay = 0; laserDelay < 400; laserDelay++)
		        continue;
		    P1OUT &= ~LASER;
		    if(mirrorCount > 1){
		        uint16_t oldX = wrench[myIndex];
			uint16_t oldY = wrench[myIndex+1];
			if(direction == 0){
			    mirrorX(wrench, wrenchLength, 256);
			    direction = 1;
			} else {
			    mirrorY(wrench, wrenchLength, 256);
			    direction = 0;
			}
			drawLine(oldX, oldY, wrench[0], wrench[1]);
		    }
		    for(laserDelay = 0; laserDelay < 250; laserDelay++)
		        continue;
		    P1OUT |= LASER;
		    myIndex = 0;
		    mirrorCount = mirrorCount - 1;
		}
    	     } else {
    	         for(laserDelay = 0; laserDelay < 400; laserDelay++)
    	 	     continue;
    	 	 P1OUT &= ~LASER;
    	 	 mirrorCount = 2;
    	 	 drawLine(wrench[myIndex], wrench[myIndex+1], leftEye[0], leftEye[1]);
    	 	 logoPart = 1;
    	 	 for(laserDelay = 0; laserDelay < 250; laserDelay++)
    	 	     continue;
    	 	 P1OUT |= LASER;
    	     }
	     break;
	//draws the eyes
    	case 1:
    	    if(myIndex < eyeLength-3){
    	        drawLine(leftEye[myIndex], leftEye[myIndex+1], leftEye[myIndex+2], leftEye[myIndex+3]);
    	        myIndex = myIndex +2;
    	    } else if(mirrorCount > 1) {
    	 	for(laserDelay = 0; laserDelay < 400; laserDelay++)
    	 	    continue;
    	 	P1OUT &= ~LASER;
    	 	uint16_t oldX = leftEye[myIndex];
    	 	uint16_t oldY = leftEye[myIndex+1];
    	 	mirrorX(leftEye, eyeLength, 256);
    	 	drawLine(oldX, oldY, leftEye[0], leftEye[1]);
    	 	myIndex = 0;
    	 	for(laserDelay = 0; laserDelay < 250; laserDelay++)
    	 	    continue;
    	 	    P1OUT |= LASER;
    	 	mirrorCount = mirrorCount - 1;
    	     } else {
    	 	for(laserDelay = 0; laserDelay < 400; laserDelay++)
    	 	    continue;
    	 	P1OUT &= ~LASER;
    	 	mirrorCount = 4;
    	 	drawLine(leftEye[myIndex], leftEye[myIndex+1], nose[0], nose[1]);
    	 	myIndex = 0;
    	 	logoPart = 2;
    	 	for(laserDelay = 0; laserDelay < 250; laserDelay++)
    	 	    continue;
    	 	P1OUT |= LASER;
    	     }
    	     break;
    	 //draws the nose
    	 case 2:
    	     if(myIndex < noseLength-3){
    	 	drawLine(nose[myIndex], nose[myIndex+1], nose[myIndex+2], nose[myIndex+3]);
    	 	myIndex = myIndex +2;
    	     } else {
    	 	for(laserDelay = 0; laserDelay < 400; laserDelay++)
    	 	    continue;
    	 	P1OUT &= ~LASER;
    	 	drawLine(nose[myIndex], nose[myIndex+1], face[0], face[1]);
    	 	logoPart = 3;
    	 	myIndex = 0;
    	 	for(laserDelay = 0; laserDelay < 250; laserDelay++)
    	 	    continue;
    	 	P1OUT |= LASER;
    	     }
    	     break;
    	 //draws the face
    	 case 3:
    	     if(myIndex < faceLength-3){
    	 	drawLine(face[myIndex], face[myIndex+1], face[myIndex+2], face[myIndex+3]);
    	 	myIndex = myIndex +2;
    	     } else {
    	 	for(laserDelay = 0; laserDelay < 400; laserDelay++)
    	 	    continue;
    	 	P1OUT &= ~LASER;
    	 	drawLine(face[myIndex], face[myIndex+1], wrench[0], wrench[1]);
    	 	logoPart = 0;
    	 	myIndex = 0;
    	 	mirrorCount = 4;
    	 	for(laserDelay = 0; laserDelay < 250; laserDelay++)
    	 	    continue;
    	 	P1OUT |= LASER;
    	     }
    	     break;
         }
     }
}

void mirrorX(uint16_t *arr, uint16_t length, uint16_t maxX){
    uint16_t i;
    for(i=0; i < length; i++){
        if(i%2 == 0){
	    arr[i] = maxX - arr[i];
	}
    }
}

void mirrorY(uint16_t *arr, uint16_t length, uint16_t maxY){
    uint16_t i;
    for(i=0; i < length; i++){
        if(i%2 == 1){
	    arr[i] = maxY - arr[i];
	}
    }
}
For a grand total 1730 bytes!? And so another round of optimization began. We changed the switch to if/else statements, hardcoded the mirror functions instead of calling them. We made the face and nose arrays constant and typedef'd the lengths. One thing that really saved us space was changing all numbers that needed multiplication and division to base 2 and just do some bit twiddling .

After all that, we were only down to 1366 bytes. Not quite enough. The problem was that for every mirror reflection we made(X and Y axis), we needed to keep track of our location. We also had to store counters to keep track of which piece of logo we were drawing and which version of it we were on. So the next thing we tried was a kind of hybrid between mirroring and the original code. The upper and lower left wrenches along with the left eye were put into one array and the face and nose were put into another. This way we could get rid of at least one counter and about 30 lines of code. The end result: 1068 Bytes. How many bytes in 1KB? Crap...

Discussions