#!/usr/bin/env python #RockTest #Programming Competition Judge's Console, "rt_judge", V1.3 #Last modification: January 22, 2005 #RockTest consists primarily of two GUI programs: RockTest Team Console, # and RockTest Judge's Console. There are also a spreadsheet for # tabulation and help files. #Copyright 2003, 2004, 2005 #Michael P. Conlon, Ph.D. #Computer Science Department #Slippery Rock University of Pennsylvania #Slippery Rock, PA 16057 #Email: michael.conlon@sru.edu #724-738-2143 # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # or see http://www.gnu.org/copyleft/gpl.html. #Bugs: none known. #Features needed: # SRU "Rock" icon # Log file # Problem queueing # Clarification acceptance and response #See the comments in RockTest Team Console for more information. from Tkinter import * from string import * import os import commands import threading FALSE=0 TRUE=1 COLOR="#c5ffc5" COLOR2="#ffffcc" MENU=0 ENTRY=1 root=Tk() root.title("RockTest Judge's Console") def strip_cr(text): loc=99999 while loc >= 0: loc = find(text, '\r') if loc >= 0: text = text[:loc] + text[loc+1:] return text class conf_class: def __init__(self): self.runlimit = StringVar() #default maximum runtime for team programs self.runlimit.set("10 sec") #initialized to 10 seconds. self.team_no = StringVar() self.prob_no = StringVar() self.lang = StringVar() self.dfn = StringVar() self.output = StringVar() self.team_no.set("01") self.teams_home=commands.getoutput(\ "grep team01 /etc/passwd | awk -F: '{print $6}'")[:-2] self.prob_no.set("1") self.lang.set("C++") self.dfn.set("program1.dat") self.output.set("") self.ext_map={"BASIC":".bas","C":".c","C++":".cpp","FORTRAN":".for", \ "Java":".java","Pascal":".pas","Python":".py"} self.no_compile = ("BASIC", "Python") self.team_name = "team01" self.prog_fn = "program1.cpp" #Find judge's home directory. #self.judge_home = commands.getoutput("echo $HOME") self.judge_home = os.environ["HOME"] #print "Judge directory is " + self.judge_home self.data=0 #Program parameters #Is there a configuration file? try: #if 1: #If there is, get parameters from the file. fd = open('/usr/local/etc/rocktest/rocktest.conf') self.data = fd.readlines() #print self.data #sys.exit(1) for self.line in self.data: self.line = self.line[:-1] #print "Line:", self.line if self.line[:13] == "problem_count": self.prob_count = atoi(self.line[14:]) elif self.line[:10] == "team_count": self.team_count = atoi(self.line[11:]) #elif self.line[:15] == "language_count": #self.language_ct = atoi(self.line[16:]) #for i in range(self.language_ct): #pass fd.close() #print "File closed." #sys.exit(1) #else: except: #,print "Error processing initialization file." self.team_count = 40 self.prob_count = 10 self.team_list = () for i in range(1, self.team_count+1): if i < 10: self.team_list = self.team_list + ("0" + str(i),) else: self.team_list = self.team_list + (str(i),) self.avail_langs = "BASIC", "C", "C++", "FORTRAN", \ "Java","Pascal","Python" self.prob_list = () for i in range(1, self.prob_count+1): self.prob_list = self.prob_list + (str(i),) conf=conf_class() def clear_dirs(): #Clear old program files from teams' directories. #First, find where team home directories are. #print "Team home is " + conf.team_home for i in range(99): #Loop through all teams' names no = i + 1 team_dir = conf.teams_home if no < 10: team_dir = team_dir + "0" team_dir = team_dir + "%d" % no try: output = os.listdir(team_dir) for file in output: if file[:7] == "program": #print file os.remove("%s/%s" % (team_dir, file)) except OSError: pass class warning_box_class: def __init__(self, parent, name, text, ok_but_text, cancel_but_text, just): self.msg=StringVar() self.tmp_msg=StringVar() self.msg.set(text) self.parent = parent self.name = name self.ok_button_text = ok_but_text self.cancel_button_text = cancel_but_text self.just = just def close(self): #Close the info box. self.warning_box.destroy() def clear_em(self): clear_dirs() self.warning_box.destroy() def create(self, msg=""): #Create the dialog box. self.warning_box=Toplevel(self.parent, bg=COLOR2) self.warning_box.title(self.name) #Use the default message if there is no msg parameter. if msg == "": self.tmp_msg.set(self.msg.get()) else: self.tmp_msg.set(msg) self.abt_msg=Message(self.warning_box, textvariable=self.tmp_msg, justify=self.just, aspect=300, width=400, bg=COLOR2).pack(side=TOP) self.button_frame = Frame(self.warning_box) self.ok_button=Button(self.button_frame, text=self.ok_button_text) self.ok_button.configure(command=lambda obj=self: obj.clear_em()) self.ok_button.pack(side=LEFT) self.cancel_button=Button(self.button_frame, text=self.cancel_button_text) self.cancel_button.configure(command=lambda obj=self: obj.close()) self.cancel_button.pack(side=RIGHT) self.button_frame.pack(side=BOTTOM) #Create "Are you sure?" warning box. box_name="Are you sure?" ok_but_text="Delete Files" cancel_but_text="Cancel" msg="""Warning!!! You are about to delete all users' program files and data files. """ del_warning_box=warning_box_class(root, box_name, msg, ok_but_text, cancel_but_text, CENTER) class info_box_class: def __init__(self, parent, name, text, but_text, just): self.msg=StringVar() self.tmp_msg=StringVar() self.msg.set(text) self.parent = parent self.name = name self.button_text = but_text self.just = just def close(self): #Close the info box. self.info_box.destroy() def create(self, msg=""): #Create the dialog box. self.info_box=Toplevel(self.parent, bg=COLOR2) self.info_box.title(self.name) #Use the default message if there is no msg parameter. if msg == "": self.tmp_msg.set(self.msg.get()) else: self.tmp_msg.set(msg) self.abt_msg=Message(self.info_box, textvariable=self.tmp_msg, justify=self.just, aspect=300, width=400, bg=COLOR2).pack(side=TOP) self.ok_button=Button(self.info_box, text=self.button_text) self.ok_button.configure(command=lambda obj=self: obj.close()) self.ok_button.pack(side=BOTTOM) #Create "About RockTest" info box. box_name="About RockTest" but_text="Close" msg="""RockTest Judge's Console V. 1.3 Copyright 2003-2005 Michael P. Conlon, Ph.D., Computer Science Department, Slippery Rock University Email: michael.conlon@sru.edu No warranty; distribution and modification is permitted under the Gnu General Public License, V2 (or later). See http://www.gnu.org/copyleft/gpl.html for details.""" about_info_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Help" info box. box_name="Help" but_text="Close" msg=""" 1) Set the team number, problem number, programming language, and data file name by clicking on the appropriate widget and selecting the desired setting. 2) Then click on the "OK" button. This will enable the buttons in the next row. 3) If the programming language requires a separate "compile" step, click on the "Compile" button. The "Compile" button will remain depressed until the compile process is complete. (Expect a delay.) Once the compile is done, the compiler output will appear in the lower pane. 4) To run the program with the selected data file, click on the "Run" button. The output will appear in the lower pane. 5) If the program does not run to completion, you can set a different runtime limit by clicking on the "Runtime Limit:" button. 6) If you want to see the source code of the program, click on the "View Source" button. The source code of the program will appear in the lower pane. 7) If there is a problem, sometimes it helps to see the team's directory. For this, click on "List Team Files". """ help_info_box=info_box_class(root, box_name, msg, but_text, LEFT) #Create "Cannot copy file" info box. box_name="Cannot copy program file" but_text="Close" msg="""Unable to copy program file. Check that the team number, problem number, and programming language options are all properly set. If so, check that team directories are group-owned by 'rocktest', with read and write permissions for the group. Also check that the file for this program is group-owned by 'rocktest' and sgid rocktest.""" ccpf_info_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No Data Directory" info box. #box_name="No Judge's Data Directory" #but_text="Close" #msg=""" #Cannot find judge's data directory. #1) Quit RockTest and create a "~/judge/data" # directory. #2) Copy the official data files into that # directory. #3) Then restart the RockTest Judge's Console. #""" #no_data_dir_box=info_box_class(root, box_name, msg, but_text, LEFT) #Create "No Data file" info box. box_name="No Data File Found" but_text="Close" msg=""" Cannot find data file. Be sure you have entered its correct name in the "Data File Name" entry. Data files should be in the "~/judge/data" directory. """ no_data_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No Source file" info box. box_name="No Source Code File" but_text="Close" msg=""" Cannot find %s program file. """ % conf.lang.get() no_source_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No ML file" info box. box_name="No Machine Code File" but_text="Close" msg=""" Cannot find machine code file. You need to compile the program first. It is also possible that the compile step failed. """ no_ml_file_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "No judge dir" info box. box_name="No Judge Directory" but_text="Close" msg="""You need a 'judge' directory within your home directory to operate the judge's console. Close this box, close the program, create a ~/judge directory, then restart the judge's console. """ no_judge_dir_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Excessive run time" info box. box_name="Runtime Limit Exceeded" but_text="Close" msg=""" The program has exceeded the allowable run time. """ excess_run_time_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Press the OK button" info box. box_name="Notice!" but_text="Close" msg=""" After changing the team, problem number, programming language, or data file name, you must press "OK" before proceeding. """ press_OK_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Supervisor's usercode missing" info box. box_name="Missing usercode!" but_text="Close" msg=""" Enter supervisor's usercode before pressing the 'Copy Files' button. """ missing_usercode_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Wrong permissions box" info box. box_name="Wrong permissions!" but_text="Close" msg=""" The contest supervisor's home directory must give execute permission to group and others. Cannot proceed.""" wrong_perms_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Trial Contest Ready box" info box. box_name="Trial Contest Ready" but_text="OK" msg=""" The data for the trial contest has been copied into your \"$HOME/judge/data\" directory. """ trial_contest_ready_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "Contest Ready box" info box. box_name="Contest Ready" but_text="OK" msg=""" The data for the contest has been copied into your \"$HOME/judge/data\" directory. """ contest_ready_box=info_box_class(root, box_name, msg, but_text, CENTER) #Create "View Parameters" info box. box_name = "Parameters" but_text="OK" msg='Number of teams: %d\n Number of problems: %d\n'%(conf.team_count, conf.prob_count) param_info_box=info_box_class(root, box_name, msg, but_text, LEFT) class start_contest_dialog_class: def __init__(self, parent, msg, name, data_kind): self.msg=StringVar() self.msg.set(msg) self.parent = parent self.name = name self.data_kind = data_kind #trial_data or data self.ok_button_text = "Copy Files" self.cancel_button_text = "Cancel" self.user=StringVar() self.user.set("") def close(self): #Close the dialog box. self.start_contest_dialog.destroy() def contest_setup(self): #print "Data kind: ", self.data_kind if len(self.user.get()) == 0: missing_usercode_box.create() return #First, check that contest supervisor's ~/judge/trial_data directory has #read and execute access for the group. status, output=commands.getstatusoutput( "ls -al ~%s/judge/%s | head -2 |tail -1 | grep -v ^......-..-" % (self.user.get(), self.data_kind)) if status != 0: wrong_perms_box.create() else: #Permissions are okay. Create directories and copy data files. #print "Clearing data directory." os.system("rm -f %s/judge/data/*.dat %s/judge/data/*.csv >\ /dev/null 2>&1" % (conf.judge_home, conf.judge_home)) #print "Copying data from %s/judge/%s" % (conf.judge_home, self.data_kind) os.system("cp %s/judge/%s/* %s/judge/data" % (conf.judge_home,\ conf.judge_home, self.data_kind)) if self.data_kind == "trial_data": trial_contest_ready_box.create() else: contest_ready_box.create() self.close() return def create(self): #Create the dialog box. self.start_contest_dialog=Toplevel(self.parent, bg=COLOR) self.start_contest_dialog.title(self.name) self.abt_msg=Message(self.start_contest_dialog, textvariable=self.msg, justify=LEFT, aspect=300, width=400, bg=COLOR).pack(side=TOP) self.entry_frame = Frame(self.start_contest_dialog, bg=COLOR) Label(self.entry_frame, text="Enter contest supervisor's usercode:", bg=COLOR).pack(side=LEFT) self.path_entry=Entry(self.entry_frame, textvariable=self.user, width=15, bg=COLOR2).pack(side=LEFT, expand=NO) self.entry_frame.pack(side=TOP) self.button_frame = Frame(self.start_contest_dialog, bg=COLOR) self.ok_button=Button(self.button_frame, text=self.ok_button_text) self.ok_button.configure(command=lambda obj=self: obj.contest_setup()) self.ok_button.pack(side=LEFT) self.cancel_button=Button(self.button_frame, text=self.cancel_button_text) self.cancel_button.configure(command=lambda obj=self: obj.close()) self.cancel_button.pack(side=RIGHT) self.button_frame.pack(side=BOTTOM) #Create "Start Trial Contest" dialog box. msg = """To start the practice contest, practice data files will be copied from the contest supervisor's $HOME/judge/trial_data directory to your $HOME/judge/data directory. """ name = "Set Up Trial Contest" kind = "trial_data" start_trial_dialog=start_contest_dialog_class(root, msg, name, kind) #Create "Start Contest" dialog box. msg = """To start the contest, data files will be copied from the contest supervisor's $HOME/judge/data directory to your $HOME/judge/data directory. """ name = "Set Up Contest" kind = "data" start_contest_dialog=start_contest_dialog_class(root, msg, name, kind) def kill_program(pfn): #print "Entering 'kill_program()'" #Kill a user program that's been running too long. #First, find the pid of the running program. #Actually, there are several processes to kill. for proc in os.popen( #For Linux: 'ps -ao pid,args | grep -i \"%s\" | grep -v grep' % (pfn)).readlines(): #For Solaris: #'ps -eo pid,args | grep -i \"%s\" | grep -v grep' % (pfn)).readlines(): pid = split(proc)[0] #Now kill it! os.system("kill -9 %s" % pid) excess_run_time_box.create() return class Execute(threading.Thread): def run(self): lang = conf.lang.get() dfn = conf.dfn.get() pfn = conf.prog_fn #Convert runlimit to milliseconds, and to an int. rl = conf.runlimit.get() if rl[-3:] == "sec": runlimit = atoi(rl[:-4]) * 1000 else: #minutes runlimit = atoi(rl[:-4]) * 60000 #Set a limit timer to stop runaway programs. id = root.after(runlimit, kill_program, pfn[:find(pfn, '.')]) if lang == "BASIC": output = commands.getoutput("nice -19 bwbasic %s/judge/%s < %s/judge/data/%s" \ % (conf.judge_home, pfn, conf.judge_home, dfn)) #Remove carriage returns from BwBASIC output. output = strip_cr(output) #Remove BWBASIC: prompt from last line of output. loc = rfind(output, '\n') output = output[:loc+1] #Remove "? " prompt from input statement's output. loc = 99999 while loc >=0: loc = find(output, '\n? ') if loc >=0: output = output[:loc] + output[loc+3:] #For JDK Java #elif lang == "Java": #output = commands.getoutput("cd %s/judge && nice -19 java %s < %s/judge/data/%s && cd %s"\ #% (conf.judge_home, pfn[:find(pfn, '.')], conf.judge_home, dfn, conf.judge_home)) #For gcj Java and other compiled languages elif conf.lang.get() in ("C", "C++", "FORTRAN", "Java", "Pascal"): output = commands.getoutput("nice -19 %s/judge/%s < %s/judge/data/%s"\ % (conf.judge_home, pfn[:find(pfn, '.')], conf.judge_home, dfn)) elif conf.lang.get() == "Python": output = commands.getoutput( "nice -19 python %s/judge/%s < %s/judge/data/%s" % \ (conf.judge_home, pfn, conf.judge_home, dfn)) else: print "Error. Undefined programming language." sys.exit(1) root.after_cancel(id) gui.textbox.insert(END, output) #These next functions are needed because .bind() cannot pass any parameters, # not even the object name, to the function that is to be bound. def delay_set_team_num(x): #print "set_team_no() called." gui.delay_set_team_no() def disable_act_buttons(x): gui.disable_action_buttons() class gui_class: def __init__(self, root): root.minsize(720,450) root.maxsize(1000, 1000) h=45 #Height of setup frame. #Build menubar and drop-down menus. self.menubar = Menu(root, relief=SUNKEN) #Create a pulldown file menu, and add it to the menu bar. self.file_menu=Menu(self.menubar, tearoff=0) self.file_menu.add_command(label="Quit", command=root.quit) self.menubar.add_cascade(label="File", menu=self.file_menu) #Create a pulldown view menu, and add it to the menu bar. self.view_menu=Menu(self.menubar, tearoff=0) self.view_menu.add_command(label="Change Team Number Control", command=self.toggle_team_no_widget) self.view_menu.add_command(label="Font size...", command=self.change_font_size) self.menubar.add_cascade(label="View", menu=self.view_menu) #Create a pulldown contest menu, and add it to the menu bar. self.contest_menu=Menu(self.menubar, tearoff=0) self.contest_menu.add_command(label="Set up practice contest...", command=start_trial_dialog.create) self.contest_menu.add_command(label="Clear contestants' directories...", command=del_warning_box.create) self.contest_menu.add_command(label="Set up real contest...", command=start_contest_dialog.create) self.menubar.add_cascade(label="Contest", menu=self.contest_menu) #Create a pulldown help menu, and add it to the menu bar. self.help_menu=Menu(self.menubar, tearoff=0) self.help_menu.add_command(label="Help...", command=help_info_box.create) self.help_menu.add_command(label="View program parameters...", command=param_info_box.create) self.help_menu.add_command(label="About RockTest...", command=about_info_box.create) self.menubar.add_cascade(label="Help", menu=self.help_menu) self.timestamp=StringVar() root.config(menu=self.menubar) self.setup_frame = Frame(root, bg=COLOR, borderwidth=3, relief=RIDGE, height=h) #, width=700) Label(self.setup_frame, text="Team:",bg=COLOR).place(anchor=W, x=0, rely=0.5) #Team-number widget options: #This widget may be a menu or an entry. Menus are easier to use, but if there #are a lot of teams and/or low screen resolution, the menu may not fit on the #screen. In that case, the entry is better. The default is to use a menu; #this choice may be toggled from the View menu on the menu bar. self.team_widget = MENU self.create_team_menu() Label(self.setup_frame, text="Problem Number:", bg=COLOR, wraplength=80)\ .place(anchor=W, x=120, rely=0.5) self.prob_no_menu = OptionMenu(self.setup_frame, conf.prob_no, *conf.prob_list) self.prob_no_menu.bind('', disable_act_buttons) self.prob_no_menu.place(anchor=W, x=175, rely=0.5) Label(self.setup_frame, text="Programming Language:", bg=COLOR, \ wraplength=100).place(anchor=W, x=243, rely=0.5) self.lang_menu = OptionMenu(self.setup_frame, conf.lang, *conf.avail_langs) self.lang_menu.bind('', disable_act_buttons) self.lang_menu.place(anchor=W, x=325, rely=0.5) Label(self.setup_frame, text="Data File Name:", wraplength=90, bg=COLOR)\ .place(anchor=W, x=450, rely=0.5) self.lb_frame = Frame(self.setup_frame, bg=COLOR) self.dfn_entry = Entry(self.lb_frame, textvariable=conf.dfn, width=12,\ bg=COLOR2).pack(side=LEFT) #bmp=Bitmap(data=) self.dfn_button = Button(self.lb_frame, text="v", width=1, height=1, \ command=lambda obj=self: obj.set_listbox()) #This doesn't work, and its functionality has been moved to self.set_listbox(). #self.dfn_button.bind('', lambda event, obj=self: \ # obj.textbox.delete(1.0, END), '+') self.dfn_listbox_exists = FALSE self.dfn_button.pack(side=LEFT) self.lb_frame.place(anchor=W, x=520, rely=0.5) Button(self.setup_frame, text="Get Program", command=self.prep_problem)\ .place(anchor=E, relx=1.0, rely=0.5) #self.setup_frame.place(x=0, y=0, height=h, relwidth=1.0) self.setup_frame.pack(side=TOP, fill=X, expand=NO) self.control_frame=Frame(root, bg=COLOR, borderwidth=3, relief=RIDGE) Label(self.control_frame, text="Timestamp:", width=11, bg=COLOR)\ .grid(row=0, column=2) self.ts=Label(self.control_frame, textvariable=self.timestamp,\ relief=SUNKEN, width=6, bg=COLOR2).grid(row=0, column=3) self.cb=Button(self.control_frame, text="Compile", width=12, state=DISABLED, command=self.compile) self.cb.grid(row=0, column=0) self.rb=Button(self.control_frame, text="Run", width=12,\ state=DISABLED, command=self.run) self.rb.grid(row=0, column=1) self.vb=Button(self.control_frame, text="View source", width=12,\ state=DISABLED, command=self.view_source) self.vb.grid(row=1, column=0) self.lb=Button(self.control_frame, text="List Team Files", width=12, command=self.list_team_dir) self.lb.grid(row=1, column=1) self.max_rt_label = Label(self.control_frame, text="Runtime Limit:",\ width=14, bg=COLOR).grid(row=1, column=2) self.max_rt_menu=OptionMenu(self.control_frame, conf.runlimit,\ "10 sec","30 sec", " 1 min"," 5 min").grid(row=1, column=3) #self.control_frame.place(x=0, y=h+2, height=1.6*h, relwidth=1.0) self.control_frame.pack(side=TOP, fill=BOTH) self.action_frame=Frame(root, bg=COLOR2, borderwidth=3) self.textbox = Text(self.action_frame, wrap=WORD, width=133, font=("Courier", 10), bg=COLOR2, relief=RIDGE) self.vscroll = Scrollbar(self.action_frame, command=self.textbox.yview) self.textbox.configure(yscrollcommand=self.vscroll.set) self.vscroll.pack(side=RIGHT, fill=Y) self.textbox.pack(side=RIGHT, fill=BOTH) #vert_size=root.winfo_height() #print vert_size #self.action_frame.place(x=0, y=2.5*h+8, relheight=0.71, relwidth=1.0) self.action_frame.pack(side=TOP, fill=BOTH) #Create ~judge and ~judge/data directories. if not ("judge" in os.listdir("%s" % conf.judge_home)): os.makedirs("%s/judge" % conf.judge_home) os.system("chgrp rocktest %s/judge" % conf.judge_home) os.chmod("%s/judge" % conf.judge_home, 488) #488_ten == 750_eight if not ("data" in os.listdir("%s/judge" % conf.judge_home)): os.makedirs("%s/judge/data" % conf.judge_home) os.system("chgrp rocktest %s/judge/data" % conf.judge_home) os.chmod("%s/judge/data" % conf.judge_home, 1512) #1512_ten == 2750_eight def create_team_menu(self): self.team_menu = OptionMenu(self.setup_frame, conf.team_no, *conf.team_list) self.team_menu.bind('', disable_act_buttons) #There seems to be no way to detect a menu selection as an event. So, #I'll bind to the initial buttonpress, and set the new team_num 3 seconds #later. #But, if we don't access "conf.team_name" but instead use "conf.team_no", # this next line will be unnecessary. #self.team_menu.bind('', delay_set_team_num) self.team_menu.place(anchor=W, x=45, rely=0.5) def create_team_entry(self): self.team_entry=Entry(self.setup_frame, textvariable=conf.team_no, width=3, justify=CENTER, bg=COLOR2) self.team_entry.bind('', disable_act_buttons) self.team_entry.place(anchor=W, x=45, rely=0.5) def delay_set_team_no(self): self.team_menu.after(3000, self.set_team_no) def set_team_no(self): conf.team_name = "team" + conf.team_no.get() #print "Team name is now ", conf.team_name def set_listbox(self): #If listbox is already open, close it and return. if self.dfn_listbox_exists: self.dfn_listbox.destroy() self.dfn_listbox_exists = FALSE return #Create listbox window. self.dfn_listbox=Listbox(root, width=13, selectmode=SINGLE, bg=COLOR2) self.dfn_listbox_exists = TRUE #Delete any existing list elements. self.dfn_listbox.delete(0, self.dfn_listbox.size()-1) conf.dfn.set("") #next, insert the data file names with the current problem's # number. for filename in os.listdir("%s/judge/data" % conf.judge_home): if find(filename, conf.prob_no.get()) > 0: self.dfn_listbox.insert(END, filename) self.dfn_listbox.place(x=523, y=33, height=20*self.dfn_listbox.size()) self.dfn_listbox.tkraise() self.dfn_listbox.bind('', lambda event, obj=self: \ obj.get_data_file(), '+') def get_data_file(self): conf.dfn.set(self.dfn_listbox.get(self.dfn_listbox.curselection()[0])) self.dfn_listbox.destroy() def change_font_size(self): self.fontsz_listbox=Listbox(root, width=3, bg=COLOR2, selectmode=SINGLE) self.fontsz_listbox_exists=TRUE for num in ("6","8","10","12","14","16","18"): self.fontsz_listbox.insert(END, num) self.fontsz_listbox.place(x=50,y=7,height=18*self.fontsz_listbox.size()) self.fontsz_listbox.tkraise() self.fontsz_listbox.bind('', lambda event, obj=self: obj.set_font_size(), '+') def set_font_size(self): point_size=self.fontsz_listbox.get(self.fontsz_listbox.curselection()[0]) self.textbox.configure(font=("Courier", atoi(point_size))) self.fontsz_listbox.destroy() def toggle_team_no_widget(self): if self.team_widget == MENU: self.team_menu.destroy() self.create_team_entry() self.team_widget = ENTRY else: #Current widget is an ENTRY. self.team_entry.destroy() self.create_team_menu() self.team_widget = MENU def enable_action_buttons(self): self.cb.configure(state=NORMAL) self.rb.configure(state=NORMAL) self.vb.configure(state=NORMAL) def disable_action_buttons(self): self.textbox.delete(1.0, END) self.cb.configure(state=DISABLED) self.rb.configure(state=DISABLED) self.vb.configure(state=DISABLED) def prep_problem(self): #"~/judge" directory must already exist. conf.team_name = "team" + conf.team_no.get() if not ("judge" in os.listdir("%s" % conf.judge_home)): no_judge_dir_box.create() return #Set parameters from control frame option buttons. conf.prog_fn = "program" + conf.prob_no.get() + \ conf.ext_map[conf.lang.get()] #Copy program file into ~/judge. #print "Copying program file: %s%s/%s\n" % \ #(conf.teams_home, conf.team_no.get(), conf.prog_fn) status, output = commands.getstatusoutput("ls -l %s%s/%s | awk '{print $8}'" % \ (conf.teams_home, conf.team_no.get(), conf.prog_fn)) if status == 0: self.timestamp.set(output) status, output = commands.getstatusoutput("cp -f %s%s/%s %s/judge" % \ (conf.teams_home, conf.team_no.get(), conf.prog_fn, conf.judge_home)) if status != 0: ccpf_info_box.create() return try: os.remove("%s/judge/%s" % (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')])) except: pass self.enable_action_buttons() #Disable "compile" button for interpreted languages. if conf.lang.get() in conf.no_compile: self.cb.configure(state=DISABLED) def control_frame_consistent(self): if conf.team_name[4:] != conf.team_no.get(): return FALSE if conf.prog_fn[7] != conf.prob_no.get(): return FALSE if not (conf.prog_fn in os.listdir("%s/judge" % conf.judge_home)): return FALSE return TRUE def compile(self): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return #Does source program file exist? if not (conf.prog_fn in os.listdir("%s/judge" % conf.judge_home)): no_source_file_box.create() return self.textbox.delete(1.0, END) if conf.lang.get() in conf.no_compile: #No compiler for these languages. output = "No compilation needed for this programming language." return self.textbox.insert(END, "Compiling. Please wait.") if conf.lang.get()=="C": #output = commands.getoutput("gcc -lm -o ~/judge/%s ~/judge/%s" %\ #(conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) output = commands.getoutput("gcc -lm -o %s/judge/%s %s/judge/%s"\ % (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="C++": #print "Compiling." #output = commands.getoutput("g++ -lm -o ~/judge/%s ~/judge/%s" %\ #(conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) output = commands.getoutput("g++ -lm -o %s/judge/%s %s/judge/%s"\ % (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="FORTRAN": #print "Compiling." #output = commands.getoutput("f77 -o ~/judge/%s ~/judge/%s" %\ #(conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) output = commands.getoutput("f77 -o %s/judge/%s %s/judge/%s" %\ (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], \ conf.judge_home, conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get()=="Java": #For JDK Java #output = commands.getoutput("javac %s/judge/%s" % (conf.judge_home, conf.prog_fn)) #Compiling gcj: #output = commands.getoutput("gcj --main=%s -o ~/judge/%s ~/judge/%s" \ #% (conf.prog_fn[:find(conf.prog_fn,'.')], \ #conf.prog_fn[:find(conf.prog_fn,'.')], \ #conf.prog_fn)) output = commands.getoutput("gcj --main=%s -o %s/judge/%s %s/judge/%s" \ % (conf.prog_fn[:find(conf.prog_fn,'.')], conf.judge_home,\ conf.prog_fn[:find(conf.prog_fn,'.')], conf.judge_home,\ conf.prog_fn)) if output == "": output = "Compile successful.\n" elif conf.lang.get() == "Pascal": #status, output = commands.getstatusoutput( #"fpc -Co -Cr -o~/judge/%s -Se10 -vew ~/judge/%s" % \ #(conf.prog_fn[:find(conf.prog_fn,'.')], conf.prog_fn)) status, output = commands.getstatusoutput( "fpc -Co -Cr -o%s/judge/%s -Se10 -vew %s/judge/%s" % \ (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')], conf.judge_home, conf.prog_fn)) ##Using P2C to preprocess. #status, output = commands.getstatusoutput( # "p2c -a %s/judge/%s 2> /dev/null" % (conf.judge_home, conf.prog_fn)) ##If the status is zero and the filename does not appear in the ##preprocessor output, there are no errors or warnings. #stat = find(output, conf.prog_fn) #if (status == 0 and stat < 0): # commands.getoutput("p2cc -o %s/judge/%s %s/judge/%s" % \ # (conf.judge_home, conf.prog_fn[:find(conf.prog_fn,'.')],\ # conf.judge_home, conf.prog_fn)) #else: # status=1 #output=commands.getoutput('echo "%s" | grep -v Translation' % output) #output=output + "\nTranslation aborted.\n" if (output == "" or status == 0): output = output + "\nCompile successful.\n" self.textbox.delete(1.0, END) self.textbox.insert(END, output) def run(self): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return lang = conf.lang.get() dfn = conf.dfn.get() pfn = conf.prog_fn if lang in conf.no_compile: #Does source program file exist? if not (pfn in os.listdir("%s/judge" % conf.judge_home)): no_source_file_box.create() return else: #Does machine language program file exist? #Code for JDK Java: #if conf.lang.get() == "Java": #if not ((pfn[:find(pfn,".")] + ".class") in \ #os.listdir("%s/judge" % conf.judge_home)): #no_ml_file_box.create() #return #elif #Remove "if" from next line if uncommenting this line. if not (pfn[:find(pfn,'.')] in os.listdir("%s/judge" % conf.judge_home)): no_ml_file_box.create() return #Does data file exist? if not (dfn in os.listdir("%s/judge/data" % conf.judge_home)): no_data_file_box.create() return #Clear previous output. self.textbox.delete(1.0, END) #Execute the program as a separate thread. Execute().start() def list_team_dir(self): #conf.team_name may not be up-to-date. status, dir = commands.getstatusoutput( "ls -l %steam%s" % (conf.teams_home[:-4], conf.team_no.get())) self.textbox.delete(1.0, END) self.textbox.insert(END, dir) def view_source(self): if not self.control_frame_consistent(): self.disable_action_buttons() press_OK_box.create() return self.textbox.delete(1.0, END) source=commands.getoutput("cat %s/judge/%s" % (conf.judge_home, conf.prog_fn)) self.textbox.insert(END, source) conf=conf_class() gui=gui_class(root) root.mainloop()