rg3 / cifras

Program to solve the numeric problems from the Spanish TV show "Cifras y Letras"

This URL has Read+Write access

cifras / node.cc
100644 134 lines (118 sloc) 3.628 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
* Author: Ricardo Garcia Gonzalez
* License: Public domain code
*/
#include <iostream>
#include <list>
#include <set>
#include <cstdlib>
#include <limits>
 
#include "operation.h"
#include "node.h"
#include "memory_manager.h"
 
using std::list;
using std::set;
using std::labs;
using std::ostream;
using std::endl;
 
// Internal functions and data.
namespace {
// Insert element in reverse-ordered list.
template <class T>
void insert_ordered(list<T> &thelist, const T &elem)
{
typedef typename list<T>::iterator iter;
for (iter ii = thelist.begin(); ii != thelist.end(); ++ii)
if (*ii <= elem) {
thelist.insert(ii, elem);
return;
}
thelist.push_back(elem);
}
 
// Create new list from list, excluding two elements.
template <class T>
void append_from_except(const list<T> &ls,
const typename list<T>::const_iterator &ii,
const typename list<T>::const_iterator &jj,
list<T> &newls)
{
typedef typename list<T>::const_iterator iter;
for (iter kk = ls.begin(); kk != ls.end(); ++kk)
if (kk != ii && kk != jj)
newls.push_back(*kk);
}
}
 
// Node constructor. Builds full solution graph.
Node::Node(const list<const Operation *> &prev_steps, long new_num, long target,
const list<long> &basics, set<list<long> > &explored, Node *parent)
: thesteps(prev_steps), successors(), thevalue(new_num), best_child(0)
{
// Target found or leaf: try to self-proclaim best.
if (parent != 0 && (new_num == target || basics.size() == 1)) {
parent->best_child = ((parent->best_child == 0)?
this : best_node(parent->best_child, this, target));
return;
}
 
// Target not found and not leaf: generate children.
long lf;
long rg;
long result;
list<long> rest;
list<long> new_nums;
list<const Operation *> new_steps;
MemoryManager *mm = MemoryManager::instance();
Operation *step;
Node *child;
 
typedef list<long>::const_iterator iter;
for (iter ii = basics.begin(); ii != basics.end(); ++ii)
for (iter jj = ii; ++jj != basics.end(); ) { // Weird "for"
// Choose a pair.
lf = *ii;
rg = *jj;
rest.clear();
append_from_except(basics, ii, jj, rest);
 
for (int op = Op_Sum; op <= Op_Div; ++op) {
// Operate them if possible.
step = mm->build_operation(OpCode(op), lf, rg);
if (! step->valid())
continue;
 
// Create new number list for child.
result = step->result();
new_nums = rest;
insert_ordered(new_nums, result);
 
// Avoid list re-exploration.
if (explored.find(new_nums) != explored.end())
continue;
explored.insert(new_nums);
 
// Build new child.
new_steps = prev_steps;
new_steps.push_back(step);
child = mm->build_node(new_steps, result,
target, new_nums, explored, this);
successors.push_back(child);
}
}
 
// After generating children, try to set parent best to our best.
if (parent != 0 && best_child != 0)
parent->best_child = ((parent->best_child == 0)? best_child :
best_node(parent->best_child, best_child, target));
}
 
// Best of two nodes.
Node *best_node(Node *first, Node *second, const long &target)
{
long fdiff = labs(first->value() - target);
long sdiff = labs(second->value() - target);
 
if (fdiff < sdiff || (first->value() == second->value() &&
first->steps().size() < second->steps().size()))
return first;
return second;
}
 
// Print node to output stream.
ostream &operator<<(ostream &out, const Node &node)
{
typedef list<const Operation *>::const_iterator iter;
const list<const Operation *>&steps = node.steps();
for (iter ii = steps.begin(); ii != steps.end(); ++ii)
out << *(*ii) << endl;
return out;
}