March Madness - Arduino on Unix

Now I know that the rules say you can't write "Hello world" in Java and then do it again in Python and have it count. Well this is eight queens again but it is MUCH more that that.

This is an include file that will allow you to compile and run an Arduino sketch on Unix. Of course not everything is supported. This first pass only implements the Serial.print functions. However, that was a tremendous start and allowed me to run the eight queens program with practially no modification on MacOS command line and intel based linux.

Therefore this is actually more useful than the eight queens program itself and can be used in many Arduino programs.

On MacOS-X it took 1.25 seconds to finish, campare that to 6 minutes 31 seconds on the Arduino
Thats 312 times faster. 16 mhz * 312 = 4992 mhz = 4.9 ghz. The machine was 2.5 ghz dual core intel based Mac. I am sure that the better than expected cpu speed is due to the word size.

How to use it.

Advantages TO-DO list What cannot be done

//************************************************************************
//*	Arduino on Unix library
//*	
//*		(C) 2010 by Mark Sproul
//*		Open source as per standard Arduino code
//************************************************************************
//*	this library (include file) allows you to compile and run SOME arduino programs
//*	on Unix without changing the entire program. It does that by implementing
//*	the hardware serial class and substituting the proper printf commands.
//*	This is expected to expand over time, 
//*	for example, I would like to add the millis function call
//************************************************************************
//*	Edit history
//************************************************************************
//*	March  2,	2010	 Started on Arduino_unix
//*	March  2,	2010	 my eight queens program runs on unix (MacOS X).
//*	March  2,	2010	 Tested on Linux (x86_64 GNU/Linux)
//*	March  2,	2010	 Added millis, it returns elapsed seconds times 1000, best I could do
//************************************************************************

#include <time.h>




typedef char			boolean;
typedef unsigned char	uint8_t;
unsigned long			gStartTimeSeconds;
time_t					tloc;

//************************************************************************
unsigned long	millis(void)
{
unsigned long	elapsedTimeSeconds;

	elapsedTimeSeconds	=	time(&tloc) - gStartTimeSeconds;

	return(elapsedTimeSeconds * 1000);
}


//************************************************************************
class HardwareSerial
{
	public:
						HardwareSerial(void);
//		virtual			~HardwareSerial(void);

		void			begin(long);
		uint8_t			available(void);
		int				read(void);
		void			flush(void);
		virtual void	write(uint8_t);
		virtual void	print(char *);
		virtual void	println(char *);
		virtual void	print(int);
		virtual void	println(int);
		virtual void	println(void);
};



//************************************************************************
HardwareSerial::HardwareSerial()
{
	//*	do nothing
}

//************************************************************************
//HardwareSerial::~HardwareSerial()
//{
	//*	do nothing
//}


//************************************************************************
void HardwareSerial::begin(long speed)
{
	//*	do nothing
}

//************************************************************************
uint8_t HardwareSerial::available(void)
{
//	return serialAvailable();
	return false;
}

//************************************************************************
int HardwareSerial::read(void)
{
//	return serialRead();
	return 0;
}

//************************************************************************
void HardwareSerial::flush()
{
//	serialFlush();
}

//************************************************************************
void HardwareSerial::write(uint8_t b)
{
//	serialWrite(b);
	printf("%c", b);
}


//************************************************************************
void HardwareSerial::print(char *theString)
{
	printf(theString);
}

//************************************************************************
void HardwareSerial::println(char *theString)
{
	printf(theString);
	printf("\r\n");
}

//************************************************************************
void HardwareSerial::println(void)
{
	printf("\r\n");
}

//************************************************************************
void HardwareSerial::print(int theNumber)
{
	printf("%d", theNumber);
}

//************************************************************************
void HardwareSerial::println(int theNumber)
{
	printf("%d", theNumber);
	printf("\r\n");
}



// Preinstantiate Objects //////////////////////////////////////////////////////

HardwareSerial Serial = HardwareSerial();





//************************************************************************
//*	Eight Queens
//*	
//*		(C) 2010 by Mark Sproul
//*		Open source as per standard Arduino code
//*	http://obereed.net/queens/solution.html
//************************************************************************

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>

#define _COMPILE_FOR_UNIX_
#ifdef _COMPILE_FOR_UNIX_
	#include	"arduino_unix.h"
#else
	#include "WProgram.h"
	#include "HardwareSerial.h"
#endif



unsigned long	gChessBoard[8];
unsigned long	gLoopCounter;
int				gValidCount;


