Don't like ads? PRO users don't see any ads ;-)
Guest

ChainReactionSolver

By: a guest on Jul 11th, 2012  |  syntax: C  |  size: 24.83 KB  |  hits: 21  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. //
  2. //  main.c
  3. //  ChainReactionSolver
  4. //
  5. //  Created by Evan Andersen on 12-04-08.
  6. //  Copyright (c) 2012 charliehorse55. All rights reserved.
  7. //
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <stdint.h>
  12. #include <inttypes.h>
  13. #include <pthread.h>
  14. #include <time.h>
  15. #include <math.h>
  16. #include <string.h>
  17.  
  18. #ifdef __MACH__
  19. #include <mach/mach.h>
  20. #include <mach/mach_time.h>
  21. #endif
  22.  
  23. //wrappers
  24. void* xmalloc(size_t size);
  25.  
  26. //Threading
  27. void* threadInit(void* arguments);
  28. int createThread(pthread_t* theThread, uint8_t* problem, uint8_t problemSize, uint8_t* allPaths, int* blockCount, long maxBlockCount, pthread_mutex_t* mutex, uint8_t blockPathLength, uint8_t* connections);
  29. void generateBlockArray(uint8_t* path, uint8_t position, uint8_t* problem, uint8_t problemSize, uint8_t pathLength, long* solutionCount, uint8_t* connections, uint8_t* allPaths);
  30. void copyPathToArray(uint8_t* path, uint8_t* allPaths, uint8_t pathLength, long arrayPosition);
  31.  
  32. //Solving
  33. uint8_t isValid(uint8_t a, uint8_t b);
  34. void findNextPathStep(uint8_t i, uint8_t j, uint8_t position, uint8_t* problem, uint8_t problemSize, uint8_t pathLength, long* solutionCount, uint8_t* connections);
  35. long solveProblem(uint8_t* problem, uint8_t problemSize, uint8_t maxThreadCount);
  36. uint8_t* createConnections(uint8_t* problem, uint8_t problemSize, double* averageNumConnections);
  37.  
  38. //Printing
  39. void printHelp(void);
  40. void printProblem(uint8_t* problem, uint8_t problemSize);
  41.  
  42. //Problem Loading
  43. uint8_t* readProblem(const char* path, uint8_t* size);
  44. uint8_t* randomProblem(uint8_t problemSize);
  45.  
  46.  
  47. //Performance tweaking constants
  48. const int kDefaultThreads = 4;
  49. const int kMaxThreads = 64;
  50. const int kBlockSize = 19;
  51.  
  52.  
  53.  
  54. //=======================================================================================================================================
  55. // Malloc wrapper
  56. //
  57. // Ensures that malloc returns a valid pointer, else quits with an error
  58. //=======================================================================================================================================
  59. void* xmalloc(size_t size)
  60. {
  61.     void* pointer = malloc(size);
  62.     if(!pointer)
  63.     {
  64.         printf("Malloc could not allocate memory of size %lu\n", size);
  65.         exit(-1);
  66.     }
  67.     return pointer;
  68. }
  69.  
  70.  
  71. //=======================================================================================================================================
  72. // Multi-threading
  73. //=======================================================================================================================================
  74. struct thread_info
  75. {
  76.     uint8_t position;
  77.     uint8_t* problem;
  78.     uint8_t problemSize;
  79.     uint8_t pathLength;
  80.     uint8_t* allPaths;
  81.     uint8_t blockPathLength;
  82.     int* blockCount;
  83.     long maxBlockCount;
  84.     pthread_mutex_t* mutex;
  85.     uint8_t* connections;
  86. };
  87.  
  88. void* threadInit(void* arguments)
  89. {
  90.     struct thread_info *args = arguments;
  91.     long* theResult = xmalloc(sizeof(long));
  92.     *theResult = 0;
  93.        
  94.     //keep loading blocks until they are all done
  95.     while(1)
  96.     {
  97.         //block other threads from accessing blockCount
  98.         pthread_mutex_lock(args->mutex);
  99.         if(*(args->blockCount) < args->maxBlockCount)
  100.         {
  101.             //store it for later
  102.             int tempBlockCount = *(args->blockCount);
  103.  
  104.             //increment so the next thread takes the next block in the queue
  105.             (*(args->blockCount))++;
  106.                        
  107.             //allow other threads to access the blockCount again
  108.             pthread_mutex_unlock(args->mutex);
  109.                        
  110.             //mark the problem array
  111.             uint8_t col, row;
  112.             for (int i = 1; i < args->blockPathLength; i++)
  113.             {
  114.                 col = (args->allPaths)[tempBlockCount*args->blockPathLength*2 + i*2];
  115.                 row = (args->allPaths)[tempBlockCount*args->blockPathLength*2 + i*2 + 1];
  116.                 (args->problem)[col*args->problemSize*2 + row*2 + 1] = 1;
  117.             }
  118.             findNextPathStep(col, row, args->blockPathLength - 1, args->problem, args->problemSize, args->pathLength, theResult, args->connections);
  119.            
  120.             if(!(tempBlockCount % 10))
  121.             {
  122.                 printf("Block %d/%ld solved\n", tempBlockCount, args->maxBlockCount);
  123.             }            
  124.             //reset the travelled path to it's default state, all 0 (except 0,0)
  125.             for (int i = 1; i < args->blockPathLength; i++)
  126.             {
  127.                 //mark the problem array
  128.                 col = (args->allPaths)[tempBlockCount*args->blockPathLength*2 + i*2];
  129.                 row = (args->allPaths)[tempBlockCount*args->blockPathLength*2 + i*2 + 1];
  130.                 (args->problem)[col*args->problemSize*2 + row*2 + 1] = 0;
  131.             }            
  132.         }
  133.         else
  134.         {
  135.             pthread_mutex_unlock(args->mutex);
  136.             break;
  137.         }
  138.     }
  139.     //free the problem
  140.     free(args->problem);
  141.          
  142.     //free the info struct
  143.     free(args);
  144.    
  145.     pthread_exit(theResult);
  146. }
  147.  
  148. int createThread(pthread_t* theThread, uint8_t* problem, uint8_t problemSize, uint8_t* allPaths, int* blockCount, long maxBlockCount, pthread_mutex_t* mutex, uint8_t blockPathLength, uint8_t* connections)
  149. {
  150.     //create a new version of the problem array asd copy the values in
  151.     uint8_t* newProblem = xmalloc(sizeof(uint8_t**)*problemSize*problemSize*2);
  152.     for(int i = 0; i < problemSize; i++)
  153.     {
  154.         for(int j = 0; j < problemSize; j++)
  155.         {
  156.             newProblem[i*problemSize*2 + j*2]  = problem[i*problemSize*2 +j*2];
  157.             newProblem[i*problemSize*2 + j*2 + 1]  = problem[i*problemSize*2 + j*2 + 1];
  158.         }
  159.     }
  160.    
  161.     //each thread needs it's own copy of the problem array        
  162.     struct thread_info* info  = xmalloc(sizeof(struct thread_info));
  163.     info->position = 1;
  164.     info->problem = newProblem;
  165.     info->problemSize = problemSize;
  166.     info->pathLength = problemSize*problemSize - 1;
  167.     info->allPaths = allPaths;
  168.     info->blockPathLength = blockPathLength;
  169.     info->blockCount = blockCount;
  170.     info->maxBlockCount = maxBlockCount;
  171.     info->mutex = mutex;
  172.     info->connections = connections;
  173.    
  174.     return pthread_create(theThread, NULL, &threadInit, (void*)info);
  175. }
  176.  
  177. //=======================================================================================================================================
  178. // Block generator
  179. //
  180. // Break the problem into smaller chunks that can be seperatley processed by threads
  181. //=======================================================================================================================================
  182. void generateBlockArray(uint8_t* path, uint8_t position, uint8_t* problem, uint8_t problemSize, uint8_t pathLength, long* solutionCount, uint8_t* connections, uint8_t* allPaths)
  183. {
  184.     //faster to define a new variable then to do position + 1 four times
  185.     uint8_t newPos = position + 1;
  186.    
  187.     uint8_t i = path[position*2];
  188.     uint8_t j = path[position*2 + 1];
  189.    
  190.     uint16_t base = problemSize*problemSize*4*i + j*problemSize*4;
  191.    
  192.     //compiler should optimize this out, prevents spagetti code
  193.     for(uint8_t z = 1; z <= connections[base]; z++)
  194.     {  
  195.         uint8_t currentCol = connections[base + z*2];
  196.         uint8_t currentRow = connections[base + z*2 + 1];
  197.         if(!problem[currentCol*problemSize*2 + currentRow*2 + 1])
  198.         {
  199.             if(isValid(problem[currentCol*problemSize*2 + currentRow*2], problem[i*problemSize*2 + j*2]))
  200.             {
  201.                 path[newPos*2] = currentCol;
  202.                 path[newPos*2 + 1] = currentRow;
  203.                
  204.                 //if we are at the end of the path, we have found a solution
  205.                 if(newPos >= pathLength)
  206.                 {
  207.                     copyPathToArray(path, allPaths, pathLength, *solutionCount);
  208.  
  209.                     (*solutionCount)++;
  210.                 }
  211.                 else
  212.                 {
  213.                     //recurse and mark this square as part of the path
  214.                     problem[currentCol*problemSize*2 + currentRow*2 + 1] = 1;
  215.                     generateBlockArray(path, newPos, problem, problemSize, pathLength, solutionCount, connections, allPaths);
  216.                     problem[currentCol*problemSize*2 + currentRow*2 + 1] = 0;
  217.                 }
  218.             }
  219.         }
  220.     }
  221. }
  222.  
  223. //=======================================================================================================================================
  224. // Copy path to array
  225. //
  226. // self explanatory
  227. //=======================================================================================================================================
  228. void copyPathToArray(uint8_t* path, uint8_t* allPaths, uint8_t pathLength, long arrayPosition)
  229. {
  230.     //copy the current path into it
  231.     pathLength++;
  232.     for(int i = 0; i < pathLength; i++)
  233.     {
  234.         allPaths[arrayPosition*pathLength*2 + i*2] = path[i*2];
  235.         allPaths[arrayPosition*pathLength*2 + i*2 + 1] = path[i*2 + 1];
  236.     }
  237. }
  238.  
  239. //=======================================================================================================================================
  240. // Shape and Color Testing
  241. //
  242. // Note - it's faster to simply check the 1 case that is illegal vs. the 3 that are legal
  243. //=======================================================================================================================================
  244. uint8_t isValid(uint8_t a, uint8_t b)
  245. {
  246.     switch (a)
  247.     {
  248.         case 0:
  249.             return b != 3;
  250.            
  251.         case 1:
  252.             return b != 2;
  253.            
  254.         case 2:
  255.             return b != 1;
  256.        
  257.         case 3:
  258.             return b != 0;
  259.     }
  260.     return 0;
  261. }
  262.  
  263. //=======================================================================================================================================
  264. // The Recursive Solution Finder
  265. //
  266. // Only checks valid moves based on the cache in the connection array
  267. //=======================================================================================================================================
  268. void findNextPathStep(uint8_t i, uint8_t j, uint8_t position, uint8_t* problem, uint8_t problemSize, uint8_t pathLength, long* solutionCount, uint8_t* connections)
  269. {
  270.     //faster to define a new variable then to do position + 1 four times
  271.     uint8_t newPos = position + 1;
  272.    
  273.     uint16_t base = problemSize*problemSize*4*i + j*problemSize*4;
  274.    
  275.     if(newPos >= pathLength)
  276.     {
  277.         for(uint8_t z = 1; z <= connections[base]; z++)
  278.         {  
  279.             //compiler should optimize this out, prevents spagetti code
  280.             uint8_t currentCol = connections[base + z*2];
  281.             uint8_t currentRow = connections[base + z*2 + 1];
  282.             if(!problem[currentCol*problemSize*2 + currentRow*2 + 1] && isValid(problem[currentCol*problemSize*2 + currentRow*2], problem[i*problemSize*2 + j*2]))
  283.             {
  284.                 (*solutionCount)++;
  285.             }
  286.         }
  287.     }    
  288.     else
  289.     {
  290.         for(uint8_t z = 1; z <= connections[base]; z++)
  291.         {  
  292.             uint8_t currentCol = connections[base + z*2];
  293.             uint8_t currentRow = connections[base + z*2 + 1];
  294.             if(!problem[currentCol*problemSize*2 + currentRow*2 + 1])
  295.             {
  296.                 if(isValid(problem[currentCol*problemSize*2 + currentRow*2], problem[i*problemSize*2 + j*2]))
  297.                 {
  298.                     //recurse and mark this square as part of the path
  299.                     problem[currentCol*problemSize*2 + currentRow*2 + 1] = 1;
  300.                     findNextPathStep(currentCol, currentRow, newPos, problem, problemSize, pathLength, solutionCount, connections);
  301.                     problem[currentCol*problemSize*2 + currentRow*2 + 1] = 0;
  302.                 }
  303.             }
  304.         }
  305.     }
  306. }
  307.  
  308. //=======================================================================================================================================
  309. // Solve Problem
  310. //
  311. // Returns the exact total number of solutions for a given problem
  312. //=======================================================================================================================================
  313. long solveProblem(uint8_t* problem, uint8_t problemSize, uint8_t maxThreadCount)
  314. {
  315.     double averageConnections;
  316.     uint8_t* possibleConnections = createConnections(problem, problemSize, &averageConnections);
  317.  
  318.     printf("\nAverage of %.3lf of %d possible connections\n\n", averageConnections, problemSize*2 - 2);
  319.  
  320.    
  321.     //calculate the path length to calculate the blocks from
  322.     int blockPathLength = problemSize*problemSize - kBlockSize;
  323.    
  324.     //should not be less than 2
  325.     if (blockPathLength < 2)
  326.     {
  327.         blockPathLength = 2;
  328.     }
  329.    
  330.     //count how many blocks we need
  331.     long blockCount = 0;
  332.     findNextPathStep(0, 0, 0, problem, problemSize, blockPathLength - 1, &blockCount, possibleConnections);
  333.    
  334.     //init an array to hold all of the blocks
  335.     uint8_t* allPaths = xmalloc(sizeof(uint8_t)*blockCount*blockPathLength*2);
  336.    
  337.     //fill the array
  338.     //make a new path
  339.     uint8_t* path = xmalloc(sizeof(uint8_t)*blockPathLength*2);
  340.    
  341.     //start of the path is always 0
  342.     path[0] = 0;
  343.     path[1] = 0;
  344.    
  345.     long pathCount = 0;
  346.     generateBlockArray(path, 0, problem, problemSize, blockPathLength - 1, &pathCount, possibleConnections, allPaths);
  347.    
  348.     printf("\nCreated %ld blocks to solve\n\n", blockCount);
  349.    
  350.     //create the specified number of threads and start handing out tasks
  351.     pthread_t* threads = xmalloc(sizeof(pthread_t)*maxThreadCount);
  352.    
  353.     //variable to synchronize the blocks between threads
  354.     int currentBlock = 0;
  355.    
  356.     //create a mutex for thread synchronization
  357.     pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  358.    
  359.     int threadCount = 0;
  360.     while(threadCount < maxThreadCount && threadCount < blockCount)
  361.     {
  362.         createThread(&(threads[threadCount]), problem, problemSize, allPaths, &currentBlock, blockCount, &mutex, blockPathLength, possibleConnections);
  363.         threadCount++;
  364.     }
  365.    
  366.     printf("\nCreated %d threads\n", threadCount);
  367.    
  368.     //wait for threads to finish and count the solutions
  369.     long solutionCount = 0;
  370.     for(uint8_t i = 0; i < threadCount; i++)
  371.     {
  372.         void* returnValue;
  373.         pthread_join(threads[i], &returnValue);
  374.         solutionCount += *(long*)returnValue;
  375.        
  376.         //free the result variable
  377.         free(returnValue);
  378.     }    
  379.    
  380.     //free stuff
  381.     free(threads);
  382.     free(possibleConnections);
  383.     free(path);
  384.     free(allPaths);
  385.    
  386.     return solutionCount;
  387. }
  388.  
  389. //=======================================================================================================================================
  390. // Connection Array
  391. //
  392. // Creates an array holding all possible connections between blocks
  393. //=======================================================================================================================================
  394. uint8_t* createConnections(uint8_t* problem, uint8_t problemSize, double* averageNumConnections)
  395. {
  396.     //cache all possible connections
  397.    
  398.     uint8_t leadingDim = problemSize*problemSize*4;
  399.    
  400.     //create the cache array
  401.     uint8_t* possibleConnections = xmalloc(sizeof(uint8_t)*leadingDim*problemSize);
  402.    
  403.     //fill the cache array
  404.     uint32_t totalConnections = 0;
  405.    
  406.     //for each row
  407.     for(int i = 0; i < problemSize; i++)
  408.     {
  409.         //for each col
  410.         for(int j = 0; j < problemSize; j++)
  411.         {  
  412.             int numConnections = 0;
  413.             //test the row
  414.             for(int z = 0; z < problemSize; z++)
  415.             {
  416.                 if(z != j && isValid(problem[i*problemSize*2 + j*2], problem[i*problemSize*2 + z*2]))
  417.                 {
  418.                     numConnections++;
  419.                     possibleConnections[i*leadingDim + j*problemSize*4 + numConnections*2] = i;
  420.                     possibleConnections[i*leadingDim + j*problemSize*4 + numConnections*2 + 1] = z;
  421.                 }
  422.             }
  423.             //test the column
  424.             for(int z = 0; z < problemSize; z++)
  425.             {
  426.                 if(z != i && isValid(problem[i*problemSize*2 + j*2], problem[z*problemSize*2 +j*2]))
  427.                 {
  428.                     numConnections++;
  429.                     possibleConnections[i*leadingDim + j*problemSize*4 + numConnections*2] = z;
  430.                     possibleConnections[i*leadingDim + j*problemSize*4 + numConnections*2 + 1] = j;
  431.                 }
  432.             }
  433.             //store the number of found connections
  434.             possibleConnections[i*leadingDim + j*problemSize*4] = numConnections;
  435.             totalConnections += numConnections;
  436.         }
  437.     }
  438.     if(averageNumConnections)
  439.     {
  440.         *averageNumConnections = (double)totalConnections / (problemSize*problemSize);
  441.     }
  442.    
  443.     return possibleConnections;
  444. }
  445.  
  446.  
  447. //=======================================================================================================================================
  448. // Read problems from the hard drive
  449. //
  450. // Note - problems are currently stored as 2 bit ints on the HD. Feel free to modify to read Cr, Cb, etc if you want
  451. //=======================================================================================================================================
  452. uint8_t* readProblem(const char* path, uint8_t* problemSize)
  453. {
  454.     //open the file for reading only
  455.     FILE* problemFile = fopen(path, "r");
  456.    
  457.     *problemSize = 0;
  458.    
  459.     if(problemFile)
  460.     {
  461.         //scan the number of elements on the first line
  462.         char input[32];
  463.         fgets(input, sizeof(input), problemFile);
  464.        
  465.         for(int i = 0; input[i] != '\n' && i < sizeof(input); i++)
  466.         {
  467.             if(input[i] >= '0' && input[i] <= '3')
  468.             {
  469.                 (*problemSize)++;
  470.             }
  471.         }
  472.        
  473.         //sanity check
  474.         if (*problemSize > 12)
  475.         {
  476.             printf("Badly formatted file at %s\n\n", path);
  477.             exit(-1);
  478.         }
  479.    
  480.         //alloc the 3D problem array
  481.         uint8_t* problem = xmalloc(sizeof(uint8_t**)*(*problemSize)*(*problemSize)*2);
  482.        
  483.         //read in the array from the file
  484.         int temp = 0;
  485.        
  486.         fseek(problemFile, 0, SEEK_SET);
  487.         for(int j = 0; (j < *problemSize); j++)
  488.         {
  489.             for(uint8_t i = 0; i < *problemSize; i++)
  490.             {
  491.                 if(fscanf(problemFile, "%d", &temp) && temp >= 0 && temp <= 3)
  492.                 {
  493.                     problem[i*(*problemSize)*2 + j*2] = (uint8_t)temp;
  494.                     problem[i*(*problemSize)*2 + j*2 + 1] = 0;
  495.                 }
  496.             }
  497.         }
  498.                
  499.         //always close a file when you are done with it
  500.         fclose(problemFile);
  501.        
  502.         return problem;
  503.     }
  504.     else
  505.     {
  506.         printf("\nError reading file at %s\n\n", path);
  507.         exit(-1);
  508.     }
  509.    
  510. }
  511.  
  512. //=======================================================================================================================================
  513. // Random Problem
  514. //
  515. // Returns a random problem of the specified size
  516. //=======================================================================================================================================
  517. uint8_t* randomProblem(uint8_t problemSize)
  518. {
  519.     uint8_t* problem = xmalloc(sizeof(uint8_t)*problemSize*problemSize*2);
  520.     for(int i = 0; i < problemSize; i++)
  521.     {
  522.         for(int j = 0; j < problemSize; j++)
  523.         {
  524.             problem[i*problemSize*2 + j*2] = rand() % 4;
  525.             problem[i*problemSize*2 + j*2 + 1] = 0;
  526.         }
  527.     }    
  528.     return problem;
  529. }
  530.  
  531. //=======================================================================================================================================
  532. // Print Problem
  533. //
  534. // Prints the problem
  535. //=======================================================================================================================================
  536. void printProblem(uint8_t* problem, uint8_t problemSize)
  537. {
  538.     for(int i = 0; i < problemSize; i++)
  539.     {
  540.         printf("      ");
  541.         for(int j = 0; j < problemSize; j++)
  542.         {
  543.             printf("%hhu ", problem[j*problemSize*2 + i*2]);
  544.         }
  545.         printf("\n");
  546.     }
  547.     printf("\n");
  548. }
  549.  
  550.  
  551. //=======================================================================================================================================
  552. // Help Function
  553. //
  554. // Prints details on how to propely use this program
  555. //=======================================================================================================================================
  556. void printHelp()
  557. {
  558.     printf("\n-------------------Chain Reaction Solver 1.0-------------------\n\n");
  559.     printf("Options:\n");
  560.     printf("           -f, --filename <filename> Specify a filename to use as input\n\n");
  561.     printf("           -t, --threads <count> Specifies the number of threads to create.\n");
  562.     printf("              Valid numbers are between 1 and 64\n\n");
  563.     printf("           -h, --help Print the help\n\n");
  564. }
  565.  
  566. //=======================================================================================================================================
  567. // Main Function
  568. //
  569. // Reads command line options and decides what to do with them
  570. //=======================================================================================================================================
  571. int main (int argc, const char * argv[])
  572. {
  573.     int maxThreads = kDefaultThreads;
  574.     const char* filename = NULL;
  575.    
  576.     srand(time(NULL));
  577.    
  578.     //parse command line options
  579.     for(int i = 1; i < argc; i++)
  580.     {
  581.         if(argv[i][0] == '-')
  582.         {
  583.             //found the file
  584.             if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--filename"))
  585.             {
  586.                 if(filename)
  587.                 {
  588.                     printHelp();
  589.                     printf("\nError - multiple input files specified\n");
  590.                     exit(-1);
  591.                 }
  592.                
  593.                 if((i + 1) < argc)
  594.                 {
  595.                     filename = argv[i + 1];
  596.                 }
  597.                
  598.                 //no need to try and parse it further
  599.                 continue;
  600.             }
  601.                        
  602.             //thread count
  603.             if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--threads"))
  604.             {
  605.                 int threadCount = 0;
  606.                 if((i + 1) < argc)
  607.                 {
  608.                     threadCount = atoi(argv[i + 1]);
  609.                 }
  610.                 else
  611.                 {
  612.                     printHelp();
  613.                     printf("\nInvalid Thread Count\n");
  614.                     exit(-1);
  615.                 }
  616.                
  617.                 if (threadCount > 0 && threadCount <= kMaxThreads)
  618.                 {
  619.                     maxThreads = threadCount;
  620.                 }
  621.                 else
  622.                 {
  623.                     printHelp();
  624.                     printf("\nInvalid Thread Count\n");
  625.                     exit(-1);
  626.                 }
  627.                
  628.                 continue;
  629.             }
  630.             if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
  631.             {
  632.                 printHelp();
  633.                 exit(0);
  634.             }
  635.             printHelp();
  636.             printf("\nInvalid Option, %s\n\n", argv[i]);
  637.             exit(-1);
  638.         }
  639.     }
  640.    
  641.     uint8_t problemSize;
  642.     uint8_t* problem;
  643.    
  644.     //if we are here and filename is null it was not found
  645.     if(filename)
  646.     {
  647.         //load the problem
  648.         problem = readProblem(filename, &problemSize);
  649.         printf("Read in problem from file:\n\n");
  650.         printProblem(problem, problemSize);
  651.     }
  652.     else
  653.     {
  654.         printf("\nNo file name specified, using a random 5x5 problem:\n\n");
  655.         problemSize = 5;
  656.         problem = randomProblem(problemSize);
  657.         printProblem(problem, problemSize);
  658.     }
  659.    
  660.     //start timing how fast the solution takes to generate (on OSX only)
  661. #ifdef __MACH__
  662.     uint64_t start = mach_absolute_time();
  663. #endif
  664.    
  665.     //path always starts in the upper left, prime the path cache
  666.     problem[1] = 1;
  667.    
  668.     //SOVLE IT
  669.     long solutionCount;
  670.     solutionCount = solveProblem(problem, problemSize, maxThreads);
  671.    
  672.     //on OSX
  673. #ifdef __MACH__
  674.     double elapsedTime = (double)(mach_absolute_time() - start) / 1e9;
  675.     uint32_t minutes = elapsedTime/60;
  676.     double seconds = elapsedTime - minutes*60;
  677.    
  678.     printf("\n\nFound %ld solutions in %u minutes and %.4f seconds\n", solutionCount, minutes, seconds);
  679.    
  680.     //other platforms
  681. #else
  682.     printf("\n\nFound %ld solutions\n", solutionCount);
  683.    
  684. #endif  
  685.    
  686.     //free the problem
  687.     free(problem);
  688.        
  689.     //Cave Johnson, we're done here
  690.     return 0;
  691. }