C++, score: 4.026 3.998
improvement: added M, E and S rotations; now eats even more RAM
Fortunately, there is no memory limit here! This program can use over 10 GB of RAM, if you are unlucky enough.
Uses a heavily modified A*-like algorithm that doesn't find even nearly optimal solutions.
It takes at least 2 bytes to cause any change to the notepad, and another byte to print it, so getting a score below 3 is almost certainly impossible.
Uses a shamelessly stolen large part of the https://codegolf.stackexchange.com/a/104881 answer to "Simulate a Rubik's cube" (by user "cmaster - reinstate monica") (for some reason I remember golfing that answer, but I can't find any related comments).
//#define _GLIBCXX_DEBUG
#include <x86intrin.h>
#include <cstring>
#include <iostream>
#include <streambuf>
#include <bitset>
#include <cstdio>
#include <atomic>
#include <vector>
#include <algorithm>
#include <cmath>
#include <climits>
#include <random>
#include <set>
#include <list>
#include <map>
#include <unordered_map>
#include <deque>
#include <stack>
#include <queue>
#include <string>
#include <iomanip>
#include <unordered_set>
#include <thread>
#define faceMove(offset) {offset,offset+1,offset+2,offset+15,offset+28,offset+27,offset+26,offset+13}
int faceMoves[9][8] = {
faceMove(3), //Up
faceMove(39), //Left
faceMove(42), //Front
faceMove(45), //Right
faceMove(48), //Back
faceMove(81), //Down
{0,0,0,0, 0,0,0,0}, //M
{0,0,0,0, 0,0,0,0}, //E
{0,0,0,0, 0,0,0,0}, //S (these 3 move the centers in Cubically)
}, lineMoves[9][12] = {
{50,49,48,47,46,45,44,43,42,41,40,39}, //Up
{3,16,29,42,55,68,81,94,107,76,63,50}, //Left
{29,30,31,45,58,71,83,82,81,67,54,41}, //Front
{109,96,83,70,57,44,31,18,5,48,61,74}, //Right
{39,52,65,107,108,109,73,60,47,5,4,3}, //Back
{65,66,67,68,69,70,71,72,73,74,75,76}, //Down
{0*13 + 4, 1*13 + 4, 2*13 + 4, 3*13 + 4, 4*13 + 4, 5*13 + 4, 6*13 + 4, 7*13 + 4, 8*13 + 4, 5*13 + 10, 4*13 + 10, 3*13 + 10}, //M
{4*13 + 0, 4*13 + 1, 4*13 + 2, 4*13 + 3, 4*13 + 4, 4*13 + 5, 4*13 + 6, 4*13 + 7, 4*13 + 8, 4*13 + 9, 4*13 + 10, 4*13 + 11}, //E
{1*13 + 3, 1*13 + 4, 1*13 + 5, 3*13 + 7, 4*13 + 7, 5*13 + 7, 7*13 + 5, 7*13 + 4, 7*13 + 3, 5*13 + 1, 4*13 + 1, 3*13 + 1} //S
};
#undef faceMove
void cubeRotate(std::string& cube, int* move, int rotation)
{
int sign = rotation < 0 ? -1 : 1;
for(int* submove = move; submove != move + rotation; submove += sign)
{
char takeout = cube[submove[3*rotation]];
for(int j = 3; j --> 0;) cube[submove[j * rotation + rotation]] = cube[submove[j*rotation]];
cube[*submove] = takeout;
}
}
std::string cubeMove(std::string cube, int move, int inverted)
{
cubeRotate(cube, faceMoves[move + inverted] - inverted, inverted ? -2 : 2);
cubeRotate(cube, lineMoves[move + inverted] - inverted, inverted ? -3 : 3);
return cube;
}
std::string cubeStart = 1+R"(
000
000
000
111222333444
111222333444
111222333444
555
555
555 )";
std::array<char, 6> faceVals(const std::string& s)
{
std::array<char, 6> fvs {};
int xs[6] { 3, 0, 3, 6, 9, 3};
int ys[6] { 0, 3, 3, 3, 3, 6};
for(int i = 0; i < 6; i++)
{
char ts = 0;
for(int y = ys[i]; y < ys[i] + 3; y++)
for(int x = xs[i]; x < xs[i] + 3; x++)
ts += s[y * 13 + x] - '0';
fvs[i] = ts;
}
return fvs;
}
std::string target;
struct sstate
{
int i;
std::string cube;
int notepad;
char prevCmd;
int movesSincePrint = 0;
bool operator < (const sstate& rhs) const
{
return std::tie(i, notepad, cube, prevCmd) < std::tie(rhs.i, rhs.notepad, rhs.cube, rhs.prevCmd);
}
int heur() const
{
return 3 * (target.size() - i);
}
};
std::vector<std::pair<sstate, char>> neighbours(sstate of)
{
std::array<char, 6> fvs = faceVals(of.cube);
std::vector<std::pair<sstate, char>> ans;
if(target[of.i] == of.notepad) return {{{of.i+1, of.cube, of.notepad, '@', 0}, '@'}};
for(char c : "+-*/X&|:_")
ans.push_back({{of.i, of.cube, of.notepad, c}, c});
if(of.prevCmd == '+' && of.notepad < 512)
for(int i = 0; i < 6; i++)
{
if(of.notepad + fvs[i] > 512) continue;
auto next = of; next.notepad += fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '-' && of.notepad < 512)
for(int i = 0; i < 6; i++)
{
if(of.notepad - fvs[i] > 512) continue;
auto next = of; next.notepad -= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '*' && of.notepad < 512)
for(int i = 0; i < 6; i++)
{
if(fvs[i] * of.notepad > 65536) continue;
auto next = of; next.notepad *= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '/')
for(int i = 0; i < 6; i++)
{
if(fvs[i] == 0) continue;
auto next = of; next.notepad /= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == 'X' && of.notepad < 512)
for(int i = 0; i < 6; i++)
{
if((of.notepad ^ fvs[i]) > 512) continue;
auto next = of; next.notepad ^= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '&')
for(int i = 0; i < 6; i++)
{
auto next = of; next.notepad &= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '|' && of.notepad < 512)
for(int i = 0; i < 6; i++)
{
if((of.notepad | fvs[i]) > 512) continue;
if(fvs[i] == 0) continue;
auto next = of; next.notepad |= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == '_')
for(int i = 0; i < 6; i++)
{
if(fvs[i] == 0) continue;
auto next = of; next.notepad %= fvs[i]; ans.push_back({next, i+'0'});
}
if(of.prevCmd == ':')
for(int i = 0; i < 6; i++)
{
auto next = of; next.notepad = fvs[i]; ans.push_back({next, i+'0'});
}
if(of.cube != cubeStart) { auto next = of; next.prevCmd = '~'; next.cube = cubeStart; ans.push_back({next, '#'}); }
std::string moves = "ULFRBDMES";
for(int i = 0; i < 9; i++)
if(of.prevCmd == moves[i])
{
auto next = of;
next.cube = cubeMove(next.cube, i, false);
next.cube = cubeMove(next.cube, i, false);
next.prevCmd = '~';
ans.push_back({next, '\''});
}
if(of.movesSincePrint < 1 || (of.movesSincePrint == 1 && 'A' <= of.prevCmd && of.prevCmd <= 'Z'))
for(int i = 0; i < 9; i++)
{
auto next = of;
next.cube = cubeMove(next.cube, i, false);
next.prevCmd = moves[i];
next.movesSincePrint++;
ans.push_back({next, moves[i]});
}
return ans;
}
struct astate
{
sstate ss;
int f;
bool operator < (const astate& rhs) const
{
if(f != rhs.f) return f < rhs.f;
if(ss.heur() != rhs.ss.heur()) return ss.heur() < rhs.ss.heur();
return ss < rhs.ss;
}
};
std::string metagolf(std::string target)
{
::target = target;
std::map<sstate, std::pair<sstate, std::string>> prev;
astate start = {{0, cubeStart, 0, '~'}, 0};
std::map<sstate, int> dists; dists[start.ss] = 0;
std::set<astate> openset; openset.insert(start);
int nodes = 0;
std::vector<int> ics(target.size() + 3);
sstate best; int bestdist = INT_MAX; bool done = false;
std::vector<std::set<std::string>> cubes(target.size() + 1);
int itsleft = 10000;
int curI = 0;
int lastChange = 0;
while(!openset.empty() && (!done || itsleft --> 0))
{
auto it = openset.begin();
auto[cs, cf] = *it; openset.erase(it);
int cd = dists[cs];
if(cs.i == target.size()) { if(cd < bestdist) bestdist = cd, best = cs; done = true; continue; }
if(cs.i < curI) continue;
if(cs.i > curI) cubes[cs.i].insert(cs.cube);
if((cubes[cs.i].size() > 1000 && cs.i > curI) || (cubes[cs.i].size() > 0 && cs.i > curI && nodes - lastChange > 5e4)) curI = cs.i, lastChange = nodes;
if(nodes % 128 == 0) printf("n=%d, cf=%d, i=%d, notepad=%d, tc=%d\r", nodes, cf, cs.i, cs.notepad, target[cs.i]);
nodes++;
for(auto[next, cmd] : neighbours(cs))
{
if(dists.count(next) && dists[next] <= cd + 1) continue;
dists[next] = cd + 1;
prev[next] = {cs, std::string(1, cmd)};
openset.insert((astate){next, cd + 1 + next.heur()});
}
}
std::string ans = "";
while(prev.count(best))
{
auto[pr, cmd] = prev[best];
best = pr;
ans += cmd;
}
std::reverse(ans.begin(), ans.end());
return ans;
}
std::string gen_random(int len)
{
static const char alphanum[] = "0123456789"
"~!@#$%^&*()_+`-=[]\\;',./{}|:\"<>?" //this is obviously not alphanumeric
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
std::string s;
while(len --> 0) s += alphanum[rand() % (sizeof(alphanum) - 1)];
return s;
}
int main()
{
//auto cube = cubeStart;
//for(int i = 0; i < 9; i++) cube = cubeMove(cube, i, 0);
//for(int i = 0; i < 9; i++) cube = cubeMove(cube, i, 1);
//printf("%s\n", cube.data());
double ans = 0;
for(int i = 0; i < 100; i++)
{
std::string s = gen_random(rand() % 35 + 5);
std::string code = metagolf(s);
printf("%s: %s\n", s.data(), code.data());
ans += code.size() * 1.0 / s.size();
}
printf("%lf\n", ans * 1.0 / 100);
//std::string ts = "Hello, World!";
//int n = ts.size();
//printf("%s\n", metagolf(ts).data());
}
To avoid Unicode handling, this program performs certain character substitutions: X
corresponds to ⊕
, &
to ·
, and #
to ▦
.
I used this to create an answer to "Hello, World!": https://codegolf.stackexchange.com/a/206322
@6
- print the sum of the nonexistent 6th-indexed face (notepad) as a character" be more accurate? Is%4
also a sum? Are+
commands sum face then add that to all values or...? \$\endgroup\$@6
/%6
just directly prints the notepad value as a character/integer.@x
/%x
(where x is any existing face) adds all values on thex
-indexed face and prints the sum as a character/integer.+
adds all the values on the specified face to the register. \$\endgroup\$