Where people come together to learn, code, and play. Custom-built HTTP server, site generator, and website from scratch using no external libraries. Goal is to be as minimalistic and fun as possible.
http://projectdivar.com
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
466 lines
17 KiB
466 lines
17 KiB
package readers;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.nio.file.Path;
|
|
import java.time.ZonedDateTime;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
import java.util.regex.Pattern;
|
|
import java.awt.Color;
|
|
|
|
public abstract class Reader{
|
|
final static int REGION_PADDING = 32;
|
|
final static boolean NUMBER = true;
|
|
int score;
|
|
int rank;
|
|
int[] notes = new int[7];
|
|
int difficulty;
|
|
String title="";
|
|
double pct;
|
|
int maxcombo;
|
|
String other="";
|
|
String[] sig_data;
|
|
public Path result_screenshot;
|
|
List<Box> readRegions = new ArrayList<>();
|
|
int sig_data_size = 0;
|
|
final int TRANSPARENT = new Color(0,0,0,0).getRGB();
|
|
protected void addRegion(Box box) {
|
|
addRegion(box,false);
|
|
}
|
|
protected void addRegion(Box box,boolean isNumb) {
|
|
readRegions.add(box);
|
|
if (isNumb) {
|
|
box.setNumber(true);
|
|
sig_data_size++;
|
|
}
|
|
}
|
|
protected void init() {
|
|
sig_data = new String[readRegions.size()];
|
|
}
|
|
String parseOutCommas(String str) {
|
|
StringBuilder sb = new StringBuilder();
|
|
boolean insideStr = false;
|
|
char escapeChar = '\'';
|
|
for (int i=0;i<str.length();i++) {
|
|
if (!insideStr) {
|
|
if (str.charAt(i)=='\''||str.charAt(i)=='"') {
|
|
insideStr=true;
|
|
escapeChar=str.charAt(i);
|
|
}
|
|
} else {
|
|
if (str.charAt(i)==escapeChar) {
|
|
insideStr=false;
|
|
}
|
|
}
|
|
if (insideStr&&str.charAt(i)==',') {
|
|
sb.append('،');
|
|
} else {
|
|
sb.append(str.charAt(i));
|
|
}
|
|
}
|
|
return sb.toString();
|
|
}
|
|
public void interpretBoxes(Path file) {
|
|
interpretBoxes(file,false);
|
|
};
|
|
public abstract void interpretBoxes(Path file,boolean testingMode);
|
|
String readAllBoxes(Path img) {
|
|
try {
|
|
Process p = Runtime.getRuntime().exec(new String[]{"python3","runocr.py","ja",img.toAbsolutePath().toString()});
|
|
while (p.isAlive());
|
|
InputStreamReader result = new InputStreamReader(p.getInputStream());
|
|
StringBuilder sb = new StringBuilder();
|
|
while (result.ready()) {
|
|
sb.append((char)result.read());
|
|
}
|
|
result.close();
|
|
sb.append("\n");
|
|
p = Runtime.getRuntime().exec(new String[]{"python3","runocr.py","en",img.toAbsolutePath().toString()});
|
|
while (p.isAlive());
|
|
result = new InputStreamReader(p.getInputStream());
|
|
while (result.ready()) {
|
|
sb.append((char)result.read());
|
|
}
|
|
return sb.toString();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
return "";
|
|
}
|
|
String interpretOutput(String[] jp_data,String[] en_data,String[] sig_data) {
|
|
//[6, 0, 218, 0, 218, 48, 6, 48, 32 5 4 1 5, 0.9670235803680689]
|
|
//For each data point we want to first see if it's within the correct rectangular bounds and from there parse it as such.
|
|
double[] accuracy = new double[readRegions.size()];
|
|
String[] finalData = new String[readRegions.size()];
|
|
for (int i=0;i<finalData.length;i++) {
|
|
finalData[i]="";
|
|
}
|
|
for (int i=0;i<en_data.length;i+=10) {
|
|
int spacing=0;
|
|
for (int j=0;j<readRegions.size();j++) {
|
|
int midpoint=(int)(Double.parseDouble(en_data[i+1])+Double.parseDouble(en_data[i+5]))/2;
|
|
if (midpoint>=spacing&&midpoint<=spacing+readRegions.get(j).h+REGION_PADDING
|
|
/*&&accuracy[j]<Double.parseDouble(en_data[i+9]) Only for jp string testing.*/) {
|
|
System.out.print("[");
|
|
for (int k=0;k<10;k++) {
|
|
if (k!=0) {
|
|
System.out.print(",");
|
|
}
|
|
System.out.print(en_data[i+k]);
|
|
}
|
|
System.out.print("]");
|
|
System.out.println(" belongs to region "+j+".");
|
|
finalData[j]=finalData[j]+"\n"+en_data[i+8]
|
|
.substring(1,en_data[i+8].length()-1); //The beginning and endings have a ', so we remove it.
|
|
if (Double.parseDouble(en_data[i+9])>accuracy[j]) {
|
|
accuracy[j]=Double.parseDouble(en_data[i+9]);
|
|
}
|
|
break;
|
|
}
|
|
spacing+=readRegions.get(j).h+REGION_PADDING;
|
|
}
|
|
}
|
|
for (int i=0;i<jp_data.length;i+=10) {
|
|
int spacing=0;
|
|
for (int j=0;j<readRegions.size();j++) {
|
|
int midpoint=(int)(Double.parseDouble(jp_data[i+1])+Double.parseDouble(jp_data[i+5]))/2;
|
|
if (midpoint>=spacing&&midpoint<=spacing+readRegions.get(j).h+REGION_PADDING
|
|
&&accuracy[j]<Double.parseDouble(jp_data[i+9])) {
|
|
System.out.print("JP[");
|
|
for (int k=0;k<10;k++) {
|
|
if (k!=0) {
|
|
System.out.print(",");
|
|
}
|
|
System.out.print(jp_data[i+k]);
|
|
}
|
|
System.out.print("]");
|
|
System.out.println(" belongs to region "+j+".");
|
|
if (accuracy[j]!=0) {
|
|
finalData[j]="";
|
|
}
|
|
finalData[j]=finalData[j]+"\n"+jp_data[i+8]
|
|
.substring(1,jp_data[i+8].length()-1); //The beginning and endings have a ', so we remove it.
|
|
accuracy[j]=0;
|
|
break;
|
|
}
|
|
spacing+=readRegions.get(j).h+REGION_PADDING;
|
|
}
|
|
}
|
|
for (int i=0;i<sig_data.length;i++) {
|
|
if (!sig_data[i].isEmpty()) {
|
|
finalData[i]=sig_data[i];
|
|
}
|
|
}
|
|
System.out.println(Arrays.toString(finalData));
|
|
return interpretResults(finalData);
|
|
};
|
|
abstract String interpretResults(String[] finalData);
|
|
void trimAllData(String[] data) {
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i=0;i<data.length;i++) {
|
|
sb.delete(0,sb.length());
|
|
for (int j=0;j<data[i].length();j++) {
|
|
if (data[i].charAt(j)!='['&&data[i].charAt(j)!='('&&data[i].charAt(j)!=')'&&data[i].charAt(j)!=']') {
|
|
sb.append(data[i].charAt(j));
|
|
}
|
|
}
|
|
data[i]=sb.toString().trim();
|
|
}
|
|
}
|
|
|
|
void seek(int[]arr,int i,ColorRange SEEKCOLOR,Color FINALCOLOR,int width) {
|
|
seek(arr,i,SEEKCOLOR,FINALCOLOR,width,0);
|
|
}
|
|
|
|
int seek(int[]arr,int i,ColorRange SEEKCOLOR,Color FINALCOLOR,int width,int farthestRight) {
|
|
arr[i]=FINALCOLOR.getRGB();
|
|
int X = i%width;
|
|
for (int x=-1;x<=1;x++) {
|
|
for (int y=-1;y<=1;y++) {
|
|
int newX=(i+x+y*width)%width;
|
|
int newY=(i+x+y*width)/width;
|
|
if (newX>=0&&newY>=0&&newX<width&&newY<arr.length/width) {
|
|
Color col = new Color(arr[i+x+y*width]);
|
|
if (!col.equals(Color.MAGENTA)&&SEEKCOLOR.colorInRange(col)) {
|
|
farthestRight=seek(arr,i+x+y*width,SEEKCOLOR,FINALCOLOR,width,farthestRight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return X>farthestRight?X:farthestRight;
|
|
}
|
|
void seekThreshold(int[]arr,int i,int threshold,Color FINALCOLOR,int width) {
|
|
seekThreshold(arr,i,threshold,FINALCOLOR,width,0);
|
|
}
|
|
|
|
int seekThreshold(int[]arr,int i,int threshold,Color FINALCOLOR,int width,int farthestRight) {
|
|
arr[i]=FINALCOLOR.getRGB();
|
|
int X = i%width;
|
|
for (int x=-1;x<=1;x++) {
|
|
for (int y=-1;y<=1;y++) {
|
|
int newX=(i+x+y*width)%width;
|
|
int newY=(i+x+y*width)/width;
|
|
if (newX>=0&&newY>=0&&newX<=width&&newY<=arr.length/width) {
|
|
Color col = new Color(arr[i+x+y*width]);
|
|
if (!col.equals(Color.MAGENTA)&&colorIsBright(col, threshold)) {
|
|
farthestRight=seekThreshold(arr,i+x+y*width,threshold,FINALCOLOR,width,farthestRight);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return X>farthestRight?X:farthestRight;
|
|
}
|
|
void process(int[]arr,int width,int a,int b,int c,int d,int e,int f,int g,int h,int ii,int j,int k,int l) {
|
|
final ColorRange TARGETCOLOR = new ColorRange(a,b,c,d,e,f);
|
|
final ColorRange SEEKINGCOLOR = new ColorRange(g,h,ii,j,k,l);
|
|
final Color FINALCOLOR = Color.MAGENTA;
|
|
for (int i=0;i<arr.length;i++) {
|
|
Color col = new Color(arr[i],true);
|
|
if (TARGETCOLOR.colorInRange(col)) {
|
|
seek(arr,i,SEEKINGCOLOR,FINALCOLOR,width);
|
|
}
|
|
}
|
|
for (int i=0;i<arr.length;i++) {
|
|
Color col = new Color(arr[i],true);
|
|
if (!col.equals(Color.MAGENTA)) {
|
|
arr[i]=TRANSPARENT;
|
|
}
|
|
}
|
|
}
|
|
boolean colorIsBright(Color col,int brightnessThreshold) {
|
|
return col.getRed()+col.getBlue()+col.getGreen()>brightnessThreshold;
|
|
}
|
|
void processBrightness(int[]arr,int width,int threshold1,int threshold2) {
|
|
final Color FINALCOLOR = Color.MAGENTA;
|
|
for (int i=0;i<arr.length;i++) {
|
|
Color col = new Color(arr[i],true);
|
|
if (colorIsBright(col, threshold1)) {
|
|
seekThreshold(arr,i,threshold2,FINALCOLOR,width);
|
|
}
|
|
}
|
|
for (int i=0;i<arr.length;i++) {
|
|
Color col = new Color(arr[i],true);
|
|
if (!col.equals(Color.MAGENTA)) {
|
|
arr[i]=TRANSPARENT;
|
|
}
|
|
}
|
|
}
|
|
|
|
char[][] number_alternatives={
|
|
/*0*/{'0','o','O','e'},
|
|
/*1*/{'1','\\','/','I','i'},
|
|
/*2*/{'2','己'},
|
|
/*3*/{'3'},
|
|
/*4*/{'4'},
|
|
/*5*/{'5'},
|
|
/*6*/{'6','b','G'},
|
|
/*7*/{'7','z','Z'},
|
|
/*8*/{'8','B'},
|
|
/*9*/{'9','g','y',},
|
|
};
|
|
|
|
String convertToString(String[]data){
|
|
return String.join(" ",data).replaceFirst(Pattern.quote(" "),"").replaceAll(Pattern.quote("\""),"\\\"");
|
|
}
|
|
|
|
double convertToDouble(String[]data){return convertToDouble("",data);}
|
|
|
|
double convertToDouble(String prefix,String[] data) {
|
|
int numb=0;
|
|
int decimal=0;
|
|
boolean decimalFound=false;
|
|
for (int i=0;i<data.length;i++) {
|
|
String s = data[i];
|
|
int j=0;
|
|
if (i==1) {
|
|
j=prefix.length();
|
|
} else {
|
|
j=0;
|
|
}
|
|
//System.out.println("["+s+"]"+" starts at "+j);
|
|
for (;j<s.length();j++) {
|
|
if (s.charAt(j)=='.'||s.charAt(j)==',') {
|
|
decimalFound=true;
|
|
}
|
|
letter_iterator:
|
|
for (int k=0;k<number_alternatives.length;k++) {
|
|
for (int l=0;l<number_alternatives[k].length;l++) {
|
|
if (s.charAt(j)==number_alternatives[k][l]) {
|
|
if (!decimalFound) {
|
|
numb*=10;
|
|
numb+=k;
|
|
} else {
|
|
decimal*=10;
|
|
decimal+=k;
|
|
}
|
|
//System.out.println(" "+s.charAt(j)+" found for "+k+".");
|
|
break letter_iterator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
try {
|
|
return Double.parseDouble(Integer.toString(numb)+"."+Integer.toString(decimal));
|
|
} catch (NumberFormatException e) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int convertToInt(String[]data){return convertToInt("",data);}
|
|
|
|
int convertToInt(String prefix,String[] data) {
|
|
String numb="";
|
|
for (int i=0;i<data.length;i++) {
|
|
String s = data[i];
|
|
int j=0;
|
|
if (i==1) {
|
|
j=prefix.length();
|
|
} else {
|
|
j=0;
|
|
}
|
|
//System.out.println("["+s+"]"+" starts at "+j);
|
|
for (;j<s.length();j++) {
|
|
letter_iterator:
|
|
for (int k=0;k<number_alternatives.length;k++) {
|
|
for (int l=0;l<number_alternatives[k].length;l++) {
|
|
if (s.charAt(j)==number_alternatives[k][l]) {
|
|
numb+=number_alternatives[k][l];
|
|
//System.out.println(" "+s.charAt(j)+" found for "+k+".");
|
|
break letter_iterator;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (numb.length()>0) {
|
|
try {
|
|
return Integer.parseInt(numb);
|
|
} catch (NumberFormatException e) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
@Override
|
|
public String toString() {
|
|
return "{\"game\":\""+getClass().getSimpleName()+"\",\"difficulty\":" + difficulty + ", \"maxcombo\":" + maxcombo + ", \"notes\":" + Arrays.toString(notes)
|
|
+ ", \"other\":" + other + ", \"pct\":" + pct + ", \"rank\":" + rank + ", \"score\":" + score + ", \"title\":\"" + title.replaceAll(Pattern.quote("\n"),"\\\\n")
|
|
+ "\"}";
|
|
}
|
|
public String toStringWithScreenshot() {
|
|
return "{\"game\":\""+getClass().getSimpleName()+"\",\"difficulty\":" + difficulty + ", \"maxcombo\":" + maxcombo + ", \"notes\":" + Arrays.toString(notes)
|
|
+ ", \"other\":" + other + ", \"pct\":" + pct + ", \"rank\":" + rank + ", \"score\":" + score + ", \"title\":\"" + title.replaceAll(Pattern.quote("\n"),"\\\\n")
|
|
+ "\", \"screenshot\":\""+result_screenshot+"\", \"date\":"+ZonedDateTime.now().toEpochSecond()+"}";
|
|
}
|
|
public int getScore() {
|
|
return score;
|
|
}
|
|
public void setScore(int score) {
|
|
this.score = score;
|
|
}
|
|
public int getRank() {
|
|
return rank;
|
|
}
|
|
public void setRank(int rank) {
|
|
this.rank = rank;
|
|
}
|
|
public int[] getNotes() {
|
|
return notes;
|
|
}
|
|
public void setNotes(int[] notes) {
|
|
this.notes = notes;
|
|
}
|
|
public int getDifficulty() {
|
|
return difficulty;
|
|
}
|
|
public void setDifficulty(int difficulty) {
|
|
this.difficulty = difficulty;
|
|
}
|
|
public String getTitle() {
|
|
return title;
|
|
}
|
|
public void setTitle(String title) {
|
|
this.title = title;
|
|
}
|
|
public double getPct() {
|
|
return pct;
|
|
}
|
|
public void setPct(double pct) {
|
|
this.pct = pct;
|
|
}
|
|
public int getMaxcombo() {
|
|
return maxcombo;
|
|
}
|
|
public void setMaxcombo(int maxcombo) {
|
|
this.maxcombo = maxcombo;
|
|
}
|
|
public String getOther() {
|
|
return other;
|
|
}
|
|
public void setOther(String other) {
|
|
this.other = other;
|
|
}
|
|
@Override
|
|
public int hashCode() {
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + difficulty;
|
|
result = prime * result + maxcombo;
|
|
result = prime * result + Arrays.hashCode(notes);
|
|
result = prime * result + Arrays.deepHashCode(number_alternatives);
|
|
result = prime * result + ((other == null) ? 0 : other.hashCode());
|
|
long temp;
|
|
temp = Double.doubleToLongBits(pct);
|
|
result = prime * result + (int) (temp ^ (temp >>> 32));
|
|
result = prime * result + rank;
|
|
result = prime * result + score;
|
|
result = prime * result + ((title == null) ? 0 : title.hashCode());
|
|
return result;
|
|
}
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null) {
|
|
System.out.println("Null");
|
|
return false;
|
|
}
|
|
Reader other = (Reader) obj;
|
|
if (difficulty != other.difficulty)
|
|
return false;
|
|
if (maxcombo != other.maxcombo)
|
|
return false;
|
|
if (!Arrays.equals(notes, other.notes))
|
|
return false;
|
|
if (this.other == null) {
|
|
if (other.other != null)
|
|
return false;
|
|
} else
|
|
if (this.other.length()>0 && other.other.length()>0 && !this.other.equals(other.other)) {
|
|
return false;
|
|
}
|
|
if (Double.compare(pct,other.pct)!=0) {
|
|
System.out.println("Doubles don't match!");
|
|
return false;
|
|
}
|
|
if (rank != other.rank)
|
|
return false;
|
|
if (score != other.score)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public boolean isReasonableData() {
|
|
for (int i=0;i<readRegions.size();i++) {
|
|
if (readRegions.get(i).isNumber()) {
|
|
if (sig_data[i].length()==0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
} |