32 / 44
Jan 2013

Thanks for the explanation about the extended list of exit statuses when using an interactive job. This indeed helped me out in properly reporting run-time errors in my generic Python judge based on doctests. However (detail): I don't understand the design decision for the SPOJ backend to make a distinction between the supported exit status list for regular judges and interactive judges.

This indeed provides the time limit as I need it. Thanks.

2 months later

[quote="Turbo"]
[b]SPOJ.C[/b]

        *spoj_u_info,   /* additional info - psetter only */
        *spoj_p_info;   /* additional info - psetter and solution's owner */

[..]
[i]*spoj_p_info[/i] - additional info availible to problemsetter (I recomend to use this possibility, you can check for errors or intermediate test data during contest. All stored information availible only to problemsetter).

[..]

SPOJ.H

        *spoj_p_info,   /* additional info - problemsetter only */
        *spoj_u_info;   /* additional info - psetter and solution's owner */

[/quote]
Just to make sure, spoj_p_info, file descriptor 6, is only available to problemsetters and spoj_u_info, file descriptor 7, is available to both users and problemsetters? Note that in the spoj.c example the descriptions are the other way around, but judging on the names I would assume that the one in spoj.h is the correct one.

21 days later
2 months later

HI
I uploaded 2 test cases and for 'RAONE'
after that i uploaded 1 more test case .. When i rejudge only the first 2 test cases were getting judged .. why not the new one ?

8 months later

Maybe your post is so old that it's useless to respond, but it seems you forgot to check the box for "Refresh cached info about test sequence" above the "Start rejudge" button.

18 days later

Just for your information here is my judge for PELL4C5.

#include "spoj.h"
#include <stdlib.h>
using namespace std;
#define SEUIL 45
// SEUIL is the minimum number of line to output to get AC.
/*
 * This a variation around the judge 'ignore whitespace',
 * for the problem PELL4C.
 * So you can use every whitespace separator
 */
// <0-255> normal, - 1 white, -2 eof
int getChar(FILE *f, bool ignWhite) {
	bool white;
	int ch;
	do {
		if ((ch = getc(f))==EOF)
			return -2;
		if (ch==' ' || ch=='\n' || ch=='\t' || ch=='\r')
			white=true;
		else white=false;
	} while (ignWhite && white);
	if (white)
		return -1;
	return ch;
}
void myexit(int score) {
	score>>=1; // now 1p per lines
	if (score<SEUIL)
		exit(SPOJ_RV_NEGATIVE);
	fprintf(spoj_score, "%d\n", score );
	exit(SPOJ_RV_POSITIVE);
}
int main(void) {
	int score=0;
	spoj_init();
	bool ignWhite = true;
	int ch1 = getChar(spoj_t_out, ignWhite);
	int ch2 = getChar(spoj_p_out, ignWhite);
	while (ch1 == ch2) {
		if (ch1==-2) {
			if (!ignWhite)
				++score;
			myexit(score);
		}
		if (ch1==-1){
			ignWhite =true;      ++score; // 2p per lines
		} else
			ignWhite=false;
		ch1 = getChar(spoj_t_out, ignWhite);
		ch2 = getChar(spoj_p_out, ignWhite);
	};
	if (ch1 == -2){
		/*
		 * we're taking care of several cases for last line output
		 * "10 19 " -> 1 more point
		 * "10 19"  -> 1 more point
		 * "10 "    -> 0 point
		 * "10"     -> 0 point
		 */
		if (!ignWhite)
			++score;
		myexit(score);
	}
	if (ch2 == -2 && ch1 == -1 && getChar(spoj_t_out, true)==-2)
		myexit(++score);
	return SPOJ_RV_NEGATIVE;
}
11 days later
1 month later

For your information, here's a fac simile of my judge for TIP3.

#include "spoj_interactive.h"
#include <time.h>
#define Q 2
  // or another one
