/
LootTable.java
184 lines (157 loc) · 4.69 KB
/
LootTable.java
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Implementation of ILootTable interface
*
*/
class LootTable implements ILootTable {
//--| Internal Data Structure |------------------------------------------------------------------
/**
* Loot drop record
*/
public class lootRecord{
String name = "[empty record]";
Integer tries = 0;
Double dropChance = 0.0;
/**
* @return string representation of loot drop
*/
public String toString(){
return String.format("%9.10s, %2d tries, drops %4.1f%%",
this.name, this.tries, 100 * this.dropChance);
}
} // lootRecord
List<lootRecord> table = new ArrayList<lootRecord>();
Double confidence = 0.95;
static Random rng = new Random();
//--| Primary Interface |------------------------------------------------------------------------
/**
* Constructor
* @param fileName CSV file to import |String name,int tries|
*/
LootTable(String fileName){
load(fileName);
}
/**
* get string representation of randomly selected loot record from the table
*/
public String get(){
Double target = rng.nextDouble();
Double sum = 0.0;
for(lootRecord record : table){
sum += record.dropChance;
if(target <= sum){
return record.toString();
}
} // else RNG rolled higher than our total drop chances
return getMostCommonItem().toString();
}
/**
* @return count of records in loot table
*/
public int size(){
return table.size();
}
/**
* @return total of loot drop chances
*/
public double total(){
Double total = 0.0;
for (lootRecord record : table) {
total += record.dropChance;
}
return total;
}
/**
* Load a set of loot items into loot table from a Comma Separated Value (CSV) file
* @param fileName expected CSV format: | String name | int tries |
* @throws NumberFormatException if 2nd column isn't an integer (extra space?)
* @throws FileNotFoundException if can't find the CSV file (path & extension?)
* @throws IOException other I/O & storage problems
*/
public void load(String fileName){
try {
BufferedReader fileReader = new BufferedReader(new FileReader(fileName));
String lineItem;
while ((lineItem = fileReader.readLine()) != null) {
String[] lootDetails = lineItem.split(",");
lootRecord record = new lootRecord();
record.name = lootDetails[0];
record.tries = Integer.valueOf(lootDetails[1]);
record.dropChance = calcDropChance(record.tries);
table.add(record);
}
fileReader.close();
}
catch (NumberFormatException e) {
System.out.println("Invalid String: Integer count of tries expected");
e.printStackTrace();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
} // load
//--| Utility Methods |--------------------------------------------------------------------------
/**
* @return string representation of loot table
*/
public String toString(){
String stringifiedRecords = new String();
for (lootRecord record : table) {
stringifiedRecords += record + "\n";
}
return stringifiedRecords;
} // toString
/**
* Change loot table confidence (1 - risk)
* Default: 95% certainty (5% risk of misadventure)
* @param confidence [0..1]
*/
public void setConfidence(double confidence){
this.confidence = confidence;
}
/**
* get confidence (1 - risk)
* @return confidence [0..1]
*/
public Double getConfidence(){
return this.confidence;
}
/**
* size of leftover drop chance in tries
* @return tries
*/
public double remainderInTries(){
return ( Math.log(1 - confidence) / Math.log(this.total()) );
}
//--| Internal Methods |-------------------------------------------------------------------------
/**
* Given tries & confidence (1-risk), calculate success (1-failure)
* failure = risk^(1/tries)
* success = 1 - (1-confidence)^(1/tries)
* @param tries before it's confidence% certain the loot has dropped
*/
double calcDropChance(int tries){
return 1.0 - Math.pow(1.0 - confidence, 1.0 / tries);
}
/**
* @return record in table with highest drop chance
*/
lootRecord getMostCommonItem(){
lootRecord mostCommon = new lootRecord();
for(lootRecord record : table){
if(record.dropChance > mostCommon.dropChance){
mostCommon = record;
}
}
return mostCommon;
} // getMostCommon
} // lootTable