-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGalaxy.java
265 lines (247 loc) · 8.05 KB
/
Galaxy.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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
package testalg;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author zhou
*
* @environment JKD1.5 or higher
*
* @input the program need to place a named "inp.txt" file near the Galaxy.java file as beginning by run the main function
*
* the content of the input text need to obey the following rules:
* 1. words separated by white space only
* 2. should define the galaxy and roma like: [galaxy] is [roma]
* 3. should define the metal costs like: [galaxy] [metal] is [number] Credits
* 4. when you want to calculate galaxy you should write like: how much is [galaxy]
* 5. when you want to calculate metal you should write like: how many Credits is [galaxy] [metal]
*
* @return currently only print the result to console in this version
*
*/
public class Galaxy {
private final static String I = "I";
private final static String V = "V";
private final static String X = "X";
private final static String L = "L";
private final static String C = "C";
private final static String D = "D";
private final static String M = "M";
private final static String IVXLCDM = "IVXLCDM";
private final static String IXC = "IXC";
private final static String SPACE = " ";
private final static String EMP = "";
private final static String HOW = "how";
private final static String MUCH = "much";
private final static String IS = "is";
private final static String MANY = "many";
private final static String CREDITS = "Credits";
private static Map<String, Integer> ROMA = new HashMap<String, Integer>();
public Galaxy(){
ROMA.put(I, 1);
ROMA.put(V, 5);
ROMA.put(X, 10);
ROMA.put(L, 50);
ROMA.put(C, 100);
ROMA.put(D, 500);
ROMA.put(M, 1000);
}
public static void main(String[] args){
Galaxy g = new Galaxy();
g.convert();
}
public void convert(){
//get input note string arrays
List<String> inp = this.readInput();
//initialize galaxy-roma and credits variables
Map<String, String> galaxyroma = new HashMap<String, String>();
List<Object[]> creds = new ArrayList<Object[]>();
//parse measurement
for(String s : inp){
parseline(s,galaxyroma,creds);
}
//calculate the credits cost of metal
Map<String, BigDecimal> mc = calculateMetalCred(creds, galaxyroma);
//loop input note to parse and print results
//TODO need to output into file or not?
for(String s : inp){
String[] ss = this.filterSpareSplit(s);
if(ss.length >= 4){
if(HOW.equalsIgnoreCase(ss[0])&&MUCH.equalsIgnoreCase(ss[1])&&IS.equalsIgnoreCase(ss[2])){
LinkedList<String> gal = new LinkedList<String>();
int e = "?".equalsIgnoreCase(ss[ss.length - 1])?1:0;
for(int i = 3; i < ss.length - e; i++){
gal.add(ss[i]);
}
int rst = calculateDec(gal, galaxyroma);
for(String sss : gal){
System.out.print(sss + SPACE);
}
System.out.println("is "+rst);
}else if(ss.length >= 6&&HOW.equalsIgnoreCase(ss[0])&&MANY.equalsIgnoreCase(ss[1])&&CREDITS.equalsIgnoreCase(ss[2])&&IS.equalsIgnoreCase(ss[3])){
int e = "?".equalsIgnoreCase(ss[ss.length - 1])?2:1;
LinkedList<String> gal = new LinkedList<String>();
for(int i = 4; i < ss.length - e; i++){
gal.add(ss[i]);
}
int rst = calculateDec(gal, galaxyroma);
for(String sss : gal){
System.out.print(sss + SPACE);
}
String metal = ss[ss.length - 2];
System.out.println(metal + " is " + (int)((double)rst * mc.get(metal).doubleValue()) + " Credits");
}else if(s.indexOf(IS)<0 && s.indexOf("redits")<0){
System.out.println("I have no idea what you are talking about");
}
}else{
System.out.println("I have no idea what you are talking about");
}
}
}
//use for parsing the measurement in the note which is used for calculating
private boolean parseline(String line, Map<String, String> galaxyroma, List<Object[]> creds){
if(line != null){
String[] ss = this.filterSpareSplit(line);
if(ss.length==3){
if(ss[1].equalsIgnoreCase(IS) && IVXLCDM.indexOf(ss[2])>=0){
galaxyroma.put(ss[0], ss[2]);
}
}
if(ss.length>=5){
String[] ssr = reverse(ss);//the reversed order
if(ssr[0].equalsIgnoreCase(CREDITS)&&ssr[2].equalsIgnoreCase(IS)){
Object[] e = new Object[3];
List<String> gal = new LinkedList<String>();
String[] gals = new String[ss.length - 4];
for(int i = 0; i < gals.length; i++){
gals[i] = ssr[ss.length - i - 1];
}
for(String g : gals){
gal.add(g);
}
e[0] = gal;//galaxy numbers of metal
e[1] = ssr[3];//name of metal
e[2] = ssr[1];//numbers of credits
creds.add(e);
}
}
}
return false;
}
//calculate every metal costs credits
@SuppressWarnings("unchecked")
private Map<String, BigDecimal> calculateMetalCred(List<Object[]> creds, Map<String, String> galaxyroma){
Map<String, BigDecimal> mc = new HashMap<String, BigDecimal>();
for(Object[] arr : creds){
int num = calculateDec((LinkedList<String>)arr[0], galaxyroma);
BigDecimal sglcr = BigDecimal.valueOf((double)Integer.valueOf(String.valueOf(arr[2])) / num);
mc.put(arr[1].toString(),sglcr);
}
return mc;
}
//calculate decimal from ROMA
private int calculateDec(LinkedList<String> gal, Map<String, String> galaxyroma){
String[] roms = new String[gal.size()];
for(int i = 0; i < gal.size(); i++){
roms[i] = galaxyroma.get(gal.get(i));
}
int rst = 0;
for(int j = 0; j < roms.length; j++){
String s = roms[j];
int curdec = ROMA.get(s);
if(IXC.indexOf(s) < 0){
rst += curdec;
}else{
if(j == roms.length - 1){
rst += curdec;
}else{
int nextdec = ROMA.get(roms[j+1]);
if(curdec < nextdec){
rst += (nextdec - curdec);
j++;
}else{
rst += curdec;
}
}
}
}
return rst;
}
//reverse the string in the array
private String[] reverse(String [] s){
if(s!=null){
int len = s.length;
String[] ss = new String[len];
for(int i = 0; i < s.length; i++){
ss[i] = s[len - i - 1];
}
return ss;
}
return null;//TODO need to dispose null
}
//read input file
private List<String> readInput(){
String pathname = "inp.txt";
List<String> rst = new ArrayList<String>();
//get the path of the inp.txt file which is placed near source file and delete the beginning "file:/"
String path = Galaxy.class.getResource(EMP).toString().substring(5);
File filename = new File(path+pathname);
if(filename.isFile() && filename.exists()){
BufferedReader br = null;
try{
InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
br = new BufferedReader(reader);
String line = br.readLine();
rst.add(line);
while (line != null) {
line = br.readLine();
if(line != null){
rst.add(line);
}
}
}catch(IOException e){
e.printStackTrace();
}finally{
if(br != null){
try{
br.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}else{
System.out.println("please place inp.txt correctlly");
}
return rst;
}
private String[] filterSpareSplit(String line){
LinkedList<String> ll = new LinkedList<String>();
if(line != null){
if(line.length() > 0){
String[] arr = line.split(SPACE);
for(String s : arr){
if(!s.trim().equals(EMP)){
ll.add(s);
}
}
}
}
int len = ll.size();
String[] rst = new String[len];
if(len > 0){
for(int i = 0; i < len; i++){
rst[i] = ll.get(i);
}
}
return rst;
}
}