int main(){
    spoj_init();
      // always at the beginning
    srand ( time(NULL) + 123456789 );
  // or another number...

int secret;
secret = rand()%Q;

const char *entree[Q] = {"222", "2222"};
  // or some other input strings, my own input ones ;-)
const char *sortie[Q] = {"21",  "291"};
  // and corresponding awaited answer
char answer[32];

spoj_printf("%s\n", entree[secret]);
  // using macro to print data for tested
  // in case tested ended -> EOF

spoj_scanf("%s", answer);
  // using macro to get data from tested
  // in case of wrong data -> WA
  // in case tested ended -> EOF

fprintf(spoj_p_info, "%s\n", entree[secret]);
fprintf(spoj_p_info, "%s\n", sortie[secret]);
fprintf(spoj_p_info, "%s\n", answer);
// outputting information that is only available for ps

for(int i=-1;sortie[secret][++i];)
    spoj_assert(sortie[secret][i]==answer[i]);
      // condition unfulfilled -> WA


return SPOJ_RV_AC;
  // AC
}

Feel free to send by PM suggestions to improve it, I'm a noob in C++.

When you update the test files and you want to rejudge
CHECK the flag
"Refresh cached info about test sequence"
(just a little hint to avoid headache when doing a rejudge becaude of you weak testcases files)

regards

4 months later

Here is my judge for BFK_AUTO3:

