PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/AIProgrammer.Fitness/Concrete/BottlesOfBeerFitness.cs

https://bitbucket.org/ryanboris/ai-programmer
C# | 213 lines | 147 code | 27 blank | 39 comment | 17 complexity | df2eae1f5b0c5e25761c7ecfba17bfaa MD5 | raw file
  1. using AIProgrammer.Fitness.Base;
  2. using AIProgrammer.GeneticAlgorithm;
  3. using AIProgrammer.Managers;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace AIProgrammer.Fitness.Concrete
  10. {
  11. /// <summary>
  12. /// "Ninety Nine Bottles of Beer on the Wall", starting from any number.
  13. /// The user is prompted for input of a starting number. The program outputs from the starting number "x bottles of beer on the wall" until it reaches 0.
  14. /// Example: input = 5: 5 bottles of beer on the wall4 bottles of beer on the wall3 bottles of beer on the wall2 bottles of beer on the wall1 bottles of beer on the wall0 bottles of beer on the wall
  15. /// Note, the final output will be in byte format (including text, ie. 98 = 'b'). To display the output for humans, we have to convert the text byte values to char and leave the numbers as byte. This will correctly display 598498398 as 5b4b3b, since (char)98 = 'b'.
  16. /// This class is best used with the BottlesOfBeerFunctions for appended code.
  17. /// Usage:
  18. /// In App.config:
  19. /// <add key="BrainfuckVersion" value="2"/>
  20. /// In Program.cs set:
  21. /// private static string _appendCode = BottlesOfBeerFitness.BottlesOfBeerFunctions;
  22. /// private static int _genomeSize = 30;
  23. /// ...
  24. /// private static IFitness GetFitnessMethod()
  25. /// {
  26. /// return new BottlesOfBeerFitness(_ga, _maxIterationCount, _appendCode);
  27. /// }
  28. /// </summary>
  29. public class BottlesOfBeerFitness : FitnessBase
  30. {
  31. private static byte[][] _trainingExamples = { new byte[] { 5, 4, 3, 2, 1, 0 },
  32. new byte[] { 3, 2, 1, 0 },
  33. new byte[] { 2, 1, 0 } };
  34. private static string _targetString = "bottles of beer on the wall";
  35. /// <summary>
  36. /// Previously generated BrainPlus functions for outputting the terms: bottles,of,beer,on,the,wall,bottles of beer,on the wall. The last two functions call sub-functions themselves. Generated using StrictStringFitness with StringFunction.
  37. /// To use, set _appendCode = BottlesOfBeerFitness.BottlesOfBeerFunctions in main program.
  38. /// </summary>
  39. public static string BottlesOfBeerFunctions = "7$>66++.!-.[!+><+++[[..-<[-t-$--[$.--$-$-$---.>.@7-[.!!>6++-$++++$+$.@7+$6++.+++..!+.@$7--+.+-$[[-[.@7++++.6++++++++.---.@7+++++++.7$6+.!----[..@$>!3$---------------a-.+-b.+!$!!>c@d3----------------.e.f@";
  40. public BottlesOfBeerFitness(GA ga, int maxIterationCount, string appendFunctions = null)
  41. : base(ga, maxIterationCount, appendFunctions)
  42. {
  43. if (_targetFitness == 0)
  44. {
  45. // Number of numeric values in training example * 256 + number of characters in target string * 256 * number of numeric values (since string is next to each number).
  46. foreach (byte[] trainingExample in _trainingExamples)
  47. {
  48. _targetFitness += (trainingExample.Length * 256) + (_targetString.Length * 256 * trainingExample.Length);
  49. }
  50. }
  51. }
  52. #region FitnessBase Members
  53. protected override double GetFitnessMethod(string program)
  54. {
  55. double countBonus = 0;
  56. double penalty = 0;
  57. for (int i = 0; i < _trainingExamples.Length; i++)
  58. {
  59. try
  60. {
  61. int state = 0;
  62. _console.Clear();
  63. // Run the program.
  64. _bf = new Interpreter(program, () =>
  65. {
  66. if (state == 0)
  67. {
  68. state++;
  69. // Send input.
  70. return _trainingExamples[i][0];
  71. }
  72. else
  73. {
  74. // Not ready for input.
  75. penalty++;
  76. return 255;
  77. }
  78. },
  79. (b) =>
  80. {
  81. _console.Append((char)b);
  82. });
  83. _bf.Run(_maxIterationCount);
  84. }
  85. catch
  86. {
  87. }
  88. _output.Append(_console.ToString());
  89. _output.Append(",");
  90. // Go through each sequence. 5bot4bot3bot2bot1bot0bot
  91. for (int j = 0; j < _trainingExamples[i].Length; j++)
  92. {
  93. int jj = j + (j * _targetString.Length);
  94. // Go through each item (5 bottles of beer on the wall). + 1 for digit. and -1 to discard digit to index into text.
  95. for (int k = 0; k < _targetString.Length + 1; k++)
  96. {
  97. if (_console.Length > jj + k)
  98. {
  99. if (k == 0)
  100. {
  101. // Verify digit.
  102. Fitness += 256 - Math.Abs((byte)_console[jj + k] - _trainingExamples[i][j]);
  103. }
  104. else
  105. {
  106. // Verify text.
  107. Fitness += 256 - Math.Abs(_console[jj + k] - _targetString[k - 1]);
  108. }
  109. }
  110. else
  111. {
  112. break;
  113. }
  114. }
  115. }
  116. // Make the AI wait until a solution is found without the penalty (too many input characters).
  117. Fitness -= penalty;
  118. // Check for solution.
  119. IsFitnessAchieved();
  120. // Bonus for less operations to optimize the code.
  121. countBonus += ((_maxIterationCount - _bf.m_Ticks) / 20.0);
  122. Ticks += _bf.m_Ticks;
  123. }
  124. if (_fitness != Double.MaxValue)
  125. {
  126. _fitness = Fitness + countBonus;
  127. }
  128. return _fitness;
  129. }
  130. protected override void RunProgramMethod(string program)
  131. {
  132. for (int i = 0; i < 99; i++)
  133. {
  134. // Get input from the user.
  135. Console.WriteLine();
  136. Console.Write(">: ");
  137. byte startingValue = Byte.Parse(Console.ReadLine());
  138. int index = 0;
  139. int index2 = 0;
  140. _console.Clear();
  141. try
  142. {
  143. // Run the program.
  144. Interpreter bf = new Interpreter(program, () =>
  145. {
  146. byte b;
  147. // Send the next character.
  148. if (index++ == 0)
  149. {
  150. b = startingValue;
  151. }
  152. else
  153. {
  154. b = 255;
  155. }
  156. return b;
  157. },
  158. (b) =>
  159. {
  160. // The program correctly solves the problem, however the output is in byte format. For example: 5b => 598 (where 98 = 'b'). We need to format the output for humans to read by leaving the numeric values as byte and the text values as char.
  161. if (index2++ % (_targetString.Length + 1) == 0)
  162. {
  163. // Append numeric byte value.
  164. _console.Append(b);
  165. }
  166. else
  167. {
  168. // Append text.
  169. _console.Append((char)b);
  170. }
  171. });
  172. bf.Run(_maxIterationCount);
  173. }
  174. catch
  175. {
  176. }
  177. Console.WriteLine(_console.ToString());
  178. }
  179. }
  180. public override string GetConstructorParameters()
  181. {
  182. return _maxIterationCount.ToString();
  183. }
  184. #endregion
  185. }
  186. }