Sunteți pe pagina 1din 16

MOTIVATION:

Every week, the lab assistants have to mark hundreds of lab tasks which consume a lot of
effort and time of the assistants. This makes their job tiresome and cumbersome.
The second motivation to pursue this idea was that the students were in deep concern that
despite of them putting full effort to ace the lab tasks, their tasks, according to them, were
evaluated on their performance in the quizzes.

SOLUTION:

We started to brainstorm along the lines of improving marking methods and standards. We
made an effort using our OOP skills to minimize the loss of time, energy and potential. We
came up with an idea of a program which does the work of Lab Assistants.
We automated the marking of lab tasks using C# whereby our program extracts the
codes in lab tasks individually (from a word file in a folder), analyse each code of an
individual lab task, figures out compile-time errors, and mentions the line of the code
where the error exists. The program then marks the lab assignment out of max. marks
taken from the user, and stores the marks in an excel spreadsheet of all the individuals in
the class.

REQUIREMENTS:

1) The lab assignment must be stored in a Word Document (.docx).


2) The file name should be the student's name.
3) All the document files should be placed in a folder.

COD-AL ANALYSIS:

Libraries Included

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;//To use Directory, getfiles
using System.Diagnostics;//To use Process.Start
using System.Threading;//To use Thread
//To write to excel
using NPOI.HSSF.UserModel;
using NPOI.HPSF;
using NPOI.POIFS.FileSystem;
using NPOI.SS.UserModel;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows;
//To run compiler
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
using Microsoft.VisualC;
Main Body

public void button1_Click(object sender, EventArgs e)


{

Form2 frm = new Form2();


frm.Show();
start.Enabled = true;
}
This button opens form2 and enables the start button after the form has been filled.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace ExternFormsApplication
{
public partial class Form2 : Form
{
string[] filePaths;
string[,] grading;
string clas;
float total;
float deduction;
bool FormFilled;
public Form2()
{
InitializeComponent();
FormFilled = false;
}

private void button1_Click(object sender, EventArgs e)


{
FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();
folderBrowserDialog1.Description = "Choose a folder where the tasks are placed.";
DialogResult result = folderBrowserDialog1.ShowDialog();//Returns a path to the folder
if (result == DialogResult.OK)
{
filePaths = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.docx");
MessageBox.Show("Files found: " + filePaths.Length.ToString(), "Message");
grading = new string[filePaths.Length, 3];
FormFilled = true;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (FormFilled==true)
{
clas = textBox1.Text;
total = float.Parse(textBox2.Text);
deduction = float.Parse(textBox3.Text);
if (total > 0 && deduction > 0 )
{
Form1.clas = clas;
Form1.Total = total;
Form1.Deduction = deduction;
Form1.filePaths = filePaths;
Form1.grading = grading;
Close();
}
else

MessageBox.Show("No field should be empty or negative");


}
else
MessageBox.Show("Either You didn't Select a folder "+Environment.NewLine+"
OR"+Environment.NewLine+
"Your Selected Folder was empty");
}}}
Form2 has some text boxes asking for user input. In case of any invalid or no input, the form
displays a warning message. This form passes the inputs to the main form.
private void button2_Click(object sender, EventArgs e)
{ if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.DoWork += (obj, ex) => codeExtracter();
backgroundWorker1.RunWorkerAsync();
button2.Enabled = true;
} }
This is the start Button. It calls the codeExtractor function in the background so that the
interface is operative while the processing is being carried out.
private void codeExtracter()
{
for (int j = 0; j <= filePaths.Length; j++)
if (!backgroundWorker1.CancellationPending)
{
long fileSize=0;
float Marks = Total;

int percent = j * 100 / filePaths.Length;


backgroundWorker1.ReportProgress(percent, j);
//To check for file size to identify if it is empty or not
FileInfo f = new FileInfo(filePaths[j]);
fileSize = f.Length;
string line = "";
if (fileSize > 0)
{
var text = new TikaOnDotNet.TextExtractor().Extract(filePaths[j]).Text;
//Console.WriteLine(text);
StreamWriter wf = new StreamWriter(@"textFile.txt");//To save into a .txt file
wf.WriteLine(text);
wf.Close();
string code = "";
StreamReader rf = new StreamReader(@"textFile.txt");
int check = 0;//To see if atleast some programs are read
bool flag = false;
int countright = 0, countleft = 0;
int taskNo = 0;
while ((line = rf.ReadLine()) != null)
{
if (line.Contains("using System") && flag == false)
{
flag = true;
code = "";
countright = 0; countleft = 0;
}
if (flag == true)
{

code += line;
code += Environment.NewLine;
if (line.Contains("{"))
countright += count(line, '{');
if (line.Contains("}"))
countleft += count(line, '}');
if (countleft == countright && countleft != 0)
{
MessageBox.Show(code);
flag = false;
taskNo++;
check++;
grading[j, 2] += "Task # " + taskNo.ToString() + Environment.NewLine;
Grader(filePaths[j], code, j, ref Marks);
}
}
}
rf.Close();
if (check == 0)
{
grading[j, 0] = Path.GetFileNameWithoutExtension(filePaths[j]);
grading[j, 1] = "0";
grading[j, 2] = "No Program Found";
}
}
else
{
grading[j, 0] = Path.GetFileNameWithoutExtension(filePaths[j]);
grading[j, 1] = "0";
grading[j, 2] = "File Empty";
}
}
}

static int count(string s, char c)