/*
	Author: Tjandra Satria Gunawan
	Judge for: http://www.spoj.com/problems/AUTO_BFK/
	Created: 24 May 2013
	Finished: 26 May 2013
	Changes:
		-(03 June 2013)Fixed: too many allocated memory
			Thanks to Mitch Schwartz for repporting this bug
*/
#include"spoj.h"
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
typedef unsigned u;
typedef struct S//struct that contatin BF cell, using linked list so total cell available is unlimited! (only limited by SPOJ memory limit)
{
	u data;//*ptr value (initial value is all 0)
	struct S *next,*prev;//next and previous *ptr value
}v;
typedef struct T//struct that contain BF code, using linked list so total code that can be executed is unlimited! (only limited by SPOJ memory limit)
{
	char cmd;//valid command is only: {'+','-','<','>','[',']','.'}
	u rpt;//for optimization only, if there are some repeated command this value will increase
	struct T *next,*jump;//"*next" is next character and "*jump" is useful when '[' and ']' command is executed
}w;
typedef struct M//struct that contain memory address to "struct T" (temporary only: added when '[' command found and stored until closing ']' command found)
{
	w *loc;//this value will copied to "*jump" in "struct T" after ']' command found
	struct M *prev;//this is linked to previous temporary value
}m;
u invalid[128];//value for valid BF ASCII (except comma ',') is 0 otherwise is 1 
#define csn 1//case number, starting from 1
#define start 1//1 for judging first test data, otherwise it set to 0
#define end 0//1 for judging last test data, otherwise it set to 0
//main code begin!
int main()
{
	spoj_init();
	double st=clock();
	if(start)
	{
		fprintf(spoj_u_info,"<u>Last Judge Update</u>: 03 June 2013 (Indonesian time)<br><u>Recent Changes</u>: More efficient memory management but the judge running time will be slower<br><table class=\"judge_output\" width=\"100%c\"><tbody><tr class=\"headerrow\"><th width=\"10%c\" class=\"headerrowleft\">Case Number</th><th width=\"10%c\">I/O Length</th><th width=\"10%c\">BF Length</th><th width=\"10%c\">BF Cell Used</th><th width=\"10%c\">BF Code Called</th><th width=\"10%c\">Judge Time</th><th width=\"40%c\" class=\"headerrowright\">The Judge's Comment</th></tr>",37,37,37,37,37,37,37,37);
	}
	u len,clu,outl,inl,exec,rexec,exbuf,i;
	/*
		len=BF code length
		clu=BF Cell Used
		outl=Output length
		inl=Input length
		exec=Executed command
		rexec=Real executed command
		exbuf=just to check if the judge judge is TLE or not
		i=additional variable (for iteration)
	*/
	for(i=0;i<128;invalid[i++]=1);
	len=outl=rexec=exec=0;
	fseek(spoj_p_in,0,SEEK_END);
	inl=ftell(spoj_p_in);clu=1;exbuf=1000000;
	fseek(spoj_p_in,0,SEEK_SET);
	invalid['+']=invalid['-']=invalid['<']=invalid['>']=invalid['[']=invalid[']']=invalid['.']=0;
	m *now,*new;now=NULL;
	v *ptr;
	w *prog,*tmp;
	ptr=(v*)malloc(sizeof(v));
	ptr->data=0;ptr->next=ptr->prev=NULL;
	char c;
	prog=tmp=(w*)malloc(sizeof(w));tmp->jump=tmp->next=NULL;
	if(prog==NULL)
	{
		fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
		if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
	}
	while((c=fgetc(spoj_t_out))>0)
	{
		if(!invalid[c])break;
		if(c==',')//of course comma: ','(ASCII(44)) is valid BF code but it's invalid here, so I don't accept this output :-p
		{
			fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>There's a comma: ','(ASCII(44)) character on your BF code which is forbidden!</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
			if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
		}
	}
	if(c>0)
	{
		tmp->cmd=c;
		tmp->rpt=1;
		if(c==']')
		{
			fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>invalid BF code: '['(ASCII(91)) and ']'(ASCII(93)) is not match! (too many ']'(ASCII(93)))</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
			if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
		}
		if(c=='[')
		{
			now=(m*)malloc(sizeof(m));
			if(now==NULL)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
			now->prev=NULL;
			now->loc=tmp;
		}
		len++;
	}
	while((c=fgetc(spoj_t_out))>0)
	{
		if(invalid[c])
		{
			if(c==',')
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>There's a comma: ','(ASCII(44)) character on your BF code which is forbidden!</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
			continue;
		}
		len++;
		if(c!='['&&c!=']')
		{
			if(c==tmp->cmd){tmp->rpt++;continue;}
			if((tmp->cmd=='+'&&c=='-')||(tmp->cmd=='-'&&c=='+')||(tmp->cmd=='>'&&c=='<')||(tmp->cmd=='<'&&c=='>'))
			{
				if(tmp->rpt)tmp->rpt--;
				else
				{
					tmp->rpt=1;
					if(tmp->cmd=='+')tmp->cmd='-';
					else if(tmp->cmd=='-')tmp->cmd='+';
					else if(tmp->cmd=='>')tmp->cmd='<';
					else tmp->cmd='>';
				}
				continue;
			}
		}
		if(tmp->rpt)
		{
			tmp->next=(w*)malloc(sizeof(w));
			tmp=tmp->next;
			if(tmp==NULL)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
			tmp->jump=tmp->next=NULL;
		}
		tmp->cmd=c;
		tmp->rpt=1;
		if(c==']')
		{
			if(now==NULL)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>invalid BF code: '['(ASCII(91)) and ']'(ASCII(93)) is not match! (too many ']'(ASCII(93)))</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
			else
			{
				new=now;now=now->prev;
				tmp->jump=new->loc;
				tmp->jump->jump=tmp;
				free(new);
			}
		}
		else if(c=='[')
		{
			if(now==NULL)
			{
				now=(m*)malloc(sizeof(m));
				if(now==NULL)
				{
					fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
					if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
				}
				now->prev=NULL;
			}
			else
			{
				new=(m*)malloc(sizeof(m));
				if(new==NULL)
				{
					fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
					if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
				}
				new->prev=now;now=new;
			}
			now->loc=tmp;
		}
	}
	if(now!=NULL)
	{
		fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>invalid BF code: '['(ASCII(91)) and ']'(ASCII(93)) is not match! (too many '['(ASCII(91)))</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
		if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
	}
	for(tmp=prog;tmp!=NULL;tmp=tmp->next)
	{
		rexec++;
		if((exec+=tmp->rpt)>exbuf)
		{
			exbuf+=1000000;//time to check the time, TLE or not?
			if((clock()-st)/CLOCKS_PER_SEC>22)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Running time >22s (Judge's TLE!) please simplify your BF code!</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
		}
		if(tmp->cmd=='+')ptr->data+=tmp->rpt;
		if(tmp->cmd=='-')ptr->data-=tmp->rpt;
		if(tmp->cmd=='[')if(!ptr->data)tmp=tmp->jump;
		if(tmp->cmd==']')if(ptr->data)tmp=tmp->jump;
		if(tmp->cmd=='>')for(i=tmp->rpt;i--;)
		{
			if(ptr->next!=NULL)ptr=ptr->next;
			else
			{
				ptr->next=(v*)malloc(sizeof(v));
				if(ptr->next==NULL)
				{
					fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
					if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
				}
				ptr->next->prev=ptr;ptr=ptr->next;
				ptr->data=0;ptr->next=NULL;clu++;
			}
		}
		if(tmp->cmd=='<')for(i=tmp->rpt;i--;)
		{
			if(ptr->prev!=NULL)ptr=ptr->prev;
			else
			{
				ptr->prev=(v*)malloc(sizeof(v));
				if(ptr->prev==NULL)
				{
					fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Can't allocate more cells! (SPOJ Memory Problem)</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
					if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
				}
				ptr->prev->next=ptr;ptr=ptr->prev;
				ptr->data=0;ptr->prev=NULL;clu++;
			}
		}
		if(tmp->cmd=='.')for(i=tmp->rpt;i--;)
		{
			outl++;
			c=fgetc(spoj_p_in);
			if(c<0)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Output of your BF code is too many! Your program should exit, but you still printing '%c'(ASCII(%u)) character!</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC,ptr->data,ptr->data);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
			if(c!=ptr->data)
			{
				fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Output of your BF code is not match with the test data: it should print '%c'(ASCII(%u)) but your BF code is printing '%c'(ASCII(%u))</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC,c,c,ptr->data,ptr->data);
				if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
			}
		}
	}
	if((c=fgetc(spoj_p_in))>0)
	{
		fprintf(spoj_u_info,"<tr class=\"kol\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Your BF code exit before completely print entire correct output data: Next character to print is '%c'(ASCII(%u))</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC,c,c);
		if(end)fprintf(spoj_u_info,"</tbody></table>");return 1;
	}
	fprintf(spoj_u_info,"<tr class=\"kol3\" align=\"center\"><td>%u</td><td>%u<br>%u</td><td>%u</td><td>%u</td><td>%u<br>%u</td><td>%.2lf</td><td>Congratulations, Your code run correctly without any problem for this case</td></tr>",csn,inl,outl,len,clu,exec,rexec,(clock()-st)/CLOCKS_PER_SEC);
	if(end)fprintf(spoj_u_info,"</tbody></table>");
	fprintf(spoj_score,"%u\n",len);
	return 0;
}
10 days later

