Golfing strings in Fourier
><>, 14310665 bytes
601398 for hamlet + 13709267 for genesis
This is still a work in progress and takes a lot of time to complete.
v
0
>i:0(?;:r-:?!v:0a-)?v v
>~:v ~ >:a(?v>
:1+?v~'v'o v o'^'~\:0)?v
>n vno'+' ^?=1:<
^ o'a'<
Python, 14307118 bytes
601216 for Hamlet + 13705902 for Genesis = 14307118
There are definitely some senarios under which this solution is not optimal, such as for 1111
, where it will output 1111o
as opposed to 11oo
. However, I think it is nearly optimal.
Edit: Saved a few bytes by improving 0o0o
to 0oo
.
The name of the file containing the input is received on STDIN, output to STDOUT.
Results verified with the official interpreter.
def opt_str(char, acc):
opts = []
char_num = ord(char)
opts.append(str(char_num))
if 0 < char_num - acc < 10:
opts.append('+' + str(char_num - acc))
if 0 < acc - char_num < 10:
opts.append('-' + str(acc - char_num))
if char_num - acc == 1:
opts.append('^')
if acc - char_num == 1:
opts.append('v')
if acc == char_num:
opts.append('')
if acc and char_num % acc == 0:
opts.append('*' + str(char_num//acc))
try:
if acc // (acc // char_num) == char_num:
opts.append('/' + str(acc // char_num))
except:
pass
return [opt for opt in opts if len(opt) == len(min(opts, key=len))]
acc = 0
result = []
pos = 0
with open(input(), "r") as myfile:
in_str = myfile.read()
while pos < len(in_str):
i = in_str[pos]
pos += 1
if i in '0123456789':
if i != '0':
while pos < len(in_str) and in_str[pos] in '0123456789':
i += in_str[pos]
pos += 1
if i == str(acc):
result.append('o')
else:
result.append(i + 'o')
acc = int(i)
else:
opts = opt_str(i, acc)
result.append(opts[0] + 'a')
acc = ord(i)
print(''.join(result))
Java, 14307140 bytes
Hamlet - 601,218
Genesis - 13,705,922
The idea here is to do all the work upfront, by making a character->character map. Then you can just loop through and grab the shortest strings.
A bit of an exception has to be made for numerals, so I check for them in the main loop. It's still fast, though, and handles the larger test case in a few seconds. I may be able to tweak this section for a couple more bytes, but I'm fairly sure it's close to optimum.
Input is a filename as argument. Output is written to a file inputFilename_out.4
, and the character count is sent to STDOUT.
This is 1737 bytes for the tiebreaker, completely ungolfed. I can golf it a lot if needed, but it's still going to be a bit big.
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Paths;
import java.text.NumberFormat;
public class FourierMapper {
public static void main(String[] args) throws Exception {
FourierMapper fm = new FourierMapper();
fm.createMap();
String filename = args.length>0? args[0]:"bible.txt";
String out = fm.fourierize(filename);
System.out.println(out.length());
Files.write(Paths.get(filename + "_out.4"), out.getBytes(), new OpenOption[]{});
}
String[][] map = new String[9999][256];
void createMap(){
for(int from=0;from<9999;from++){
for(int to=0;to<256;to++){
if(to<10||from<1){
map[from][to] = ""+to;
} else if(to==from){
map[from][to] = "";
} else if(to-from==1){
map[from][to] = "^";
} else if(to-from==-1){
map[from][to] = "v";
} else if(to>99){
if(to%from<1){
map[from][to] = "*"+(to/from);
} else if(to>from&&to-from<10){
map[from][to] = "+"+(to-from);
} else if(from>to&&from-to<10){
map[from][to] = "-"+(from-to);
} else {
map[from][to] = ""+to;
}
} else {
map[from][to] = ""+to;
}
}
}
}
String fourierize(String filename) throws Exception{
StringBuilder out = new StringBuilder();
byte[] in = Files.readAllBytes(Paths.get(filename));
String whole = new String(in);
out.append(in[0] + "a");
int number = -1;
for(int i=1;i<in.length;){
if(in[i]<58&&in[i]>47){
number = in[i]==48?0:((Number)NumberFormat.getInstance().parse(whole.substring(i,i+4))).intValue();
out.append(""+number+"o");
i += (""+number).length();
} else {
if(number<0)
out.append(map[in[i-1]][in[i]]+"a");
else
out.append(map[number][in[i]]+"a");
number = -1;
i++;
}
}
return out.toString();
}
}