//************************************************************************
boolean	CheckCurrentBoard(void)
{
int		ii;
int		jj;
int		theRow;
long	theLongRow;
long	theLongColumns;
int		bitCount;

	//*	we know we have 1 in each row,
	//*	Check for 1 in each column
	theRow	=	0;
	for (ii=0; ii<8; ii++)
	{
		theRow	|=	gChessBoard[ii];
	}
	if (theRow != 0x0ff)
	{
		return(false);
	}

	//*	we have 1 in each column, now check the diagonals
	theLongColumns	=	0;
	for (ii=0; ii<8; ii++)
	{
		theLongRow	=	gChessBoard[ii] & 0x0ff;
		theLongRow	=	theLongRow << ii;
		
		theLongColumns	|=	theLongRow;
	}
	
	//*	now count the bits
	bitCount	=	0;
	for (ii=0; ii<16; ii++)
	{
		if ((theLongColumns & 0x01) == 0x01)
		{
			bitCount++;
		}
		theLongColumns	=	theLongColumns >> 1;
	}
	if (bitCount != 8)
	{
		return(false);
	}

	
	//*	we now have to check the other diagonal
	theLongColumns	=	0;
	for (ii=0; ii<8; ii++)
	{
		theLongRow	=	gChessBoard[ii] & 0x0ff;
		theLongRow	=	theLongRow << 8;
		theLongRow	=	theLongRow >> ii;
		
		theLongColumns	|=	theLongRow;
	}

	//*	now count the bits
	bitCount	=	0;
	for (ii=0; ii<16; ii++)
	{
		if ((theLongColumns & 0x01) == 0x01)
		{
			bitCount++;
		}
		theLongColumns	=	theLongColumns >> 1;
	}
	if (bitCount != 8)
	{
		return(false);
	}


	return(true);
}


//************************************************************************
boolean	CheckForDone(void)
{
int		ii;
boolean	weAreDone;
int		theRow;

	weAreDone	=	false;

	//*	we know we have 1 in each row,
	//*	Check for 1 in each column
	theRow	=	0;
	for (ii=0; ii<8; ii++)
	{
		theRow	|=	gChessBoard[ii];
	}
	if (theRow == 0x01)
	{
		weAreDone	=	true;
	}

	return(weAreDone);
}


//************************************************************************
void	RotateQueens(void)
{
int		ii;
boolean	keepGoing;
int		theRow;

	ii			=	0;
	keepGoing	=	true;
	while (keepGoing && (ii < 8))
	{
		theRow	=	gChessBoard[ii] & 0x0ff;
		theRow	=	(theRow >> 1) & 0x0ff;
		if (theRow != 0)
		{
			gChessBoard[ii]	=	theRow;
			keepGoing		=	false;
		}
		else
		{
			gChessBoard[ii]	=	0x080;
		}
		ii++;
	}
}


//************************************************************************
void	PrintChessBoard(boolean printSolutionNumber)
{
int		ii;
int		jj;
int		theRow;
char	textString[32];

	if (printSolutionNumber)
	{
		Serial.print("loop= ");
		Serial.print(gLoopCounter);
		Serial.print(" solution count= ");
		Serial.println(gValidCount);
	}
	
//	sprintf(textString, "LOOP= %ld", gLoopCounter);
//	Serial.println(textString);
	
	Serial.println("+----------------+");
	for (ii=0; ii<8; ii++)
	{
		theRow	=	gChessBoard[ii];
		
		Serial.print("|");
		for (jj=0; jj<8; jj++)
		{
			if (theRow & 0x080)
			{
				Serial.print("Q ");
			}
			else
			{
				Serial.print(". ");
			}
			theRow	=	theRow << 1;
		}
		Serial.println("|");
	}
	Serial.println("+----------------+");
	Serial.println();
}


//************************************************************************
void setup()
{
int	ii;

	Serial.begin(9600);
	Serial.println();
	Serial.println("Eight Queens brute force");

	//*	put the 8 queens on the board, 1 in each row
	for (ii=0; ii<8; ii++)
	{
		gChessBoard[ii]	=	0x080;
	}

	Serial.println("The board starts out like this");

	PrintChessBoard(false);
	
	gLoopCounter	=	0;
	gValidCount		=	0;
}

//************************************************************************
void loop()
{
	gLoopCounter++;
	
	if (CheckCurrentBoard())
	{
		gValidCount++;
		PrintChessBoard(true);
	}
	else if ((gLoopCounter % 1000) == 0)
	{
//		PrintChessBoard();
	}

	RotateQueens();
	if (CheckForDone())
	{
	long	elapsedSeconds;
	long	elapsedMinutes;
	long	elapsedHours;
	
		elapsedSeconds	=	millis() / 1000;
		elapsedMinutes	=	elapsedSeconds / 60;
		elapsedHours	=	elapsedMinutes / 60;
		
		Serial.println("----------------------------------");
		Serial.println("All done");
		Serial.print("Total itterations (boards) checked ");
		Serial.println(gLoopCounter);


		Serial.println("This is what the board ends up looking like");


		PrintChessBoard(false);
		Serial.println("----------------------------------");

		Serial.print("total seconds=");
		Serial.println(elapsedSeconds);

		Serial.print("hours=");
		Serial.println(elapsedHours);

		Serial.print("minutes=");
		Serial.println(elapsedMinutes % 60);

		Serial.print("seconds=");
		Serial.println(elapsedSeconds % 60);

	#ifdef _COMPILE_FOR_UNIX_
		exit(0);
	#endif
		while (1);
	}
}



#ifdef _COMPILE_FOR_UNIX_
//************************************************************************
int	main()
{
	gStartTimeSeconds	=	time(&tloc);
	setup();
	
	while (true)
	{
		loop();
	}
}

#endif