# public rg3 /cifras

### Subversion checkout URL

You can clone with HTTPS or Subversion.

Fetching contributors…

Cannot retrieve contributors at this time

file 115 lines (94 sloc) 5.606 kb
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 `Author: Ricardo Garcia GonzalezLicense: Public domain codeTHE WHAT========This program solves the numeric exercises from the Spanish TV show "Cifrasy Letras". In the program, the contestants are given 6 random numbers fromthe following set: 1 2 3 4 5 6 7 8 9 10 25 50 75 100Then they are asked, by using only natural numbers and exact operations,to combine them arithmetically in order to find another random number from100 to 999. Only sums, substractions, multplications and divisions areallowed. For example, they could be given numbers (5, 5, 6, 25, 9, 7) andcombine them to get number 881. One of the possible answers is ((5 * 25 *7) + 6). As you can see, using all the basic numbers is not required. Ifyou prefer to put it step by step: 5 * 7 = 35 25 * 35 = 875 875 + 6 = 881This problem has been generalized in the program. You can use at least 2basic numbers but as many as you want, and the range is not limited, at leastin theory. In practice, the amount of basic numbers and range is limited,but the limits "should be high enough for anybody".THE HOW=======The program is divided in 3 different parts: the Operation class, the Nodeclass and the MemoryManager class. I will explain them in that order.The Operation class is quite easy to understand. It's an abstract classthat represents a binary operation. It stores a left and a right operand,and has methods to check if the operation is valid and to get the result. Theoperation may not be valid. For example, you cannot divide by zero and youcannot divide if the result is not an exact natural number (i.e. you cannotdivide 3 by 2). This abstract class has 4 subclasses that represent thebasic operations allowed in the game.This class is used by the Node class. The problem we are trying to solvecan be represented by a graph. If we have a list of numbers that we canoperate together, we can form pairs of those numbers and try the differentoperations in that pair. For example, lets suppose we have the numbers (1,2, 3). 3 pairs can be formed with these numbers: (1, 2) leaving out the 3 (1, 3) leaving out the 2 (2, 3) leaving out the 1The first pair can be used in the following valid operations: 2 + 1 (result: 3) 2 * 1 (result: 2) 2 - 1 (result: 1) 2 / 1 (result: 2)As we left out the 3 in the that first pair, by combining the other two wehave a result that can be operated with the remaining 3. That is, after doingeach one of those operations, we would have the following "partial results": 2 + 1 = 3, partial result (3, 3) 2 * 1 = 2, partial result (3, 2) 2 - 1 = 1, partial result (3, 1) 2 / 1 = 2, partial result (3, 2)In other words, we start with a so-called root node that has all the initialnumbers. This node is connected to many partial result nodes, by performing ahigh number of operations with pairs of numbers. Each one of these, in turn,is connected to a whole set of more partial result nodes, with as much deepas needed to reach the target number, or until the partial result only hasone number remaining.This graph is not a tree, as you can see in the example above. Both (2 * 1 =2) and (2 / 1 = 2) allowed us to go from the node (1, 2, 3) to the node (2,3). A node has three very important things: first, it has a list of operationsneeded to reach it from the root node; second, each node introduces a newnumber which is the result of operating a couple of numbers; third, it has alist of remaining usable numbers to be combined to reach the result, and thislist includes the newly introduced number. When generating a new node, thechild node has a new list of operations, which is the same as in the parentnode plus one more operation, a new introduced number, which is the resultof the last operation, and a list of possible numbers to be combined, whichare the numbers not used in the operation, plus the result of the operation.This allows us to recursively apply backtracking and explore the graph. If,on top of that, we store the partial results we obtain, this can be doneefficiently. This means we wouldn't explore the node (2, 3) the secondtime it appears. All this work is done in the Node constructor. The Nodeconstructor builds the full problem graph, because when building a node,it builds all of its children.One minor implementation detail is that the initial number list is sorted indescending order, and when a new number is introduced, it's also insertedpreserving order. Order preservation allows us to form valid pairs quicklyand easily with the algorithm present in the node constructor, where eachnumber is paired with all of the numbers to its right. This way, we make suresubstractions always work, and divisions may work if the result is exact. Wedon't need to try the other way around with these two non-commutativeoperations, because we know we can't subtract B from A or divide A by B ifB is greater than A.Finally, the MemoryManager class was designed to help track new nodes andoperations we need to create. It creates operations and nodes on the fly,and stores all pointers it returns. This way, we can clean memory at anypoint using the free() method. Currently, this is called at the end of theprogram. This class is also designed using the Singleton design pattern. Thismeans the class has a static pointer to an object of the same class, and theconstructor is private. Te only way to get a MemoryManager instance is to callthe instance() static method, which always returns the same instance. Thisguarantees there's only one MemoryManager object in the same program.`
Something went wrong with that request. Please try again.