And here is Master Judge for my BFK_AUTO2 problem, written in C language:

#include <spoj.h>
#include <stdio.h>
int main()
{
	spoj_init();
	int test, sig, SIG, mem, memMax=0, MEMMAX, tc=0;
	double score, scoreAll=0, time, timeAll=0, TIMEALL;
	char status[4],STATUS[4],ok=1;
	fprintf(spoj_u_info,"---<b>MasterJudge Output</b>---<br><br><div align=\"left\">");
	while (fscanf(spoj_p_in, "%d %3s %lf %d %lf %d\n", &test, status, &score, &sig, &time, &mem)==6)
	{
		fprintf(spoj_u_info,"<u>Case %.2i</u>: User's Runnig Time=%.2lf Seconds | Status=%s | Memory Usage=%iKB<br>",test,time,status,mem);
		fprintf(spoj_p_info, "test %d - %s (score=%lf, sig=%d, time=%lf, mem=%d)\n", test, status, score, sig, time, mem);
		if (mem > memMax) memMax = mem;
		scoreAll += score;
		if (timeAll >= 0) {
			if (time >= 0)
				timeAll += time;
			else
				timeAll = -1;
		}
		if (status[0]!='A')
		{
			if(ok)
			{
				STATUS[0]=status[0];
				STATUS[1]=status[1];
				STATUS[2]=status[2];
				STATUS[3]=status[3];
				SIG=sig;
				MEMMAX=memMax;
				TIMEALL=timeAll;
				ok=0;
			}
		}
		tc++;
	}
	if(ok)
	{
		fprintf(spoj_u_info,"<br><i>MasterJudge's Comment</i>: Congratulations, now you can optimize your code or find more interesting problem on <a href=\"http://www.spoj.com/problems/TJANDRA/\" target=\"_blank\">TJANDRA</a> page</div><br>");
		fprintf(spoj_score, "AC %lf 0 %lf %d\n",scoreAll, timeAll, memMax);
	}
	else
	{
		fprintf(spoj_u_info,"<br><i>MasterJudge's Comment</i>: Sorry, Your code is not AC, but don't give up :)</div><br>");
		fprintf(spoj_score, "%s 0 %d %lf %d\n", STATUS, SIG, TIMEALL, MEMMAX);
	}
	fprintf(spoj_u_info,"---<b>End of MasterJudge Output</b>---<br>");
	return 0;
}
3 months later

