Judge != Master Judge
You should allow only TEXT submissions (to prevent of execution)
Set 'Problem type' to 'interactive' (more results)
Judge's TLE == IE
For classic problems judge's time limit is const and == 150s, for interactive problems judge's time limit is 2 * solution's time limit + 2s. You can use getrlimit() to determine it.
What information becomes available for what kind of judge indeed wasn't clear for me while writing early prototypes of my judge. My questions were specifically related to judges, not master judges. I had to find out the use of the exit status for judges by trial-and-error. I never found any documentation about that. Up until now it is still unclear to me how to generate a "run-time errors" status from judges. My judge is able to detect run-time errors, but I've found no way to set this status using an appropriate exit status.
My Python-specific judge (using doctests) doesn't suffer from the fact that SPOJ does run the user code. It simply ignores the outcome of that process. My problem with allowing only TEXT submissions (which would prevent an extra execution of the code) is that users (in my case students that are new to programming) submit Python code. Having them submit their code as TEXT would be quite confusing.
One particular reason I've written a generic Python-specific, is to perform tests on source code beyond a test purely based on input/output. It also allows mixing source code submitted by the user with additional source code. For example a skeleton of classes users have to further implement or code that adds extra layers to the source code submitted by the user, e.g. to provide additional feedback or add a graphical layer to it. In my opinion, the design decision to automatically execute the source code provided by the user is to tightly linked with the idea of testing the "correctness" of submitted source code, based only on the output the software generates for a given input. A more flexible solution would use "lazy execution". With that, I mean that the source code of the user is only executed in case the judge requests the output generated by the source code. This would mean that if the judge ignores the output, the code is never executed beyond the control of the judge.
Explain "more results". As far as I understood the principle behind interactive problems, it means that the judge can respond interactively to output generated by the program submitted by the user. This output on it's turn then can be used by the user program. For the moment, I think I don't need this feature, unless I've got it wrong.
This I figured out. However, I would like my Python-specific judge to take into account the time limit that is specified in the problem definition. In order to do that, the judge should be able to access that time limit (e.g. through an environment variable).
The getrlimit() function actually is the answer to my question addressed in point number 4. I can also get the information coming from that system call in Python.
Judge: problem_input, problem_output, tested_output, tested_src.
Master Judge: results of testcases, tested_src.
// spoj.h
#define SPOJ_RV_POSITIVE 0
#define SPOJ_RV_NEGATIVE 1
#define SPOJ_RV_IE 2
// spoj_interactive.h
#define SPOJ_RV_AC 0
#define SPOJ_RV_WA 1
#define SPOJ_RV_SE 2
#define SPOJ_RV_CE 3
#define SPOJ_RV_RE 4
#define SPOJ_RV_TLE 5
#define SPOJ_RV_MLE 6
#define SPOJ_RV_EOF 7
#define SPOJ_RV_IE 255
In each testcase judge is executed only if there was no problem with tested (RE/TLE/MLE).
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.
[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.
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;
}
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++.
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;
}
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;
}
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]
You should receive something. You request could be missed, please use the form available here: spoj.com/info/4
Not deleted, but rather moved here8 as it will take many places.