package readers ;
import java.io.IOException ;
import java.io.InputStreamReader ;
import java.nio.file.Path ;
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 ;
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 ( " " ) , "" ) ;
}
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 ;
}
}
}
}
}
return Double . parseDouble ( Integer . toString ( numb ) + "." + Integer . toString ( decimal ) ) ;
}
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 ) {
return Integer . parseInt ( numb ) ;
} 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 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 . doubleToLongBits ( pct ) ! = Double . doubleToLongBits ( other . pct ) ) {
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 ;
}
}