PageRenderTime 56ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/mona/src/muzz/evolveMuzzes.cpp

#
C++ | 1485 lines | 1215 code | 168 blank | 102 comment | 249 complexity | 10795a1d540cbea02fea4518a0bdde4d MD5 | raw file
  1. // For conditions of distribution and use, see copyright notice in muzz.hpp
  2. // Evolve muzzes by mutating and recombining brain parameters.
  3. #include "evolveMuzzes.hpp"
  4. // Version (SCCS "what" format).
  5. const char *MuzzEvolveVersion = MUZZ_EVOLVE_VERSION;
  6. // Print version.
  7. void
  8. printEvolveVersion(FILE *out = stdout)
  9. {
  10. fprintf(out, "%s\n", &MuzzEvolveVersion[4]);
  11. }
  12. // Usage.
  13. char *Usage[] =
  14. {
  15. (char *)"To run:",
  16. (char *)" evolve_muzzes",
  17. (char *)" -generations <evolution generations>",
  18. (char *)" [-muzzCycles (muzz cycles per run)]",
  19. (char *)" [-initHunger (initial hunger)]",
  20. (char *)" [-initThirst (initial thirst)]",
  21. (char *)" [-input <evolution input file name> (for run continuation)]",
  22. (char *)" -output <evolution output file name>",
  23. (char *)" [-mutationRate <mutation rate>]",
  24. (char *)" [-randomSeed <random seed> (for new run)]",
  25. (char *)" [-objectSeed <object generation seed>]",
  26. (char *)" [-terrainSeed <terrain generation seed>]",
  27. (char *)" [-terrainDimension <terrain size = dimension x dimension> (minimum=2)]",
  28. (char *)" [-minTrainingTrials (minimum number of training trials per test trial)]",
  29. (char *)" [-maxTrainingTrials (maximum number of training trials per test trial)]",
  30. (char *)" [-logfile <log file name>]",
  31. (char *)" [-ignoreInterrupts (ignore interrupts)]",
  32. #ifdef WIN32
  33. (char *)" [-attachConsole (attach to console)]",
  34. #endif
  35. (char *)"To run an evolved muzz with graphics:",
  36. (char *)" evolve_muzzes",
  37. (char *)" -muzz <identifier> (? to list available muzzes)",
  38. (char *)" [-muzzCycles (number of cycles)]",
  39. (char *)" [-initHunger (initial hunger)]",
  40. (char *)" [-initThirst (initial thirst)]",
  41. (char *)" -input <evolution input file name>",
  42. (char *)" [-pause (start paused)]",
  43. (char *)"To print version:",
  44. (char *)" evolve_muzzes",
  45. (char *)" [-version (print version)]",
  46. NULL
  47. };
  48. // Print and log error.
  49. void printError(char *buf)
  50. {
  51. fprintf(stderr, "%s\n", buf);
  52. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  53. {
  54. sprintf(Log::messageBuf, "%s", buf);
  55. Log::logError();
  56. }
  57. }
  58. // Print and log information.
  59. void printInfo(char *buf)
  60. {
  61. fprintf(stderr, "%s\n", buf);
  62. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  63. {
  64. sprintf(Log::messageBuf, "%s", buf);
  65. Log::logInformation();
  66. }
  67. }
  68. // Print usage.
  69. void printUsage()
  70. {
  71. for (int i = 0; Usage[i] != NULL; i++)
  72. {
  73. printInfo(Usage[i]);
  74. }
  75. }
  76. // Evolution generation.
  77. int Generation = 0;
  78. // Generations to run.
  79. int Generations;
  80. // Mutation rate.
  81. PROBABILITY MutationRate = DEFAULT_MUTATION_RATE;
  82. // Number of training trials.
  83. int MinTrainingTrials = DEFAULT_MIN_TRAINING_TRIALS;
  84. int MaxTrainingTrials = DEFAULT_MAX_TRAINING_TRIALS;
  85. // Population file names.
  86. char *InputFileName;
  87. char *OutputFileName;
  88. // Save default muzz.
  89. Muzz *SaveMuzz;
  90. // Parameter mutator.
  91. class ParmMutator
  92. {
  93. public:
  94. // Probability of random mutation.
  95. static PROBABILITY RANDOM_MUTATION;
  96. typedef enum
  97. {
  98. INTEGER_PARM, FLOAT_PARM, DOUBLE_PARM
  99. }
  100. PARM_TYPE;
  101. PARM_TYPE type;
  102. enum { PARM_NAME_SIZE=50 };
  103. char name[PARM_NAME_SIZE];
  104. void *parm;
  105. double min;
  106. double max;
  107. double delta;
  108. // Constructors.
  109. ParmMutator()
  110. {
  111. type = DOUBLE_PARM;
  112. name[0] = '\0';
  113. parm = NULL;
  114. min = max = delta = 0.0f;
  115. }
  116. ParmMutator(PARM_TYPE type, char *name, void *parm,
  117. double min, double max, double delta)
  118. {
  119. this->type = type;
  120. strncpy(this->name, name, PARM_NAME_SIZE - 1);
  121. this->parm = parm;
  122. this->min = min;
  123. this->max = max;
  124. this->delta = delta;
  125. }
  126. // Mutate parameter.
  127. void mutate()
  128. {
  129. int i;
  130. float f;
  131. double d;
  132. if (!Randomizer->RAND_CHANCE(MutationRate)) { return; }
  133. switch (type)
  134. {
  135. case INTEGER_PARM:
  136. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  137. {
  138. *(int *)parm = (int)Randomizer->RAND_INTERVAL(min, max + 0.99);
  139. }
  140. else
  141. {
  142. i = *(int *)parm;
  143. if (Randomizer->RAND_BOOL())
  144. {
  145. i += (int)delta;
  146. if (i > (int)max) { i = (int)max; }
  147. }
  148. else
  149. {
  150. i -= (int)delta;
  151. if (i < (int)min) { i = (int)min; }
  152. }
  153. *(int *)parm = i;
  154. }
  155. break;
  156. case FLOAT_PARM:
  157. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  158. {
  159. *(float *)parm = (float)Randomizer->RAND_INTERVAL(min, max);
  160. }
  161. else
  162. {
  163. f = *(float *)parm;
  164. if (Randomizer->RAND_BOOL())
  165. {
  166. f += (float)delta;
  167. if (f > (float)max) { f = (float)max; }
  168. }
  169. else
  170. {
  171. f -= (float)delta;
  172. if (f < (float)min) { f = (float)min; }
  173. }
  174. *(float *)parm = f;
  175. }
  176. break;
  177. case DOUBLE_PARM:
  178. if (Randomizer->RAND_CHANCE(RANDOM_MUTATION))
  179. {
  180. *(double *)parm = (double)Randomizer->RAND_INTERVAL(min, max);
  181. }
  182. else
  183. {
  184. d = *(double *)parm;
  185. if (Randomizer->RAND_BOOL())
  186. {
  187. d += delta;
  188. if (d > max) { d = max; }
  189. }
  190. else
  191. {
  192. d -= delta;
  193. if (d < min) { d = min; }
  194. }
  195. *(double *)parm = d;
  196. }
  197. break;
  198. }
  199. }
  200. // Copy parameter from given one.
  201. void copy(ParmMutator *from)
  202. {
  203. switch (type)
  204. {
  205. case INTEGER_PARM:
  206. *(int *)parm = *(int *)from->parm;
  207. break;
  208. case FLOAT_PARM:
  209. *(float *)parm = *(float *)from->parm;
  210. break;
  211. case DOUBLE_PARM:
  212. *(double *)parm = *(double *)from->parm;
  213. break;
  214. }
  215. }
  216. };
  217. PROBABILITY ParmMutator::RANDOM_MUTATION = 0.1;
  218. // Brain parameter mutator.
  219. class BrainParmMutator
  220. {
  221. public:
  222. // Brain.
  223. Mona *brain;
  224. // Parameter mutators.
  225. vector<ParmMutator *> parmMutators;
  226. // Constructor.
  227. BrainParmMutator(Mona *brain)
  228. {
  229. this->brain = brain;
  230. // INITIAL_ENABLEMENT.
  231. ParmMutator *parmMutator =
  232. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"INITIAL_ENABLEMENT",
  233. (void *)&brain->INITIAL_ENABLEMENT, 0.1, 1.0, 0.1);
  234. assert(parmMutator != NULL);
  235. parmMutators.push_back(parmMutator);
  236. // DRIVE_ATTENUATION.
  237. parmMutator =
  238. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"DRIVE_ATTENUATION",
  239. (void *)&brain->DRIVE_ATTENUATION, 0.0, 1.0, 0.1);
  240. assert(parmMutator != NULL);
  241. parmMutators.push_back(parmMutator);
  242. // LEARNING_DECREASE_VELOCITY.
  243. parmMutator =
  244. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"LEARNING_DECREASE_VELOCITY",
  245. (void *)&brain->LEARNING_DECREASE_VELOCITY, 0.1, 0.9, 0.1);
  246. assert(parmMutator != NULL);
  247. parmMutators.push_back(parmMutator);
  248. // LEARNING_INCREASE_VELOCITY.
  249. parmMutator =
  250. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"LEARNING_INCREASE_VELOCITY",
  251. (void *)&brain->LEARNING_INCREASE_VELOCITY, 0.1, 0.9, 0.1);
  252. assert(parmMutator != NULL);
  253. parmMutators.push_back(parmMutator);
  254. // FIRING_STRENGTH_LEARNING_DAMPER.
  255. parmMutator =
  256. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"FIRING_STRENGTH_LEARNING_DAMPER",
  257. (void *)&brain->FIRING_STRENGTH_LEARNING_DAMPER, 0.05, 0.9, 0.05);
  258. assert(parmMutator != NULL);
  259. parmMutators.push_back(parmMutator);
  260. // RESPONSE_RANDOMNESS.
  261. parmMutator =
  262. new ParmMutator(ParmMutator::DOUBLE_PARM, (char *)"RESPONSE_RANDOMNESS",
  263. (void *)&brain->RESPONSE_RANDOMNESS, 0.01, 0.2, 0.01);
  264. assert(parmMutator != NULL);
  265. parmMutators.push_back(parmMutator);
  266. }
  267. // Destructor.
  268. ~BrainParmMutator()
  269. {
  270. for (int i = 0; i < (int)parmMutators.size(); i++)
  271. {
  272. delete parmMutators[i];
  273. }
  274. parmMutators.clear();
  275. }
  276. // Mutate.
  277. void mutate()
  278. {
  279. for (int i = 0; i < (int)parmMutators.size(); i++)
  280. {
  281. parmMutators[i]->mutate();
  282. }
  283. // Initialize effect event intervals and weights.
  284. brain->initEffectEventIntervals();
  285. brain->initEffectEventIntervalWeights();
  286. brain->initMaxLearningEffectEventIntervals();
  287. // Initialize brain with new parameters.
  288. Muzz::initBrain(brain);
  289. }
  290. // Copy parameters from given brain.
  291. void copy(BrainParmMutator *from)
  292. {
  293. for (int i = 0; i < (int)parmMutators.size(); i++)
  294. {
  295. parmMutators[i]->copy(from->parmMutators[i]);
  296. }
  297. // Initialize effect intervals.
  298. brain->initEffectEventIntervals();
  299. brain->initEffectEventIntervalWeights();
  300. brain->initMaxLearningEffectEventIntervals();
  301. // Initialize brain with new parameters.
  302. Muzz::initBrain(brain);
  303. }
  304. // Randomly merge parameters from given brains.
  305. void meld(BrainParmMutator *from1, BrainParmMutator *from2)
  306. {
  307. for (int i = 0; i < (int)parmMutators.size(); i++)
  308. {
  309. if (Randomizer->RAND_BOOL())
  310. {
  311. parmMutators[i]->copy(from1->parmMutators[i]);
  312. }
  313. else
  314. {
  315. parmMutators[i]->copy(from2->parmMutators[i]);
  316. }
  317. }
  318. // Initialize effect intervals.
  319. brain->initEffectEventIntervals();
  320. brain->initEffectEventIntervalWeights();
  321. brain->initMaxLearningEffectEventIntervals();
  322. // Initialize brain with new parameters.
  323. Muzz::initBrain(brain);
  324. }
  325. };
  326. // Population member.
  327. class Member
  328. {
  329. public:
  330. Muzz *muzz;
  331. double fitness;
  332. int generation;
  333. // Brain parameter mutator.
  334. BrainParmMutator *brainParmMutator;
  335. // Muzz placement.
  336. static GLfloat MuzzX, MuzzY, MuzzDir;
  337. // Constructors.
  338. Member(int generation = 0)
  339. {
  340. float color[3];
  341. for (int i = 0; i < 3; i++)
  342. {
  343. color[i] = Randomizer->RAND_INTERVAL(0.0, 1.0);
  344. }
  345. muzz = new Muzz(color, Terrain, Randomizer->RAND(), Randomizer);
  346. assert(muzz != NULL);
  347. muzz->place(MuzzX, MuzzY, MuzzDir);
  348. // Create brain parameter mutator.
  349. brainParmMutator = new BrainParmMutator(muzz->brain);
  350. assert(brainParmMutator != NULL);
  351. brainParmMutator->mutate();
  352. fitness = 0.0;
  353. this->generation = generation;
  354. }
  355. // Destructor.
  356. ~Member()
  357. {
  358. if (brainParmMutator != NULL) { delete brainParmMutator; }
  359. if (muzz != NULL) { delete muzz; }
  360. }
  361. // Evaluate.
  362. // Fitness is determined by cycle count to goals,
  363. // so lesser value is fitter.
  364. void evaluate(int trainTrials)
  365. {
  366. int foodCycle, waterCycle;
  367. // Use member muzz.
  368. Muzzes[0] = muzz;
  369. // Run muzz world.
  370. if (Graphics)
  371. {
  372. // Should not return.
  373. resetMuzzWorld();
  374. runMuzzWorld();
  375. Muzzes[0] = NULL;
  376. return;
  377. }
  378. // Training?
  379. if (trainTrials > 0)
  380. {
  381. ForcedResponseTrain = true;
  382. NumTrainingTrials = trainTrials;
  383. runMuzzWorld();
  384. ForcedResponseTrain = false;
  385. NumTrainingTrials = -1;
  386. }
  387. // Test run.
  388. resetMuzzWorld();
  389. NumTrainingTrials = -1;
  390. RunMuzzWorldUntilGoalsGotten = true;
  391. runMuzzWorld();
  392. RunMuzzWorldUntilGoalsGotten = false;
  393. foodCycle = Muzzes[0]->gotFoodCycle;
  394. waterCycle = Muzzes[0]->gotWaterCycle;
  395. Muzzes[0] = NULL;
  396. if (foodCycle != -1)
  397. {
  398. if (waterCycle != -1)
  399. {
  400. if (foodCycle > waterCycle)
  401. {
  402. sprintf(Log::messageBuf, "Found food and water at cycle %d", foodCycle);
  403. }
  404. else
  405. {
  406. sprintf(Log::messageBuf, "Found food and water at cycle %d", waterCycle);
  407. }
  408. }
  409. else
  410. {
  411. sprintf(Log::messageBuf, "Found only food at cycle %d", foodCycle);
  412. }
  413. }
  414. else
  415. {
  416. if (waterCycle != -1)
  417. {
  418. sprintf(Log::messageBuf, "Found only water at cycle %d", waterCycle);
  419. }
  420. else
  421. {
  422. sprintf(Log::messageBuf, "Food and water not found");
  423. }
  424. }
  425. Log::logInformation();
  426. // Determine fitness.
  427. if (foodCycle == -1) { foodCycle = Cycles; }
  428. if (waterCycle == -1) { waterCycle = Cycles; }
  429. fitness = (double)max(foodCycle, waterCycle);
  430. }
  431. // Get fitness.
  432. double getFitness()
  433. {
  434. return(fitness);
  435. }
  436. // Create mutated member by varying brain parameters.
  437. void mutate(Member *member)
  438. {
  439. brainParmMutator->copy(member->brainParmMutator);
  440. brainParmMutator->mutate();
  441. }
  442. // Merge given member brain parameters into this brain.
  443. void mindMeld(Member *member1, Member *member2)
  444. {
  445. brainParmMutator->meld(member1->brainParmMutator,
  446. member2->brainParmMutator);
  447. }
  448. // Load.
  449. void load(FILE *fp)
  450. {
  451. muzz->load(fp);
  452. FREAD_DOUBLE(&fitness, fp);
  453. FREAD_INT(&generation, fp);
  454. }
  455. // Save.
  456. void save(FILE *fp)
  457. {
  458. muzz->save(fp);
  459. FWRITE_DOUBLE(&fitness, fp);
  460. FWRITE_INT(&generation, fp);
  461. }
  462. // Print.
  463. void print()
  464. {
  465. printf("fitness=%f, generation=%d\n", getFitness(), generation);
  466. printf("muzz brain:\n");
  467. muzz->printBrain();
  468. }
  469. };
  470. // Muzz placement in world.
  471. GLfloat Member::MuzzX = 0.0f;
  472. GLfloat Member::MuzzY = 0.0f;
  473. GLfloat Member::MuzzDir = 0.0f;
  474. // Population.
  475. Member *Population[POPULATION_SIZE];
  476. // Start/end functions.
  477. void logParameters();
  478. void loadPopulation(FILE *fp);
  479. void savePopulation(FILE *fp);
  480. // Evolve functions.
  481. void evolve(), evaluate(), prune(), mutate(), mate();
  482. #ifdef WIN32
  483. #ifdef _DEBUG
  484. // For Windows memory checking, set CHECK_MEMORY = 1.
  485. #define CHECK_MEMORY 0
  486. #if (CHECK_MEMORY == 1)
  487. #define MEMORY_CHECK_FILE "memory.txt"
  488. #include <crtdbg.h>
  489. #endif
  490. #endif
  491. #endif
  492. // Main.
  493. int main(int argc, char *argv[])
  494. {
  495. int i;
  496. FILE *fp;
  497. int muzzID;
  498. char buf[200];
  499. #if (CHECK_MEMORY == 1)
  500. {
  501. #endif
  502. #ifdef WIN32
  503. // Attach to parent console?
  504. if (_isatty(1))
  505. {
  506. for (i = 1; i < argc; i++)
  507. {
  508. if (strcmp(argv[i], "-attachConsole") == 0)
  509. {
  510. break;
  511. }
  512. }
  513. if (i < argc)
  514. {
  515. FreeConsole();
  516. if (AttachConsole(ATTACH_PARENT_PROCESS))
  517. {
  518. freopen("CONOUT$", "w", stdout);
  519. freopen("CONOUT$", "w", stderr);
  520. freopen("CONIN$", "r", stdin);
  521. }
  522. }
  523. }
  524. #endif
  525. // Initialize logging..
  526. Log::LOGGING_FLAG = LOG_TO_PRINT;
  527. // Process glut args.
  528. glutInit(&argc, argv);
  529. // Parse arguments.
  530. Generations = -1;
  531. InputFileName = OutputFileName = NULL;
  532. RandomSeed = INVALID_RANDOM;
  533. muzzID = -1;
  534. bool gotTerrainDimension = false;
  535. bool gotMinTrainingTrials = false;
  536. bool gotMaxTrainingTrials = false;
  537. for (i = 1; i < argc; i++)
  538. {
  539. if (strcmp(argv[i], "-generations") == 0)
  540. {
  541. i++;
  542. if (i >= argc)
  543. {
  544. printUsage();
  545. exit(1);
  546. }
  547. Generations = atoi(argv[i]);
  548. if (Generations < 0)
  549. {
  550. printUsage();
  551. exit(1);
  552. }
  553. continue;
  554. }
  555. if (strcmp(argv[i], "-muzzCycles") == 0)
  556. {
  557. i++;
  558. if (i >= argc)
  559. {
  560. printUsage();
  561. exit(1);
  562. }
  563. if ((Cycles = atoi(argv[i])) < 0)
  564. {
  565. printUsage();
  566. exit(1);
  567. }
  568. continue;
  569. }
  570. if (strcmp(argv[i], "-initHunger") == 0)
  571. {
  572. i++;
  573. if (i >= argc)
  574. {
  575. printUsage();
  576. exit(1);
  577. }
  578. Muzz::INIT_HUNGER = atof(argv[i]);
  579. if ((Muzz::INIT_HUNGER < 0.0) || (Muzz::INIT_HUNGER > 1.0))
  580. {
  581. printUsage();
  582. exit(1);
  583. }
  584. continue;
  585. }
  586. if (strcmp(argv[i], "-initThirst") == 0)
  587. {
  588. i++;
  589. if (i >= argc)
  590. {
  591. printUsage();
  592. exit(1);
  593. }
  594. Muzz::INIT_THIRST = atof(argv[i]);
  595. if ((Muzz::INIT_THIRST < 0.0) || (Muzz::INIT_THIRST > 1.0))
  596. {
  597. printUsage();
  598. exit(1);
  599. }
  600. continue;
  601. }
  602. if (strcmp(argv[i], "-input") == 0)
  603. {
  604. i++;
  605. if (i >= argc)
  606. {
  607. printUsage();
  608. exit(1);
  609. }
  610. InputFileName = argv[i];
  611. continue;
  612. }
  613. if (strcmp(argv[i], "-output") == 0)
  614. {
  615. i++;
  616. if (i >= argc)
  617. {
  618. printUsage();
  619. exit(1);
  620. }
  621. OutputFileName = argv[i];
  622. continue;
  623. }
  624. if (strcmp(argv[i], "-mutationRate") == 0)
  625. {
  626. i++;
  627. if (i >= argc)
  628. {
  629. printUsage();
  630. exit(1);
  631. }
  632. MutationRate = atof(argv[i]);
  633. if (MutationRate < 0.0)
  634. {
  635. printUsage();
  636. exit(1);
  637. }
  638. continue;
  639. }
  640. if (strcmp(argv[i], "-randomSeed") == 0)
  641. {
  642. i++;
  643. if (i >= argc)
  644. {
  645. printUsage();
  646. exit(1);
  647. }
  648. RandomSeed = (RANDOM)atoi(argv[i]);
  649. continue;
  650. }
  651. if (strcmp(argv[i], "-objectSeed") == 0)
  652. {
  653. i++;
  654. if (i >= argc)
  655. {
  656. printUsage();
  657. exit(1);
  658. }
  659. ObjectSeed = (RANDOM)atoi(argv[i]);
  660. continue;
  661. }
  662. if (strcmp(argv[i], "-terrainSeed") == 0)
  663. {
  664. i++;
  665. if (i >= argc)
  666. {
  667. printUsage();
  668. exit(1);
  669. }
  670. TerrainSeed = (RANDOM)atoi(argv[i]);
  671. continue;
  672. }
  673. if (strcmp(argv[i], "-terrainDimension") == 0)
  674. {
  675. i++;
  676. if (i >= argc)
  677. {
  678. printUsage();
  679. exit(1);
  680. }
  681. if ((TerrainDimension = atoi(argv[i])) < 2)
  682. {
  683. printError((char *)"Invalid terrain dimension");
  684. printUsage();
  685. exit(1);
  686. }
  687. gotTerrainDimension = true;
  688. continue;
  689. }
  690. if (strcmp(argv[i], "-logfile") == 0)
  691. {
  692. i++;
  693. if (i >= argc)
  694. {
  695. printUsage();
  696. exit(1);
  697. }
  698. Log::LOGGING_FLAG = LOG_TO_FILE;
  699. Log::setLogFileName(argv[i]);
  700. continue;
  701. }
  702. if (strcmp(argv[i], "-muzz") == 0)
  703. {
  704. i++;
  705. if (i >= argc)
  706. {
  707. printUsage();
  708. exit(1);
  709. }
  710. if (argv[i][0] == '?')
  711. {
  712. muzzID = -2;
  713. }
  714. else
  715. {
  716. muzzID = atoi(argv[i]);
  717. if (muzzID < 0)
  718. {
  719. printError((char *)"Invalid muzz identifier");
  720. printUsage();
  721. exit(1);
  722. }
  723. }
  724. continue;
  725. }
  726. if (strcmp(argv[i], "-minTrainingTrials") == 0)
  727. {
  728. i++;
  729. if (i >= argc)
  730. {
  731. printUsage();
  732. exit(1);
  733. }
  734. MinTrainingTrials = atoi(argv[i]);
  735. if (MinTrainingTrials < 0)
  736. {
  737. printError((char *)"Invalid minimum number of training trials");
  738. printUsage();
  739. exit(1);
  740. }
  741. gotMinTrainingTrials = true;
  742. continue;
  743. }
  744. if (strcmp(argv[i], "-maxTrainingTrials") == 0)
  745. {
  746. i++;
  747. if (i >= argc)
  748. {
  749. printUsage();
  750. exit(1);
  751. }
  752. MaxTrainingTrials = atoi(argv[i]);
  753. if (MaxTrainingTrials < 0)
  754. {
  755. printError((char *)"Invalid maximum number of training trials");
  756. printUsage();
  757. exit(1);
  758. }
  759. gotMaxTrainingTrials = true;
  760. continue;
  761. }
  762. if (strcmp(argv[i], "-pause") == 0)
  763. {
  764. Pause = true;
  765. continue;
  766. }
  767. if (strcmp(argv[i], "-ignoreInterrupts") == 0)
  768. {
  769. signal(SIGINT, SIG_IGN);
  770. continue;
  771. }
  772. #ifdef WIN32
  773. if (strcmp(argv[i], "-attachConsole") == 0)
  774. {
  775. continue;
  776. }
  777. #endif
  778. if (strcmp(argv[i], "-version") == 0)
  779. {
  780. printEvolveVersion();
  781. printVersion();
  782. Mona::printVersion();
  783. exit(0);
  784. }
  785. printUsage();
  786. exit(1);
  787. }
  788. if (muzzID == -1)
  789. {
  790. if (Generations == -1)
  791. {
  792. printError((char *)"Generations option required");
  793. printUsage();
  794. exit(1);
  795. }
  796. if (OutputFileName == NULL)
  797. {
  798. printError((char *)"Output file required");
  799. printUsage();
  800. exit(1);
  801. }
  802. if ((InputFileName != NULL) &&
  803. ((RandomSeed != INVALID_RANDOM) ||
  804. (ObjectSeed != INVALID_RANDOM) ||
  805. (TerrainSeed != INVALID_RANDOM)))
  806. {
  807. printError((char *)"Random seeds are loaded from file");
  808. printUsage();
  809. exit(1);
  810. }
  811. if ((InputFileName != NULL) && gotTerrainDimension)
  812. {
  813. printError((char *)"Terrain dimension is loaded from file");
  814. printUsage();
  815. exit(1);
  816. }
  817. if (Pause)
  818. {
  819. printError((char *)"Pause option invalid without muzz identifier");
  820. printUsage();
  821. exit(1);
  822. }
  823. if (gotMinTrainingTrials && gotMaxTrainingTrials && (MinTrainingTrials > MaxTrainingTrials))
  824. {
  825. printError((char *)"Minimum number of training trials cannot exceed maximum");
  826. printUsage();
  827. exit(1);
  828. }
  829. if (gotMinTrainingTrials && (MinTrainingTrials > MaxTrainingTrials))
  830. {
  831. MaxTrainingTrials = MinTrainingTrials;
  832. }
  833. if (gotMaxTrainingTrials && (MinTrainingTrials > MaxTrainingTrials))
  834. {
  835. MinTrainingTrials = MaxTrainingTrials;
  836. }
  837. }
  838. else
  839. {
  840. if (InputFileName == NULL)
  841. {
  842. printError((char *)"Input file required with muzz identifier");
  843. printUsage();
  844. exit(1);
  845. }
  846. if (OutputFileName != NULL)
  847. {
  848. printError((char *)"Output file invalid with muzz identifier");
  849. printUsage();
  850. exit(1);
  851. }
  852. if (Generations != -1)
  853. {
  854. printError((char *)"Generations option invalid with muzz identifier");
  855. printUsage();
  856. exit(1);
  857. }
  858. if ((RandomSeed != INVALID_RANDOM) ||
  859. (ObjectSeed != INVALID_RANDOM) ||
  860. (TerrainSeed != INVALID_RANDOM))
  861. {
  862. printError((char *)"Random seeds are loaded from file");
  863. printUsage();
  864. exit(1);
  865. }
  866. if (gotTerrainDimension)
  867. {
  868. printError((char *)"Terrain dimension is loaded from file");
  869. printUsage();
  870. exit(1);
  871. }
  872. if (gotMinTrainingTrials || gotMaxTrainingTrials)
  873. {
  874. printError((char *)"Training trials options invalid with muzz identifier");
  875. printUsage();
  876. exit(1);
  877. }
  878. }
  879. // Seed random numbers.
  880. if (InputFileName != NULL)
  881. {
  882. if ((RandomSeed != INVALID_RANDOM) ||
  883. (ObjectSeed != INVALID_RANDOM) ||
  884. (TerrainSeed != INVALID_RANDOM))
  885. {
  886. printError((char *)"Random seeds are loaded from input file");
  887. printUsage();
  888. exit(1);
  889. }
  890. if (gotTerrainDimension)
  891. {
  892. printError((char *)"Terrain dimension is loaded from input file");
  893. printUsage();
  894. exit(1);
  895. }
  896. if ((fp = FOPEN_READ(InputFileName)) == NULL)
  897. {
  898. sprintf(buf, "Cannot load population file %s", InputFileName);
  899. printError(buf);
  900. exit(1);
  901. }
  902. FREAD_LONG(&RandomSeed, fp);
  903. Randomizer = new Random(RandomSeed);
  904. assert(Randomizer != NULL);
  905. Randomizer->RAND_LOAD(fp);
  906. FREAD_LONG(&ObjectSeed, fp);
  907. FREAD_LONG(&TerrainSeed, fp);
  908. FREAD_INT(&TerrainDimension, fp);
  909. FREAD_INT(&Generation, fp);
  910. }
  911. else
  912. {
  913. fp = NULL;
  914. if (RandomSeed == INVALID_RANDOM)
  915. {
  916. RandomSeed = (RANDOM)time(NULL);
  917. }
  918. Randomizer = new Random(RandomSeed);
  919. assert(Randomizer != NULL);
  920. Randomizer->SRAND(RandomSeed);
  921. if (ObjectSeed == INVALID_RANDOM)
  922. {
  923. ObjectSeed = RandomSeed;
  924. }
  925. if (TerrainSeed == INVALID_RANDOM)
  926. {
  927. TerrainSeed = RandomSeed;
  928. }
  929. }
  930. if (muzzID == -1)
  931. {
  932. Log::logInformation((char *)"Initializing evolve:");
  933. sprintf(Log::messageBuf, "generations=%d", Generations);
  934. Log::logInformation();
  935. if (InputFileName != NULL)
  936. {
  937. sprintf(Log::messageBuf, "input=%s", InputFileName);
  938. Log::logInformation();
  939. }
  940. sprintf(Log::messageBuf, "output=%s", OutputFileName);
  941. Log::logInformation();
  942. }
  943. // Initialize muzz world.
  944. if (muzzID == -1)
  945. {
  946. Graphics = false;
  947. if (Cycles == -1)
  948. {
  949. Cycles = DEFAULT_MUZZ_CYCLES;
  950. }
  951. }
  952. SaveFile = LoadFile = NULL;
  953. SmoothMove = false;
  954. initMuzzWorld();
  955. Member::MuzzX = Muzzes[0]->getPlaceX();
  956. Member::MuzzY = Muzzes[0]->getPlaceY();
  957. Member::MuzzDir = Muzzes[0]->getPlaceDirection();
  958. // Remove default muzz since population member will be used.
  959. SaveMuzz = Muzzes[0];
  960. Muzzes[0] = NULL;
  961. // Log run parameters.
  962. if (muzzID == -1)
  963. {
  964. logParameters();
  965. }
  966. // Create population.
  967. if (fp == NULL)
  968. {
  969. for (i = 0; i < POPULATION_SIZE; i++)
  970. {
  971. Population[i] = new Member(0);
  972. assert(Population[i] != NULL);
  973. }
  974. }
  975. else
  976. {
  977. // Continue run.
  978. loadPopulation(fp);
  979. FCLOSE(fp);
  980. }
  981. // Running a muzz?
  982. if (muzzID != -1)
  983. {
  984. if (muzzID == -2)
  985. {
  986. sprintf(buf, "Muzz identifiers:");
  987. printf("%s\n", buf);
  988. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  989. {
  990. sprintf(Log::messageBuf, "%s", buf);
  991. Log::logInformation();
  992. }
  993. for (i = 0; i < POPULATION_SIZE; i++)
  994. {
  995. sprintf(buf, "%d", Population[i]->muzz->id);
  996. printf("%s\n", buf);
  997. if (Log::LOGGING_FLAG == LOG_TO_FILE)
  998. {
  999. sprintf(Log::messageBuf, "%s", buf);
  1000. Log::logInformation();
  1001. }
  1002. }
  1003. }
  1004. else
  1005. {
  1006. for (i = 0; i < POPULATION_SIZE; i++)
  1007. {
  1008. if ((Population[i] != NULL) && (Population[i]->muzz->id == muzzID))
  1009. {
  1010. break;
  1011. }
  1012. }
  1013. if (i == POPULATION_SIZE)
  1014. {
  1015. printError((char *)"Invalid muzz identifier");
  1016. exit(1);
  1017. }
  1018. if (Cycles == -1)
  1019. {
  1020. SmoothMove = true;
  1021. }
  1022. else
  1023. {
  1024. SmoothMove = false;
  1025. }
  1026. Population[i]->evaluate(0);
  1027. }
  1028. }
  1029. else
  1030. {
  1031. // Evolution loop.
  1032. Log::logInformation((char *)"Begin evolve:");
  1033. for (i = 0; i < Generations; i++, Generation++)
  1034. {
  1035. sprintf(Log::messageBuf, "Generation=%d", Generation);
  1036. Log::logInformation();
  1037. evolve();
  1038. // Save population?
  1039. if ((i % SAVE_FREQUENCY) == 0)
  1040. {
  1041. if ((fp = FOPEN_WRITE(OutputFileName)) == NULL)
  1042. {
  1043. sprintf(buf, "Cannot save to population file %s", OutputFileName);
  1044. printError(buf);
  1045. exit(1);
  1046. }
  1047. FWRITE_LONG(&RandomSeed, fp);
  1048. Randomizer->RAND_SAVE(fp);
  1049. FWRITE_LONG(&ObjectSeed, fp);
  1050. FWRITE_LONG(&TerrainSeed, fp);
  1051. FWRITE_INT(&TerrainDimension, fp);
  1052. FWRITE_INT(&Generation, fp);
  1053. savePopulation(fp);
  1054. FCLOSE(fp);
  1055. }
  1056. }
  1057. // Save population.
  1058. if ((fp = FOPEN_WRITE(OutputFileName)) == NULL)
  1059. {
  1060. sprintf(buf, "Cannot save to population file %s", OutputFileName);
  1061. printError(buf);
  1062. exit(1);
  1063. }
  1064. FWRITE_LONG(&RandomSeed, fp);
  1065. Randomizer->RAND_SAVE(fp);
  1066. FWRITE_LONG(&ObjectSeed, fp);
  1067. FWRITE_LONG(&TerrainSeed, fp);
  1068. FWRITE_INT(&TerrainDimension, fp);
  1069. FWRITE_INT(&Generation, fp);
  1070. savePopulation(fp);
  1071. FCLOSE(fp);
  1072. }
  1073. // Release memory.
  1074. for (i = 0; i < POPULATION_SIZE; i++)
  1075. {
  1076. if (Population[i] != NULL)
  1077. {
  1078. delete Population[i];
  1079. Population[i] = NULL;
  1080. }
  1081. }
  1082. Muzzes[0] = SaveMuzz;
  1083. termMuzzWorld();
  1084. // Close log.
  1085. if (muzzID == -1)
  1086. {
  1087. Log::logInformation((char *)"End evolve");
  1088. }
  1089. Log::close();
  1090. #if (CHECK_MEMORY == 1)
  1091. }
  1092. // Check for memory leaks.
  1093. printf("Checking for memory leaks, report in file %s\n",
  1094. MEMORY_CHECK_FILE);
  1095. HANDLE hFile = CreateFile(
  1096. MEMORY_CHECK_FILE,
  1097. GENERIC_WRITE,
  1098. FILE_SHARE_WRITE,
  1099. NULL,
  1100. OPEN_ALWAYS,
  1101. 0,
  1102. NULL
  1103. );
  1104. if (hFile == INVALID_HANDLE_VALUE)
  1105. {
  1106. fprintf(stderr, "Cannot open memory check file %s",
  1107. MEMORY_CHECK_FILE);
  1108. exit(1);
  1109. }
  1110. _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
  1111. _CrtSetReportFile(_CRT_WARN, hFile);
  1112. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
  1113. _CrtSetReportFile(_CRT_ERROR, hFile);
  1114. if (!_CrtDumpMemoryLeaks())
  1115. {
  1116. printf("No memory leaks\n");
  1117. }
  1118. else
  1119. {
  1120. printf("Memory leaks found\n");
  1121. }
  1122. CloseHandle(hFile);
  1123. #endif
  1124. return(0);
  1125. }
  1126. // Log run parameters.
  1127. void logParameters()
  1128. {
  1129. Log::logInformation((char *)"Evolve Parameters:");
  1130. sprintf(Log::messageBuf, "RandomSeed = %lu", RandomSeed);
  1131. Log::logInformation();
  1132. sprintf(Log::messageBuf, "ObjectSeed = %lu", ObjectSeed);
  1133. Log::logInformation();
  1134. sprintf(Log::messageBuf, "TerrainSeed = %lu", TerrainSeed);
  1135. Log::logInformation();
  1136. sprintf(Log::messageBuf, "FIT_POPULATION_SIZE = %d", FIT_POPULATION_SIZE);
  1137. Log::logInformation();
  1138. sprintf(Log::messageBuf, "NUM_MUTANTS = %d", NUM_MUTANTS);
  1139. Log::logInformation();
  1140. sprintf(Log::messageBuf, "NUM_OFFSPRING = %d", NUM_OFFSPRING);
  1141. Log::logInformation();
  1142. sprintf(Log::messageBuf, "MutationRate = %f", MutationRate);
  1143. Log::logInformation();
  1144. sprintf(Log::messageBuf, "MUZZ_CYCLES = %d", Cycles);
  1145. Log::logInformation();
  1146. Log::logInformation((char *)"Muzz Parameters:");
  1147. sprintf(Log::messageBuf, "INIT_HUNGER = %f", Muzz::INIT_HUNGER);
  1148. Log::logInformation();
  1149. sprintf(Log::messageBuf, "INIT_THIRST = %f", Muzz::INIT_THIRST);
  1150. Log::logInformation();
  1151. sprintf(Log::messageBuf, "EAT_GOAL_VALUE = %f", Muzz::EAT_GOAL_VALUE);
  1152. Log::logInformation();
  1153. sprintf(Log::messageBuf, "DRINK_GOAL_VALUE = %f", Muzz::DRINK_GOAL_VALUE);
  1154. Log::logInformation();
  1155. sprintf(Log::messageBuf, "MinTrainingTrials = %d", MinTrainingTrials);
  1156. Log::logInformation();
  1157. sprintf(Log::messageBuf, "MaxTrainingTrials = %d", MaxTrainingTrials);
  1158. Log::logInformation();
  1159. Log::logInformation((char *)"Terrain Parameters:");
  1160. sprintf(Log::messageBuf, "WIDTH = %d", Terrain->WIDTH);
  1161. Log::logInformation();
  1162. sprintf(Log::messageBuf, "HEIGHT = %d", Terrain->HEIGHT);
  1163. Log::logInformation();
  1164. sprintf(Log::messageBuf, "MAX_PLATFORM_ELEVATION = %d", Terrain->MAX_PLATFORM_ELEVATION);
  1165. Log::logInformation();
  1166. sprintf(Log::messageBuf, "MIN_PLATFORM_SIZE = %d", Terrain->MIN_PLATFORM_SIZE);
  1167. Log::logInformation();
  1168. sprintf(Log::messageBuf, "MAX_PLATFORM_SIZE = %d", Terrain->MAX_PLATFORM_SIZE);
  1169. Log::logInformation();
  1170. sprintf(Log::messageBuf, "MAX_PLATFORM_GENERATIONS = %d", Terrain->MAX_PLATFORM_GENERATIONS);
  1171. Log::logInformation();
  1172. sprintf(Log::messageBuf, "EXTRA_RAMPS = %d", Terrain->EXTRA_RAMPS);
  1173. Log::logInformation();
  1174. }
  1175. // Load evolution population.
  1176. void loadPopulation(FILE *fp)
  1177. {
  1178. for (int i = 0; i < POPULATION_SIZE; i++)
  1179. {
  1180. Population[i] = new Member();
  1181. assert(Population[i] != NULL);
  1182. Population[i]->load(fp);
  1183. }
  1184. }
  1185. // Save evolution population.
  1186. void savePopulation(FILE *fp)
  1187. {
  1188. for (int i = 0; i < POPULATION_SIZE; i++)
  1189. {
  1190. Population[i]->save(fp);
  1191. }
  1192. }
  1193. // Evolution generation.
  1194. void evolve()
  1195. {
  1196. // Evaluate member fitness.
  1197. evaluate();
  1198. // Prune unfit members.
  1199. prune();
  1200. // Create new members by mutation.
  1201. mutate();
  1202. // Create new members by mating.
  1203. mate();
  1204. }
  1205. // Evaluate member fitnesses.
  1206. void evaluate()
  1207. {
  1208. int i, j;
  1209. Log::logInformation((char *)"Evaluate:");
  1210. for (i = 0; i < POPULATION_SIZE; i++)
  1211. {
  1212. Muzz::initBrain(Population[i]->muzz->brain);
  1213. // Evaluate.
  1214. j = Randomizer->RAND_CHOICE(MaxTrainingTrials - MinTrainingTrials + 1) + MinTrainingTrials;
  1215. Population[i]->evaluate(j);
  1216. sprintf(Log::messageBuf, " Member=%d, Muzz=%d, Fitness=%f, Generation=%d",
  1217. i, Population[i]->muzz->id, Population[i]->getFitness(), Population[i]->generation);
  1218. Log::logInformation();
  1219. }
  1220. }
  1221. // Prune unfit members.
  1222. void prune()
  1223. {
  1224. double min;
  1225. int i, j, m;
  1226. Member *member;
  1227. Member *fitPopulation[FIT_POPULATION_SIZE];
  1228. Log::logInformation((char *)"Select:");
  1229. for (i = 0; i < FIT_POPULATION_SIZE; i++)
  1230. {
  1231. m = -1;
  1232. for (j = 0; j < POPULATION_SIZE; j++)
  1233. {
  1234. member = Population[j];
  1235. if (member == NULL)
  1236. {
  1237. continue;
  1238. }
  1239. if ((m == -1) || (member->getFitness() < min))
  1240. {
  1241. m = j;
  1242. min = member->getFitness();
  1243. }
  1244. }
  1245. member = Population[m];
  1246. Population[m] = NULL;
  1247. fitPopulation[i] = member;
  1248. sprintf(Log::messageBuf, " Muzz=%d, Fitness=%f, Generation=%d",
  1249. member->muzz->id, member->getFitness(), member->generation);
  1250. Log::logInformation();
  1251. }
  1252. for (i = 0; i < POPULATION_SIZE; i++)
  1253. {
  1254. if (Population[i] != NULL)
  1255. {
  1256. delete Population[i];
  1257. Population[i] = NULL;
  1258. }
  1259. }
  1260. for (i = 0; i < FIT_POPULATION_SIZE; i++)
  1261. {
  1262. Population[i] = fitPopulation[i];
  1263. }
  1264. }
  1265. // Mutate members.
  1266. void mutate()
  1267. {
  1268. int i, j;
  1269. Member *member, *mutant;
  1270. Log::logInformation((char *)"Mutate:");
  1271. for (i = 0; i < NUM_MUTANTS; i++)
  1272. {
  1273. // Select a fit member to mutate.
  1274. j = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE);
  1275. member = Population[j];
  1276. // Create mutant member.
  1277. mutant = new Member(member->generation + 1);
  1278. assert(mutant != NULL);
  1279. Population[FIT_POPULATION_SIZE + i] = mutant;
  1280. sprintf(Log::messageBuf, " Member=%d, Muzz=%d -> Member=%d, Muzz=%d",
  1281. j, member->muzz->id, FIT_POPULATION_SIZE + i, mutant->muzz->id);
  1282. Log::logInformation();
  1283. // Mutate.
  1284. mutant->mutate(member);
  1285. }
  1286. }
  1287. // Produce offspring by "mind melding" parent brain parameters.
  1288. void mate()
  1289. {
  1290. int i, j, k;
  1291. Member *member1, *member2, *offspring;
  1292. Log::logInformation((char *)"Mate:");
  1293. if (FIT_POPULATION_SIZE < 2)
  1294. {
  1295. return;
  1296. }
  1297. for (i = 0; i < NUM_OFFSPRING; i++)
  1298. {
  1299. // Select a pair of fit members to mate.
  1300. j = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE);
  1301. member1 = Population[j];
  1302. while ((k = Randomizer->RAND_CHOICE(FIT_POPULATION_SIZE)) == j)
  1303. {
  1304. }
  1305. member2 = Population[k];
  1306. // Create offspring.
  1307. offspring = new Member((member1->generation > member2->generation ?
  1308. member1->generation : member2->generation) + 1);
  1309. assert(offspring != NULL);
  1310. Population[FIT_POPULATION_SIZE + NUM_MUTANTS + i] = offspring;
  1311. sprintf(Log::messageBuf, " Members=%d,%d, Muzzes=%d,%d -> Member=%d, Muzz=%d",
  1312. j, k, member1->muzz->id, member2->muzz->id, FIT_POPULATION_SIZE + NUM_MUTANTS + i, offspring->muzz->id);
  1313. Log::logInformation();
  1314. // Combine parent brains into offspring.
  1315. offspring->mindMeld(member1, member2);
  1316. }
  1317. }