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
135
136
137
138
139
140
141
142
|
using VQDR.Expression;
using VQDR.Common;
public class RollAndKeepFunctionToken : FunctionToken {
private const int INDEX_ROLL = 1;
private const int INDEX_POOL = 1;
private const int INDEX_KEEP = 2;
private const int MAX_POOL_SIZE = 50;
private long[] roll_values = null; // = new long[MAX_POOL_SIZE];
private bool[] valid_values = null; // = new bool[MAX_POOL_SIZE];
construct {
mandatory_num_child = 2;
optional_num_child = 1;
}
protected override void evaluate_self (VQDR.Expression.Context instance) throws GLib.Error {
Token? roll;
long pool_size;
long keep_size;
roll = get_child (INDEX_ROLL);
try {
get_child (INDEX_POOL).evaluate (instance);
} catch (Error e) {
stderr.printf ("Error: %s, Error Domain: %s\n",
e.message, e.domain.to_string ());
GLib.assert_not_reached ();
}
pool_size = get_child (INDEX_POOL).result_value.to_int ();
if (pool_size > MAX_POOL_SIZE) {
throw new ParamError.OUT_OF_BOUNDS (@"Max value $MAX_POOL_SIZE, got $pool_size");
}
if (pool_size < 0) {
pool_size = 0;
}
{
Token? keep_child = get_child (INDEX_KEEP);
if (keep_child != null) {
keep_child.evaluate (instance);
keep_size = keep_child.result_value.to_int ();
} else {
keep_size = pool_size;
}
}
if (keep_size > pool_size) {
keep_size = pool_size;
}
/* */
long roll_result;
long min_keep = long.MAX;
int min_keep_index = 0;
if (roll_values == null || roll_values.length < pool_size) {
roll_values = new long[pool_size];
valid_values = new bool[pool_size];
}
for (int i = 0; i < pool_size; i++) {
roll.evaluate (instance);
roll_result = roll.result_value.raw_number;
roll_values[i] = roll_result;
valid_values[i] = true;
if (i < keep_size) {
// simply keep and detect the minium kept value
if (min_keep > roll_result) {
min_keep = roll_result;
min_keep_index = i;
}
} else {
// Chose what to do.
if (roll_result >= min_keep) {
// Discard the Minimum value
valid_values[min_keep_index] = false;
// Search for new Minimum value
min_keep = long.MAX;
min_keep_index = 0;
for (int j = 0; j <= i; j++) {
if (valid_values[j]) {
if (min_keep > roll_values[j]) {
min_keep = roll_values[j];
min_keep_index = j;
}
}
}
} else {
valid_values[i] = false;
}
}
} // end for loop
StringBuilder strbldr = new StringBuilder ();
strbldr.append (SYM_BEGIN);
FastNumber tmp_fstnmbr;
for (int i = 0; i < pool_size; i++) {
if (strbldr.len < MAX_TOKEN_STRING_LENGTH) {
//we don't start with a seperator mark.
if (i > 0) {
strbldr.append (SYM_SEP);
}
// We don't want to deal with the conertion directly.
// FIXME: Convert everything to FastNumbers instead of using "raw" values?
tmp_fstnmbr = FastNumber.raw (roll_values[i]);
strbldr.append (tmp_fstnmbr.to_string ());
if (valid_values[i] && keep_size != pool_size) {
strbldr.append (SYM_SELECTED);
}
}
if (valid_values[i]) {
tmp_fstnmbr = FastNumber.raw (roll_values[i]);
result_value.add (tmp_fstnmbr);
}
}
result_max_value = roll.result_max_value.multiply (FastNumber(keep_size));
result_min_value = roll.result_min_value.multiply (FastNumber(keep_size));
if (strbldr.len < MAX_TOKEN_STRING_LENGTH) {
strbldr.append (SYM_END);
result_string = strbldr.str;
} else {
result_string = SYM_TRUNK_BEGIN + result_value.to_string () + SYM_TRUNK_END;
}
}
}
/* vim: set tabstop=2:softtabstop=2:shiftwidth=2:expandtab */
|