Problem judge consists of one file and can be written in any language supported by SPOJ. Here I put as example, how you can write it in C/C++. Standard project for SPOJ consists from 3 files: spoj.c, spoj.h and judge.c. First two files are given by SPOJ system developers and in general case looks like:
SPOJ.C
#include <spoj.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
/* file handles */
FILE
*spoj_p_in, /* problem's input */
*spoj_p_out, /* problem's output */
*spoj_t_out, /* tested program's output */
*spoj_t_src, /* tested program's source */
*spoj_score, /* score for the program, for challenge problems */
*spoj_p_info, /* additional info - psetter only */
*spoj_u_info; /* additional info - psetter and solution's owner */
#define __WARN_IF_NULL(x) if (errno=0, (x)==NULL)\
fprintf(stderr, "warning: \"" #x "\" -> %s\n", strerror(errno))
#define __BUF_SIZE 1024*1024
static char buffer[__BUF_SIZE+1];
static void spoj_finalize();
void spoj_init() {
__WARN_IF_NULL(spoj_p_in = fdopen(SPOJ_P_IN_FD,"r"));
__WARN_IF_NULL(spoj_p_out = fdopen(SPOJ_P_OUT_FD,"r"));
__WARN_IF_NULL(spoj_t_out = fdopen(SPOJ_T_OUT_FD,"r"));
__WARN_IF_NULL(spoj_t_src = fdopen(SPOJ_T_SRC_FD,"r"));
__WARN_IF_NULL(spoj_score = fdopen(SPOJ_SCORE_FD,"w"));
__WARN_IF_NULL(spoj_p_info = fdopen(SPOJ_P_INFO_FD,"w"));
__WARN_IF_NULL(spoj_u_info = fdopen(SPOJ_U_INFO_FD,"w"));
atexit(spoj_finalize);
}
static void spoj_finalize() {
fclose(spoj_p_in);
fclose(spoj_p_out);
fclose(spoj_t_out);
fclose(spoj_t_src);
fclose(spoj_score);
fclose(spoj_p_info);
fclose(spoj_u_info);
}
unsigned spoj_file_length(FILE *file) {
int fd = fileno(file);
unsigned size = 0;
unsigned temp;
while ((temp = read(fd, buffer, __BUF_SIZE))>0)
size+=temp;
return size;
}
void __spoj_assert_fail(char *s, int r) {
if (!r) {
fprintf(spoj_p_info, "%s\n", s);
exit(SPOJ_RV_NEGATIVE);
}
}
For local debug, its useful to slightly change functions spoj_init() and spoj_finalize() for your own necessities. Standard availble streams:
*spoj_p_in - problem input data
*spoj_p_out - problem output data
*spoj_t_out - output generated by user program
*spoj_t_src - source code of tested solution
*spoj_score - score
*spoj_p_info - 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
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef __SPOJ_H__
#define __SPOJ_H__
#include <stdio.h>
/* return values */
#define SPOJ_RV_POSITIVE 0
#define SPOJ_RV_NEGATIVE 1
#define SPOJ_RV_IE 2
/* descriptor numbers */
#define SPOJ_P_IN_FD 0
#define SPOJ_P_OUT_FD 4
#define SPOJ_T_OUT_FD 3
#define SPOJ_T_SRC_FD 5
#define SPOJ_SCORE_FD 1
#define SPOJ_P_INFO_FD 6
#define SPOJ_U_INFO_FD 7
/* file handles */
extern FILE
*spoj_p_in, /* problem's input */
*spoj_p_out, /* problem's output */
*spoj_t_out, /* tested program's output */
*spoj_t_src, /* tested program's source */
*spoj_score, /* score for the program, for challenge problems */
*spoj_p_info, /* additional info - problemsetter only */
*spoj_u_info; /* additional info - psetter and solution's owner */
/* must be called before using other functions or variables */
void spoj_init();
/* spoj "files" are really pipes, this is the recommended way to tell size */
/* the file's data is unaccessible later, so use it only if it doesn't matter */
unsigned spoj_file_length(FILE*);
/* use spoj_assert()! */
/* usual assert() from assert.h will cause "judge's internal error" in the future! */
#define spoj_assert(x) __spoj_assert_fail(__FILE__ ":" __spoj_xstr(__LINE__) ": SPOJ assertion `" #x "' failed.", x)
#define __spoj_str(x) #x
#define __spoj_xstr(x) __spoj_str(x)
void __spoj_assert_fail(char*, int);
#endif
#ifdef __cplusplus
}
#endif
Judge example: Real judge for problem “Digits of PI” (not so accurate):
Judge.C
#include <cstdio>
#include <spoj.h>
#define LIMIT 1000000
#define mMin(a, b) (((a)<(b))?(a):(b))
char s[LIMIT], o[LIMIT];
int main()
{
int i;
spoj_init();
int lo = fread (o, 1, LIMIT, spoj_t_out);
int ls = fread (s, 1, LIMIT, spoj_p_out);
while (lo>0 && o[lo-1]=='\n') lo--;
while (ls>0 && s[ls-1]=='\n') ls--;
spoj_assert(lo > 0);
for (i = 0; i < mMin(lo, ls); i++)
if (s[i]!=o[i])
break;
fprintf (spoj_score, "%d\n", i);
return 0;
}
Judge example: Real judge for problem “Size Contest”:
Judge.C
#include "spoj.h"
#include <stdio.h>
#include <string.h>
int main()
{
int a, b, i;
int score;
int c;
spoj_init();
/* Check for AC */
fscanf(spoj_p_out, "%d", &a);
fscanf(spoj_t_out, "%d", &b);
if (b != a)
return 1;
score = 0;
for (i = 0; i < 10003; i++)
{
c = fgetc(spoj_t_src);
if (c > 32)
score++;
}
fprintf (spoj_score, "%d\n", score);
return 0;
}
Any nonzero return from judge interpreted by SPOJ, as Wrong Answer.