This is my first custom judge, written with the thoughtful help of Mitch Schwartz, for the problem www.spoj.com/problems/GODNIS20/7
I had to change it because some users guessed the input. Since the problem ranks the user by the total sum of moves, some users created programs to add redundancy depending on the scrambled cube positions. In this way, they observed how the score changed, got the cubes and then executed, outside SPOJ, in long time programs that always find optimal solutions and send it with precomputations. If you have a solved cube and perform F2 F2, the cube is still solved. The did like this:
Let's say 1 is for Green and 2 if for Yellow.
If you add (F2 F2), the cube is still solved and you can call this 1. If you add (F2 F2) (F2 F2), the cube is again solved. Let's call this 2. Etc. I thank Stefan Pochmann for foreseeing this.
The workaround was to add an interactive judge that gives random scrambled cubes. In this way, there's no room for guessing like that. The "lucky effect" is about 1%, in my tests, i.e., standard deviation/average is about 0,01. Perhaps in the future I'll add the interactive judge here as well.
I just shared this because I think that the problem setters must have this features in mind, depending on the problem.
/*
Author: Alexandre Henrique Afonso Campos
Judge for: www.spoj.com/problems/GODNIS20/
Created: 13 Fev 2016
Finished: 27 Fev 2016
Thanks: Mitch Schwartz
*/
#include "spoj.h"
#include <stdio.h>
#include <string.h>
#define ReadColor(i, j, k) { color = read_color(); if (color == -1) return -1; cube[(i)][(j)][(k)] = color; }
//FILE* spoj_p_in;
//FILE* spoj_t_out;
// U -> 0
// L -> 1
// F -> 2
// R -> 3
// B -> 4
// D -> 5
// targets of the moves
int U_perm[5][4][3] = { { {1, 0, 0}, {4, 0, 0}, {3, 0, 0}, {2, 0, 0} }, { {1, 0, 1}, {4, 0, 1}, {3, 0, 1}, {2, 0, 1} }, { {1, 0, 2}, {4, 0, 2}, {3, 0, 2}, {2, 0, 2} }, {{0, 0, 0}, {0, 0, 2}, {0, 2, 2}, {0, 2, 0}}, {{0, 0, 1}, {0, 1, 2}, {0, 2, 1}, {0, 1, 0}} },
L_perm[5][4][3] = { { {0, 0, 0}, {2, 0, 0}, {5, 0, 0}, {4, 2, 2} }, { {0, 1, 0}, {2, 1, 0}, {5, 1, 0}, {4, 1, 2} }, { {0, 2, 0}, {2, 2, 0}, {5, 2, 0}, {4, 0, 2} }, {{1, 0, 0}, {1, 0, 2}, {1, 2, 2}, {1, 2, 0}}, {{1, 0, 1}, {1, 1, 2}, {1, 2, 1}, {1, 1, 0}} },
F_perm[5][4][3] = { { {0, 2, 0}, {3, 0, 0}, {5, 0, 2}, {1, 2, 2} }, { {0, 2, 1}, {3, 1, 0}, {5, 0, 1}, {1, 1, 2} }, { {0, 2, 2}, {3, 2, 0}, {5, 0, 0}, {1, 0, 2} }, {{2, 0, 0}, {2, 0, 2}, {2, 2, 2}, {2, 2, 0}}, {{2, 0, 1}, {2, 1, 2}, {2, 2, 1}, {2, 1, 0}} },
R_perm[5][4][3] = { { {0, 2, 2}, {4, 0, 0}, {5, 2, 2}, {2, 2, 2} }, { {0, 1, 2}, {4, 1, 0}, {5, 1, 2}, {2, 1, 2} }, { {0, 0, 2}, {4, 2, 0}, {5, 0, 2}, {2, 0, 2} }, {{3, 0, 0}, {3, 0, 2}, {3, 2, 2}, {3, 2, 0}}, {{3, 0, 1}, {3, 1, 2}, {3, 2, 1}, {3, 1, 0}} },
B_perm[5][4][3] = { { {0, 0, 2}, {1, 0, 0}, {5, 2, 0}, {3, 2, 2} }, { {0, 0, 1}, {1, 1, 0}, {5, 2, 1}, {3, 1, 2} }, { {0, 0, 0}, {1, 2, 0}, {5, 2, 2}, {3, 0, 2} }, {{4, 0, 0}, {4, 0, 2}, {4, 2, 2}, {4, 2, 0}}, {{4, 0, 1}, {4, 1, 2}, {4, 2, 1}, {4, 1, 0}} },
D_perm[5][4][3] = { { {2, 2, 0}, {3, 2, 0}, {4, 2, 0}, {1, 2, 0} }, { {2, 2, 1}, {3, 2, 1}, {4, 2, 1}, {1, 2, 1} }, { {2, 2, 2}, {3, 2, 2}, {4, 2, 2}, {1, 2, 2} }, {{5, 0, 0}, {5, 0, 2}, {5, 2, 2}, {5, 2, 0}}, {{5, 0, 1}, {5, 1, 2}, {5, 2, 1}, {5, 1, 0}} };
int cube[6][3][3];
// BEGIN MOVE THE CUBE
void move_perm(int perm[5][4][3], int d) {
int i, j;
for (i=0; i<5; i++){
int temp[4];
for (j=0; j<4; j++) {
temp[j] = cube[perm[i][j][0]][perm[i][j][1]][perm[i][j][2]];
}
for (j=0; j<4; j++) {
cube[perm[i][j][0]][perm[i][j][1]][perm[i][j][2]] = temp[(4+j-d)%4];
}
}
}
void move_face(char face, char d) {
switch (face) {
case 'U': move_perm(U_perm, d); break;
case 'L': move_perm(L_perm, d); break;
case 'F': move_perm(F_perm, d); break;
case 'R': move_perm(R_perm, d); break;
case 'B': move_perm(B_perm, d); break;
case 'D': move_perm(D_perm, d); break;
default: ;
}
}
// END MOVE THE CUBE
int is_solved(void) {
int i, j, k;
for (i=0; i<6; i++) {
for (j=0; j<3; j++) {
for (k=0; k<3; k++) {
if (cube[i][j][k] != i) {
return 0;
}
}
}
}
return 1;
}
int read_color(void) {
char colors[] = "WOGRBY";
char ch, *ptr;
if (fscanf(spoj_p_in, " %c", &ch) != 1) return -1;
ptr = strchr(colors, ch);
if (!ptr) return -1;
return (int)(ptr - colors);
}
int read_cube(void) {
int color;
int i, j, k;
for (j=0; j<3; j++) {
for (k=0; k<3; k++) {
ReadColor(0, j, k);
}
}
for (j=0; j<3; j++) {
for (i=1; i<5; i++) {
for (k=0; k<3; k++) {
ReadColor(i, j, k);
}
}
}
for (j=0; j<3; j++) {
for (k=0; k<3; k++) {
ReadColor(5, j, k);
}
}
return 0;
}
int main(void) {
spoj_init();
// spoj_p_in = fopen ("cases.txt" , "r");
// spoj_t_out = fopen ("solve_old_pochmann.txt" , "r");
int d, n, t;
int len;
int score = 0;
int skipped_all = 1;
char move[4];
if (fscanf(spoj_p_in, "%d", &t) != 1) return SPOJ_RV_IE;
while (t--) {
if (read_cube() == -1) return SPOJ_RV_IE;
if (fscanf(spoj_t_out, "%d", &n) != 1) return SPOJ_RV_NEGATIVE;
if (n == -1) {
score += 1000;
continue;
}
if (n<0 || n>1000) return SPOJ_RV_NEGATIVE;
score += n;
skipped_all = 0;
while (n--) {
if (fscanf(spoj_t_out, "%3s", move) != 1) return SPOJ_RV_NEGATIVE;
len = strlen(move);
if (len == 3) return SPOJ_RV_NEGATIVE;
if (!strchr("LRUDFB", move[0])) return SPOJ_RV_NEGATIVE;
if (len == 1) d = 1;
else if (move[1] == '2') d = 2;
else if (move[1] == '\'') d = 3;
else return SPOJ_RV_NEGATIVE;
move_face(move[0], d);
}
if (!is_solved()) return SPOJ_RV_NEGATIVE;
}
if (fscanf(spoj_t_out, " %c", move) != EOF) return SPOJ_RV_NEGATIVE;
if (skipped_all) return SPOJ_RV_NEGATIVE;
fprintf(spoj_score, "%d\n", score);
// printf("%d\n", score);
return SPOJ_RV_POSITIVE;
}