{
int i = 0, counter = 0;
for (i = 0; i < s.Length; i++)
{
if (s[i] == c)
counter++;
}
return counter;
}
The codeExtractor uses the file paths stored in two dimensional string array to access the
word files. The program uses a library TikaOnDotNet which converts .docx files to .txt files.
Before passing file to TikaOnDotNet, program checks if size of file is not zero(i.e. file is
empty) because this library seems to malfunction while dealing with zero kb files. After
conversion to text file, program searches it line by line to mark the start of code while
ignoring everything else. The algorithm used to extract the code is that when the program
finds "using System" in a line, it turns on a switch and starts copying everything into a
string. This process continues until the number of "{" become equal to number of "}". Then
the string is passed to grader function. The characters (i.e. { }) are counted using a count
function.
private void Grader(string path, string code, int SRnum, ref float Marks)
{
string name = Path.GetFileNameWithoutExtension(path);
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "Out.exe";
textBox1.Text = "";
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.ReferencedAssemblies.Add("System.linq.dll");

parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.ReferencedAssemblies.Add("mscorlib.dll");
parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
parameters.WarningLevel = 3;
parameters.CompilerOptions = "/target:library /optimize";
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = false;
parameters.OutputAssembly = Output;
CompilerResults results = icc.CompileAssemblyFromSource(parameters, code);
string err = "";
if (results.Errors.Count > 0)
{
if (Marks > 0)
Marks = Marks - results.Errors.Count*Deduction;
textBox1.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
textBox1.Text = textBox1.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine;
err = err + "Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine;
}
}
else

{
//Successful Compile
textBox1.ForeColor = Color.Blue;
textBox1.Text = "Success!";
}
grading[SRnum, 0] = name;
grading[SRnum, 1] = Marks.ToString();
grading[SRnum, 2] += err;
if (!grading[SRnum, 2].Contains("Line number"))
grading[SRnum, 2] = "";
}
This function uses a CSharpCodeProvider class to create a compiler, set its parameters like
referencing libraries, compile code and store result of compilation. The result is displayed in
the textbox. In case of an error, some marks are deducted as specified by the user. The
marks are converted to string and stored in a two dimensional array, against the name of the
student, which should be the word file's name submitted by the student. The task number
along with the type and line of error is stored in the third column of the array.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progress.Value = e.ProgressPercentage;
lblProgress.Text = string.Format("Processing .... {0}%", e.ProgressPercentage);
lblItems.Text = string.Format("Items Checked .... {0}/{1}", e.UserState, filePaths.Length);
if (int.Parse(e.UserState.ToString()) != filePaths.Length)
label1.Text = string.Format("Checking tasks of "+
Path.GetFileNameWithoutExtension(filePaths[int.Parse(e.UserState.ToString())]));
progress.Update();
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{

MessageBox.Show("Process Completed", "Message");


label1.Text = string.Format(" Finished");
}
This function backgroundWorker1_ProgressChanged updates the progress bar and labels
on the form, to provide real time feedback to the assistant on the marking process. On
completion, the form displays a message.

private void button2_Click_1(object sender, EventArgs e)


{
saveFileDialog1.ShowDialog();
string path = saveFileDialog1.FileName;
InitializeWorkbook();
ISheet sheet1 = hssfworkbook.CreateSheet(clas);
IRow row0 = sheet1.CreateRow(0);
row0.CreateCell(0).SetCellValue("Names");
row0.CreateCell(1).SetCellValue("Marks");
row0.CreateCell(2).SetCellValue("Mistakes");
for (int i = 0; i < filePaths.Length; i++)
{
IRow row = sheet1.CreateRow(i + 1);
for (int j = 0; j < 3; j++)
{
if (j == 0)
row.CreateCell(j).SetCellValue(grading[i, j]);
if (j == 1)
row.CreateCell(j).SetCellValue(Convert.ToDouble(grading[i, j]));
if (j == 2)
{
row.CreateCell(j).CellStyle.WrapText = true;
row.CreateCell(j).SetCellValue(grading[i,j]);

}
}
}
sheet1.AutoSizeColumn(0);
sheet1.AutoSizeColumn(1);
sheet1.AutoSizeColumn(2);
WriteToFile(path);
Saved = true;
}
static HSSFWorkbook hssfworkbook;
static void WriteToFile(string path)
{
//Write the stream data of workbook to the root directory
FileStream file = new FileStream(path, FileMode.Create);
hssfworkbook.Write(file);
file.Close();
}
static void InitializeWorkbook()
{
hssfworkbook = new HSSFWorkbook();
////create a entry of DocumentSummaryInformation
DocumentSummaryInformation dsi =
PropertySetFactory.CreateDocumentSummaryInformation();
dsi.Company = "NPOI Team";
hssfworkbook.DocumentSummaryInformation = dsi;
////create a entry of SummaryInformation
SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
si.Subject = "NPOI SDK Example";
hssfworkbook.SummaryInformation = si;
}

This function deploys the NPOI Library to create an excel spreadsheet with the name
specified by the user. The two dimensional array grading[i,j] fits in the condition of the
spreadsheet, with rows and columns as the array arguments. The function assigns the name
to first column, marks to the second and errors along with the task and line number in
which the error has occurred.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (Saved == false)
{
DialogResult dialog = MessageBox.Show("Do You want to exit without saving?", "Exit",
MessageBoxButtons.YesNo);
if (dialog == DialogResult.Yes)
{
Application.ExitThread();
}
else if (dialog == DialogResult.No)
e.Cancel = true;
}
}
If the user tries to close the form without saving, he/she is asked whether to exit with or
without saving. All this functionality is provided in this function.
Interface

Result

S-ar putea să vă placă și