Hi. Currently, adding judges in Haskell (or Python) is not working. If it was, this would be a valid judge for a problem I'm making:
[bbone=haskell,611]
import Control.Applicative ((<$>))
import System.Exit (ExitCode(..), exitWith, exitFailure, exitSuccess)
import System.IO (hGetContents)
import System.Posix.IO (fdToHandle)

data SPOJDescriptor = ProblemInput | ProblemOutput | TestedProgramOutput | TestedProgramSource

descriptorNumber :: SPOJDescriptor -> Int
descriptorNumber ProblemInput = 0
descriptorNumber ProblemOutput = 4
descriptorNumber TestedProgramOutput = 3
descriptorNumber TestedProgramSource = 5

descriptorContents :: SPOJDescriptor -> IO String
descriptorContents d = let fd = fromIntegral (descriptorNumber d)
in fdToHandle fd >>= hGetContents

greedy :: [Integer] -> Integer -> [Integer]
greedy [] 0 = []
greedy (x:xs) k = let (q, r) = quotRem k x
in q:(greedy xs r)

dot :: [Integer] -> [Integer] -> Integer
dot = (sum .) . zipWith (*)

checkCase :: ([Integer], [Integer], [Integer]) -> Bool
checkCase (_, [-1], tested) = tested == [-1]
checkCase ((nplates:plates), _, tested) = let value = plates dot tested
greedySolution = greedy plates value
in length tested == nplates && sum tested < sum greedySolution

parseLine :: String -> [Integer]
parseLine = map read . words

main = do
problemInputLines <- map parseLine . tail . lines <$> descriptorContents ProblemInput
problemOutputLines <- map parseLine . lines <$> descriptorContents ProblemOutput
testedOutputLines <- map parseLine . lines <$> descriptorContents TestedProgramOutput
let triples = zip3 problemInputLines problemOutputLines testedOutputLines
results = map checkCase triples
success = (length problemOutputLines == length testedOutputLines) && and results
if success
then exitSuccess
else exitWith (ExitFailure 1)
[/bbone]

This is currently a valid judge in C++ for the same problem:

[bbone=cpp,612]

include

include

define forsn(i, s, n) for (int i = (s); i < (n); ++i)

define forn(i, n) forsn(i, 0, n)

using namespace std;
typedef vector vint;

FILE* user_answer;
FILE* expected_answer;
FILE* test_case;

inline int get_int(FILE* f) {
int n;
fscanf(f, "%d", &n);
return n;
}

inline int get_user_int() {
return get_int(user_answer);
}

inline int get_expected_int() {
return get_int(expected_answer);
}

inline int get_testcase_int() {
return get_int(test_case);
}

vint greedy(const vint& plates, int k) {
int n = plates.size();
vint ans(n);
forn (i, n) {
int c = plates[i];
int q = k / c;
k = k % c;
ans[i] = q;
}
return ans;
}

int dot(const vint& v, const vint& w) {
int n = v.size();
int ans = 0;
forn (i, n) ans += v[i] * w[i];
return ans;
}

int sum(const vint& v) {
int s = 0, n = v.size();
forn (i, n) s += v[i];
return s;
}

bool check_case() {
int nplates = get_testcase_int();
vint plates(nplates);
forn (i, nplates) plates[i] = get_testcase_int();

int correct_n = get_expected_int(),
user_n = get_user_int();
if (correct_n == -1) {
return user_n == -1;
}

vint user_solution(nplates);
user_solution[0] = user_n;
forn (i, nplates - 1) user_solution[i + 1] = get_user_int();
forn (i, nplates - 1) get_expected_int(); // discard & advance file pointer

int value = dot(plates, user_solution);
vint greedy_solution = greedy(plates, value);
return sum(user_solution) < sum(greedy_solution);
}

void setup() {
user_answer = fdopen(3, "r");
expected_answer = fdopen(4, "r");
test_case = fdopen(0, "r");
}

int main() {
setup();
int ncases = get_testcase_int();
while (ncases--) {
if (!check_case()) return 1;
}
}
[/bbone]

4 months later

I've sent in an application weeks ago and haven't received a reply.

Is this normal, does this mean the application was not accepted?

Thanks in advance.

I resent my application via the form (I used it last time as well). Wish me luck smiley

2 months later

Not deleted, but rather moved here8 as it will take many places. wink

2 years later

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;
}
1 year later
4 years later