Prototype using Visual Basic for Applications (VBA) and C
The prototype application is available as a
Microsoft Excel file.
VBA Module : Create metadata table
' Module: CreateMetadata
' DateTime: 21/08/2007 16:01:13
' Author: Dragana Nikolic
' Description: Creates metadata
'-----------------------------------------------------------------
Option Explicit
'*****************************************************************
Public Const dataSheet = "DATASET" ' name of dataset sheet
Public Const maxUsers = 100 ' maximum number of users in dataset
Public Const maxAttributes = 9 ' maximum number of attributes in dataset
Public Const maxSets = maxAttributes * (maxAttributes - 1) * (maxAttributes - 2) / 6
Public Const maxNoOfLogin = 3 ' maximum number of login attempts at one time
Public Const maxIDLength = 6 ' maximum length of IDs in login procedure
Public Const maxQuestions = 50 ' total number of questions
Public Const maxAnswerLength = 50 ' maximum length of answer in login procedure
' different answer types
Public Const YesNo = 0
Public Const MatchStrings = 1
Public Const MatchNumbers = 2
' different attribute types
Public Const Text = 0
Public Const equalNumbers = 10
Public Const smallNumbers = 11
Public Const largeNumbers = 12
'*****************************************************************
Public Type Attributes
No As Integer
Name As String
DataType As Integer
QuartileValue(0 To 4) As Double
End Type
Public allAtt(1 To maxAttributes) As Attributes
Public Type Sets
index As Integer
att(1 To 3) As Attributes
End Type
Public set3A(1 To maxSets) As Sets
Public Type Users
ID As String
attValue(1 To maxAttributes) As Variant
lastSet As Sets
nextSet As Sets
p(1 To maxSets) As Integer
End Type
Public user(1 To maxUsers) As Users
Public Type Questions
No As Integer
Group As Integer
Form() As Variant
CorrectAnswer As Variant
AnswerType As Integer ' 0 for yes/no, 1 for matched strings, 2 for matched numbers
AnswerLength As Integer
End Type
Public question(1 To maxQuestions) As Questions
Public set3Q(1 To 3) As Questions
Public lastCol As Long
Public lastRow As Long
Public n_sets As Integer ' number of sets of triple questions
Public askedQno As Integer ' number of currently asked question
Public answer(1 To 3) As String
Sub CreateMetadata()
Call CreateAttributeMetadata
Call PrintAttributeMetadata("Attribute")
ActiveWorkbook.Sheets(dataSheet).Activate
' MsgBox "Attribute metadata are successfully created! Wait for the rest of metadata to be created..."
Call CalculateOccurrence3
Call PrintOccurrence3("Occurrence3")
ActiveWorkbook.Sheets(dataSheet).Activate
MsgBox "Metadata are successfully created!"
End Sub
'*****************************************************************
' Create attribute metadata for whole set of attributes
'*****************************************************************
Sub CreateAttributeMetadata()
Dim i As Integer
lastCol = Sheets(dataSheet).Range("B1").End(xlToRight).Column
lastRow = Sheets(dataSheet).Range("A3").End(xlDown).Row
For i = 1 To lastCol - 1
allAtt(i).No = i
allAtt(i).Name = LCase(Sheets(dataSheet).Cells(1, i + 1).Value)
If (IsAttributeNumeric(allAtt(i).No) = True) Then
Call CalculateQuartiles(allAtt(i).No)
allAtt(i).DataType = CheckDataRange(allAtt(i).No, 99999)
End If
Next i
End Sub
'*****************************************************************
' Check whether the type of attribute value is numeric (flag=1) or not (flag=0)
'*****************************************************************
Function IsAttributeNumeric(attributeNo As Integer)
Dim row1 As Long
Dim flag As Boolean
flag = True
For row1 = 3 To lastRow
If IsNumeric(Sheets(dataSheet).Cells(row1, attributeNo + 1).Value) = False Then
flag = False
End If
Next row1
IsAttributeNumeric = flag
End Function
'*****************************************************************
' Calculate 5 quartiles for the numeric attribute
'*****************************************************************
Private Sub CalculateQuartiles(attributeNo As Integer)
Dim dataRange As Range
Dim j As Integer
Dim str As String
str = Chr(65 + attributeNo) & "3:" & Chr(65 + attributeNo) & lastRow
Set dataRange = Sheets(dataSheet).Range(str)
For j = 0 To 4
allAtt(attributeNo).QuartileValue(j) _
= Application.WorksheetFunction.quartile(dataRange, j)
Next j
End Sub
'*****************************************************************
' Check the range of the numeric attribute
'*****************************************************************
Private Function CheckDataRange(attributeNo As Integer, limit As Long)
If allAtt(attributeNo).QuartileValue(0) = allAtt(attributeNo).QuartileValue(4) Then
CheckDataRange = equalNumbers
ElseIf allAtt(attributeNo).QuartileValue(4) <= limit Then
CheckDataRange = smallNumbers
Else
CheckDataRange = largeNumbers
End If
End Function
'*****************************************************************
' Print metadata obtained for each attribute
'*****************************************************************
Private Sub PrintAttributeMetadata(metadataSheet)
Dim row1 As Long
Dim col1 As Integer
Application.ScreenUpdating = False
Call CreateNewWorksheet(metadataSheet)
Sheets(metadataSheet).Cells(1, 1).Value = "attribute no"
Sheets(metadataSheet).Cells(2, 1).Value = "attribute name"
Sheets(metadataSheet).Cells(3, 1).Value = "data type"
For row1 = 4 To 8
Sheets(metadataSheet).Cells(row1, 1).Value = "quartile " & row1 - 4
Sheets(metadataSheet).Cells(row1, 1).Font.Bold = True
Next row1
For col1 = 2 To lastCol
Sheets(metadataSheet).Cells(1, col1).Value = allAtt(col1 - 1).No
Sheets(metadataSheet).Cells(2, col1).Value = allAtt(col1 - 1).Name
Sheets(metadataSheet).Cells(2, col1).Font.Bold = True
Sheets(metadataSheet).Cells(3, col1).Value = allAtt(col1 - 1).DataType
For row1 = 4 To 8
Sheets(metadataSheet).Cells(row1, col1).Value _
= allAtt(col1 - 1).QuartileValue(row1 - 4)
Next row1
Next col1
Application.ScreenUpdating = True
End Sub
'*****************************************************************
' Calculate the number of occurrences of the same sets of three attributes
' (i.e. triples) in dataset
'*****************************************************************
Private Sub CalculateOccurrence3()
Dim row1 As Long
Dim row2 As Long
Dim col1 As Integer
Dim col2 As Integer
Dim col3 As Integer
Dim occNo As Integer
Dim temp1 As String
Dim temp2 As String
Dim A As String
Dim B As String
Dim C As String
n_sets = 1
For col1 = 2 To lastCol
For col2 = 2 To lastCol
For col3 = 2 To lastCol
If (col1 < col2 And col2 < col3) Then
set3A(n_sets).index = n_sets
set3A(n_sets).att(1) = allAtt(col1 - 1)
set3A(n_sets).att(2) = allAtt(col2 - 1)
set3A(n_sets).att(3) = allAtt(col3 - 1)
' Checks for same attribute triples and count them
For row1 = 3 To lastRow
occNo = 0
For row2 = 3 To lastRow
temp1 = Sheets(dataSheet).Cells(row1, col1).Value
temp2 = Sheets(dataSheet).Cells(row2, col1).Value
A = StrComp(CStr(temp1), CStr(temp2), vbTextCompare)
temp1 = Sheets(dataSheet).Cells(row1, col2).Value
temp2 = Sheets(dataSheet).Cells(row2, col2).Value
B = StrComp(CStr(temp1), CStr(temp2), vbTextCompare)
temp1 = Sheets(dataSheet).Cells(row1, col3).Value
temp2 = Sheets(dataSheet).Cells(row2, col3).Value
C = StrComp(CStr(temp1), CStr(temp2), vbTextCompare)
If (A = 0 And B = 0 And C = 0) Then
occNo = occNo + 1
End If
Next row2
user(row1 - 2).p(n_sets) = (lastRow - 2) - occNo
Next row1
' Counts total number of sets/columns
n_sets = n_sets + 1
End If
Next col3
Next col2
Next col1
' n_sets = n_sets - 1
For row1 = 3 To lastRow
user(row1 - 2).ID = Sheets(dataSheet).Cells(row1, 1).Value
user(row1 - 2).lastSet = set3A(GenerateRandomNo(1, maxSets))
For col1 = 2 To lastCol
user(row1 - 2).attValue(col1 - 1) = Sheets(dataSheet).Cells(row1, col1).Value
Next col1
Next row1
End Sub
'*****************************************************************
' Print the number of occurrences of the triples in dataset
'*****************************************************************
Private Sub PrintOccurrence3(metadataSheet)
Dim row1 As Long
Dim col1 As Integer
Application.ScreenUpdating = False
Call CreateNewWorksheet(metadataSheet)
Sheets(metadataSheet).Cells(1, 2).Value = "Set no."
Sheets(metadataSheet).Cells(1, 2).Interior.ColorIndex = 6
Sheets(metadataSheet).Cells(6, 1).Value = "Student ID"
Sheets(metadataSheet).Cells(6, 1).Interior.ColorIndex = 8
Sheets(metadataSheet).Cells(6, 2).Value = "Last set no."
Sheets(metadataSheet).Cells(6, 2).Interior.ColorIndex = 8
For col1 = 1 To maxSets
Sheets(metadataSheet).Cells(1, col1 + 2).Value = set3A(col1).index
Sheets(metadataSheet).Cells(1, col1 + 2).Font.Bold = True
Next col1
For row1 = 1 To 3
Sheets(metadataSheet).Cells(row1 + 1, 2).Value = "Attribute " & row1
Sheets(metadataSheet).Cells(row1 + 1, 2).Interior.ColorIndex = 6
For col1 = 1 To maxSets
Sheets(metadataSheet).Cells(row1 + 1, col1 + 2).Value = set3A(col1).att(row1).Name
Next col1
Next row1
For row1 = 3 To lastRow
Sheets(metadataSheet).Cells(row1 + 4, 1).Value = user(row1 - 2).ID
Sheets(metadataSheet).Cells(row1 + 4, 2).Value = user(row1 - 2).lastSet.index
Sheets(metadataSheet).Cells(row1 + 4, 2).Font.Bold = True
For col1 = 1 To maxSets
Sheets(metadataSheet).Cells(row1 + 4, col1 + 2).Value = (lastRow - 2) - user(row1 - 2).p(col1)
Next col1
Next row1
Application.ScreenUpdating = True
End Sub
Back to
top of page.
VBA Module : Generate questions
' Module: GenerateQuestions
' DateTime: 24/08/2007 12:14:43
' Author: Dragana Nikolic
' Description: Creates metadata
'-----------------------------------------------------------------
Option Explicit
Sub GenerateQuestions()
End Sub
'*****************************************************************
' Generate question for given attribute
'*****************************************************************
Public Function GenerateQuestion(qNum As Integer, att As Attributes)
Dim x As Integer
' temporary solution to choose question acording to the attribute data type
Select Case att.DataType
Case Text:
x = GenerateRandomNo(1, 2)
Case equalNumbers:
x = GenerateRandomNo(10, 11)
Case smallNumbers:
x = GenerateRandomNo(10, 17)
Case largeNumbers:
x = 20 ' GenerateRandomNo(20, 22)
End Select
' set the random question and save it in the set of three questions
' that going to be asked
Call SetQuestion(att, x)
set3Q(qNum) = question(x)
' create question sentence
GenerateQuestion = Join(question(x).Form, "")
End Function
'*****************************************************************
' Generate random integer number from the interval [lowerB, higherB]
'*****************************************************************
Public Function GenerateRandomNo(lowerB As Integer, upperB As Integer)
Randomize
GenerateRandomNo = Int((upperB - lowerB + 1) * Rnd + lowerB)
End Function
'*****************************************************************
' Generate possible questions for given attribute type
'*****************************************************************
Public Sub SetQuestion(att As Attributes, x As Integer)
Dim qLow As Integer
Dim qHigh As Integer
Dim qMid As Integer
Dim nDigits As Integer
Select Case att.DataType
Case Text:
Case equalNumbers, smallNumbers:
If (att.QuartileValue(0) <> att.QuartileValue(4)) Then
Do
qLow = GenerateRandomNo(0, 3)
qHigh = GenerateRandomNo(1, 4)
Loop Until (att.QuartileValue(qHigh) > att.QuartileValue(qLow))
qMid = GenerateRandomNo(1, 3)
End If
Case largeNumbers:
nDigits = GenerateRandomNo(4, 6)
End Select
Select Case x
' list of questions for textual attribute
Case 1:
With question(1)
.No = 1
.Group = att.DataType
.Form = Array("What is your ", att.Name, "?")
.CorrectAnswer = user(userIndex).attValue(att.No)
.AnswerType = MatchStrings
.AnswerLength = maxAnswerLength
End With
Case 2:
With question(2)
.No = 2
.Group = att.DataType
.Form = Array("Please enter your ", att.Name, ".")
.CorrectAnswer = user(userIndex).attValue(att.No)
.AnswerType = MatchStrings
.AnswerLength = maxAnswerLength
End With
' list of questions for numerical attribute
Case 10:
With question(10)
.No = 10
.Group = att.DataType
.Form = Array("What is the value of your ", att.Name, "?")
.CorrectAnswer = user(userIndex).attValue(att.No)
.AnswerType = MatchNumbers
.AnswerLength = maxAnswerLength
End With
Case 11:
With question(11)
.No = 11
.Group = att.DataType
.Form = Array("Please enter the value of your ", att.Name, ".")
.CorrectAnswer = user(userIndex).attValue(att.No)
.AnswerType = MatchNumbers
.AnswerLength = maxAnswerLength
End With
Case 12:
With question(12)
.No = 12
.Group = att.DataType
.Form = Array("Is your ", att.Name, " greater than ", att.QuartileValue(qMid), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) > att.QuartileValue(qMid)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 13:
With question(13)
.No = 13
.Group = att.DataType
.Form = Array("Is your ", att.Name, " greater than or equal to ", att.QuartileValue(qMid), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) >= att.QuartileValue(qMid)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 14:
With question(14)
.No = 14
.Group = att.DataType
.Form = Array("Is your ", att.Name, " less than ", att.QuartileValue(qMid), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) < att.QuartileValue(qMid)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 15:
With question(15)
.No = 15
.Group = att.DataType
.Form = Array("Is your ", att.Name, " less than or equal to ", att.QuartileValue(qMid), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) <= att.QuartileValue(qMid)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 16:
With question(16)
.No = 16
.Group = att.DataType
.Form = Array("Is your ", att.Name, _
" greater than or equal to ", att.QuartileValue(qLow), _
" and less than ", att.QuartileValue(qHigh), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) >= att.QuartileValue(qLow)) _
And (Val(user(userIndex).attValue(att.No)) < att.QuartileValue(qHigh)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 17:
With question(17)
.No = 17
.Group = att.DataType
.Form = Array("Is your ", att.Name, _
" greater than ", att.QuartileValue(qLow), _
" and less than or equal to ", att.QuartileValue(qHigh), "?")
.CorrectAnswer = IIf((Val(user(userIndex).attValue(att.No)) > att.QuartileValue(qLow)) _
And (Val(user(userIndex).attValue(att.No)) <= att.QuartileValue(qHigh)), "Yes", "No")
.AnswerType = YesNo
.AnswerLength = maxAnswerLength
End With
Case 20:
With question(20)
.No = 20
.Group = att.DataType
.Form = Array("Please enter the last ", nDigits, _
" digits of your ", att.Name, ".")
.CorrectAnswer = Right(CStr(user(userIndex).attValue(att.No)), nDigits)
.AnswerType = MatchStrings
.AnswerLength = nDigits
End With
End Select
End Sub
Back to
top of page.
VBA Module : Login procedure
' Module: LoginProcedure
' DateTime: 27/03/2007 13:46:02
' Author: Dragana Nikolic
' Description: Login step 1 - username (or ID) check
'-----------------------------------------------------------------
Public userIndex As Long
Public helpNote As String
Sub LoginProcedure()
Call DisplayLoginScreen1
End Sub
'*****************************************************************
' Display LoginScreen1 form
'*****************************************************************
Private Sub DisplayLoginScreen1()
LoginScreen1.Username.MaxLength = maxIDLength
LoginScreen1.Show
End Sub
'*****************************************************************
' Check does entered ID match any of the existing IDs in dataset
'*****************************************************************
Public Sub CheckUserID()
Dim checkString As Integer
Dim i As Integer
Static NoOfTries As Integer ' number of tries in login procedure
If LoginScreen1.Username.TextLength = maxIDLength Then
i = 1
Do
checkString = StrComp(CStr(user(i).ID), LoginScreen1.Username.Value, vbTextCompare)
If checkString = 0 Then
userIndex = i
' continue here with Metropolis algorithm
'*********************************************
Call Metropolis
' MsgBox "User's last set is " & user(userIndex).lastSet.index & _
' ". User's next set is " & user(userIndex).nextSet.index & "."
'*********************************************
Unload LoginScreen1
Call InitialiseLoginScreen2
Else
i = i + 1
End If
Loop Until (i = lastRow - 1 Or checkString = 0)
' limit the number of login attempts at one time
If i = lastRow - 1 Then
If NoOfTries < maxNoOfLogin - 1 Then
MsgBox "Wrong username. Please, try again!"
NoOfTries = NoOfTries + 1
Else
MsgBox "No more tries, sorry!"
NoOfTries = 0
Unload LoginScreen1
End If
End If
Else
MsgBox "You need to enter " & maxIDLength & " characters for ID!"
End If
End Sub
'*****************************************************************
' Generate random number of question's set according to given distribution
'*****************************************************************
Private Sub Metropolis()
Dim set0 As Integer
Dim setT As Integer
Dim ratio As Double
Dim x As Double
Dim accepted As Boolean
set0 = user(userIndex).lastSet.index
accepted = False
While (accepted = False)
setT = GenerateRandomNo(1, maxSets)
' check whether random number is accepted or not
ratio = user(userIndex).p(setT) / user(userIndex).p(set0)
If (ratio >= 1) Then
accepted = True
set0 = setT
Else
x = Rnd
If (ratio > x) Then
accepted = True
set0 = setT
End If
End If
Wend
user(userIndex).nextSet = set3A(setT)
End Sub
'*****************************************************************
' Initialise LoginScreen2 form
'*****************************************************************
Private Sub InitialiseLoginScreen2()
Call RandomiseQuestionSet
askedQno = 0
Call DisplayLoginScreen2
End Sub
'*****************************************************************
' Display LoginScreen2 form
'*****************************************************************
Public Sub DisplayLoginScreen2()
askedQno = askedQno + 1
If askedQno <= 3 Then
LoginScreen2.Caption = "Login Screen (step " & askedQno + 1 & " of 4)"
LoginScreen2.userAnswer.Value = ""
LoginScreen2.txtQuestion.Caption = askedQno & ". " & GenerateQuestion(askedQno, user(userIndex).nextSet.att(askedQno))
LoginScreen2.userAnswer.MaxLength = set3Q(askedQno).AnswerLength
LoginScreen2.Show
Else
Call CheckAnswers
End If
End Sub
'*****************************************************************
' Randomise the order of the questions in the chosen question set
'*****************************************************************
Private Sub RandomiseQuestionSet()
Dim i As Integer
Dim j As Integer
Dim tmp As Attributes
' randomise the array
For i = 1 To 2
' pick a random entry from i to 3
j = GenerateRandomNo(i, 3)
' swap the attributes in the set
tmp = user(userIndex).nextSet.att(i)
user(userIndex).nextSet.att(i) = user(userIndex).nextSet.att(j)
user(userIndex).nextSet.att(j) = tmp
Next i
End Sub
'*****************************************************************
' Check the answers obtained for the chosen set of questions
'*****************************************************************
Public Sub CheckAnswers()
Dim validAnswer(1 To 3) As Boolean
Dim i As Integer
For i = 1 To 3
validAnswer(i) = IsAnswerCorrect(i, answer(i))
Next i
If (validAnswer(1) And validAnswer(2) And validAnswer(3)) Then
MsgBox "Congratulation! You are successfully log in."
user(userIndex).lastSet = user(userIndex).nextSet
Unload LoginScreen2
Else
MsgBox "Sorry, you've failed to log in."
End If
End Sub
'*****************************************************************
' Check is the answer correct depending on the question type
'*****************************************************************
Public Function IsAnswerCorrect(qNo As Integer, answer As String)
Select Case set3Q(qNo).AnswerType
Case YesNo:
IsAnswerCorrect = (StrComp(ReturnCorrectAnswerFormat(answer), set3Q(qNo).CorrectAnswer, vbTextCompare) = 0)
Case MatchStrings:
IsAnswerCorrect = (StrComp(LCase(answer), LCase(CStr(set3Q(qNo).CorrectAnswer)), vbTextCompare) = 0)
Case MatchNumbers:
IsAnswerCorrect = (Val(answer) = Val(set3Q(qNo).CorrectAnswer))
End Select
End Function
'*****************************************************************
' Return default value of the answer if the given answer is from the specific array
'*****************************************************************
Public Function ReturnCorrectAnswerFormat(answer As String)
Dim i As Integer
Dim YesAnswers As Variant
Dim NoAnswers As Variant
YesAnswers = Array("Yes", "y", "True", "1", "Yes, it is")
NoAnswers = Array("No", "n", "False", "0", "No, it is not", "No, it isn't", "No, it's not")
' for any answer from YesAnswers array return "Yes"
For i = 0 To UBound(YesAnswers)
If (StrComp(LCase(CStr(answer)), LCase(CStr(YesAnswers(i))), vbTextCompare) = 0) Then
ReturnCorrectAnswerFormat = "Yes"
End If
Next i
' for any answer from NoAnswers array return "No"
For i = 0 To UBound(NoAnswers)
If (StrComp(LCase(CStr(answer)), LCase(CStr(NoAnswers(i))), vbTextCompare) = 0) Then
ReturnCorrectAnswerFormat = "No"
End If
Next i
End Function
Back to
top of page.
VBA Module : Delete all sheets
' Module: DeleteAllSheets
' DateTime: 27/03/2007 13:56:33
' Author: Dragana Nikolic
' Description: Delete all worksheets containing metadata
'-----------------------------------------------------------------
'*****************************************************************
Public Sub DeleteAllSheets()
Call DeleteSheets
End Sub
'*****************************************************************
' Delete all worksheets in the current workbook except the active one
'*****************************************************************
Public Sub DeleteSheets()
For Each sheetNo In Sheets
If ActiveSheet.index <> sheetNo.index Then
Application.DisplayAlerts = False
sheetNo.Delete
Application.DisplayAlerts = True
End If
Next sheetNo
End Sub
'*****************************************************************
' Add another worksheet named as sheetName in the current workbook
'*****************************************************************
Public Sub CreateNewWorksheet(sheetName)
Dim sheetNo As Variant
Dim response As String
For Each sheetNo In Sheets
If sheetNo.Name = sheetName Then
Call DeleteSheets
' response = MsgBox("Metadata already exist. Do you want to delete them and perform this action again?", vbYesNo)
' If response = vbYes Then
' ' user choose Yes
' Call DeleteSheets
' Else
' End
' ' GoTo ReturnFromSubroutine
' End If
End If
Next sheetNo
Sheets.Add.Name = sheetName
' ReturnFromSubroutine:
End Sub
Back to
top of page.
VBA Forms : Login screen 1
' Form: LoginScreen1
' DateTime: 25/03/2007 09:53:22
' Author: Dragana Nikolic
' Description: Login step 1 - check user's ID
'-----------------------------------------------------------------
Private Sub LoginButton_Click()
Call CheckUserID
End Sub
Back to
top of page.
VBA Forms : Login screen 2
' Form: LoginScreen2
' DateTime: 26/03/2007 11:32:47
' Author: Dragana Nikolic
' Description: Login step 2 - ask set of three questions and check answers
'-----------------------------------------------------------------
Private Sub OKButton_Click()
txtNoteLabel.Caption = ""
If (Len(LoginScreen2.userAnswer.Value) = 0) Then
txtNoteLabel.Caption = "You need to enter the answer in the text field."
txtNoteLabel.ForeColor = &HFF&
Else
answer(askedQno) = userAnswer.Value
Unload LoginScreen2
Call DisplayLoginScreen2
End If
End Sub
Private Sub CancelButton_Click()
txtNoteLabel.Caption = ""
Unload LoginScreen2
End Sub
'Private Sub OKButton_Enter()
' txtNoteLabel.Caption = "Submit your answer"
' txtNoteLabel.ForeColor = &H808080
'End Sub
'Private Sub CancelButton_Enter()
' txtNoteLabel.Caption = "Cancel login procedure"
' txtNoteLabel.ForeColor = &H808080
'End Sub
Private Sub userAnswer_Enter()
txtNoteLabel.Caption = IIf(set3Q(askedQno).AnswerType = YesNo, _
"HINT: Possible answer formats are Yes/No, y/n, True/False, 1/0.", _
"Please type your answer here")
txtNoteLabel.ForeColor = &H808080
End Sub
Back to
top of page.
Prototype C program
#include ‹stdio.h›
#include ‹string.h›
#include ‹stdlib.h›
#include ‹ctype.h›
#include ‹math.h›
#include ‹time.h›
/* define all variables */
/**************************************************************************/
#define MAXUSERS 500 // maximum number of users in dataset
#define MAXATTRIBUTES 10 // maximum number of attributes in dataset
#define MAXSETS ((int)(MAXATTRIBUTES * (MAXATTRIBUTES - 1) * (MAXATTRIBUTES - 2) / 6))
#define MAXNOLOGINS 3 // maximum number of login attempts at one time
#define NOQUESTIONS 3 // number of questions that will be asked
#define MAXQUESTIONS 50 // overall number of possible questions
#define MAXIDLENGTH 6 // maximum length of IDs in login procedure
#define MAXDATALENGTH 50 // maximum length of each data stored in database
#define MAXQUESTIONLENGTH 100 // maximum length of asked question
#define MAXANSWERLENGTH 30 // maximum length of given answer in login procedure
#define LIMIT 99999 // define is the number "small" or "large"
#define MAXLINELENGTH MAXIDLENGTH+MAXATTRIBUTES*(MAXDATALENGTH+2) // maximum length of each line read from file
enum Boolean
{FALSE =
0,
TRUE =
1};
/* different answer types */
enum AnswerTypes
{YESNO =
0, MATCHSTRINGS =
1, MATCHNUMBERS =
2};
/* different attribute data types */
enum AttributeTypes
{TEXT =
0, EQUALNUMBERS =
10, SMALLNUMBERS =
11, LARGENUMBERS =
12};
/**************************************************************************/
struct Attributes
{
int No;
char Name
[MAXDATALENGTH
+1];
enum AttributeTypes DataType;
double Quartile
[5];
};
struct Attributes allAtt
[MAXATTRIBUTES
];
struct Sets
{
int index;
struct Attributes att
[NOQUESTIONS
];
};
struct Sets setA
[MAXSETS
];
struct Users
{
char ID
[MAXIDLENGTH
+1];
char attValue
[MAXATTRIBUTES
][MAXDATALENGTH
+1];
struct Sets lastSet;
struct Sets nextSet;
int p
[MAXSETS
];
};
struct Users user
[MAXUSERS
];
struct Questions
{
int No;
enum AttributeTypes Group;
char Form
[MAXQUESTIONLENGTH
+1];
// question sentence
char* CorrectAnswer;
//
enum AnswerTypes AnswerType;
// 0 for yes/no, 1 for matched strings, 2 for matched numbers
int AnswerLength;
};
struct Questions question
[MAXQUESTIONS
];
struct Questions setQ
[NOQUESTIONS
];
// define global variables
const char filename
[] =
"database1.csv";
char data
[MAXUSERS
][MAXATTRIBUTES
][MAXDATALENGTH
+1];
int maxRow, maxCol;
int n_sets;
// number of sets of triple questions
int userIndex;
int askedQno;
// number of currently asked question
char answer
[NOQUESTIONS
][MAXANSWERLENGTH
+1];
// define global functions
int ReadDatabase
(void);
void PrintDataset
(void);
void CreateAttributeMetadata
(void);
void PrintAttributeMetadata
(void);
char *LowerCase
(char *s
);
int IsAttributeNumeric
(const int attNo
);
int IsNumeric
(const char *p
);
int CheckDataRange
(double *p_q
);
double CalculateMedian
(double *p_array,
int length
);
void CalculateQuartiles
(struct Attributes *p_att
);
void SortByNumber
(double *p_array
);
void CalculateOccurrence3
(void);
void CalculateOccurrenceN
(void);
void PrintOccurrence3
(void);
int GenerateRandomNo
(int lowerB,
int upperB
);
int CheckUserID
(void);
void Metropolis
(struct Users *p_user
);
void RandomiseQuestionSet
(struct Attributes *p_att
);
void SetQuestion
(struct Attributes att,
int x
);
char* GenerateQuestion
(int qNo,
struct Attributes att
);
void StartLoginStep2
(struct Users *p_user
);
void CheckAnswers
(void);
char* DefaultAnswerFormat
(char *answer
);
int IsAnswerCorrect
(char *answer,
struct Questions *pq
);
/**************************************************************************
/* MAIN function
/**************************************************************************/
int main
(void)
{
ReadDatabase
();
// PrintDataset();
CreateAttributeMetadata
();
// PrintAttributeMetadata();
CalculateOccurrence3
();
// PrintOccurrence3();
printf ("\nMetadata are successfully created!\n");
CheckUserID
();
return 0;
}
/**************************************************************************
/* Read database from CSV file
/**************************************************************************/
int ReadDatabase
(void)
{
FILE *file = fopen
(filename,
"r");
char line
[MAXLINELENGTH
];
char *tmp;
int row =
0;
int col =
0;
if (file !=
NULL)
{
while (fgets
(line,
sizeof line, file
) !=
NULL)
{
for (tmp = strtok
(line,
","); tmp !=
NULL; tmp = strtok
(NULL,
","))
{
strncpy
(data
[row
][col
], tmp, MAXDATALENGTH
);
maxCol = col;
col++;
}
col =
0;
maxRow = row;
row++;
}
fclose
(file
);
}
else
{
perror
(filename
);
}
// printf ("\nmaxRow is %d, maxCol is %d.\n", maxRow, maxCol);
return 0;
}
/**************************************************************************
/* Print out data imported from database
/**************************************************************************/
void PrintDataset
(void)
{
int i, j;
for (i=
0; i<=maxRow; i++
)
for (j=
0; j<=maxCol; j++
)
{
printf("\nData[%d][%d] is: %s", i, j, &data
[i
][j
]);
}
}
/**************************************************************************
/* Create attribute metadata for whole set of attributes
/**************************************************************************/
void CreateAttributeMetadata
(void)
{
int j;
struct Attributes *p_att = &allAtt
[0];
for (j=
0; j‹maxCol; j++
)
{
p_att->No = j;
strncpy
(p_att->Name, LowerCase
(data
[0][j
+1]), MAXDATALENGTH
);
if (IsAttributeNumeric
(p_att->No
))
{
CalculateQuartiles
(p_att
);
p_att->DataType = CheckDataRange
(p_att->Quartile
);
// printf("\nAttribute[%d] '%s' is numeric.", j, p_att->Name);
}
else
{
p_att->DataType = TEXT;
}
p_att++;
}
}
/**************************************************************************
/* Convert string into lowercase
/**************************************************************************/
char *LowerCase
(char *str
)
{
char *tmp = str;
if (str
)
{
for(; *str; ++str
)
*str = tolower
((unsigned char)*str
);
}
return tmp;
}
/**************************************************************************
/* Check whether the attribute is numeric (flag=TRUE) or not (flag=FALSE)
/**************************************************************************/
int IsAttributeNumeric
(const int attNo
)
{
int row =
1;
enum Boolean flag =
TRUE;
do
{
flag = IsNumeric
(data
[row++
][attNo
+1]);
} while (row<=maxRow && flag
);
return flag;
}
/**************************************************************************
/* Check whether the specific attribute value is numeric (TRUE) or not (FALSE)
/**************************************************************************/
int IsNumeric
(const char *p
)
{
if (*p
)
{
char c;
while (c=*p++
)
{
if (!isdigit
(c
) && c !=
'.')
return FALSE;
}
return TRUE;
}
return FALSE;
}
/**************************************************************************
/* Calculate 5 quartiles for the numeric attribute
/**************************************************************************/
void CalculateQuartiles
(struct Attributes *p_att
)
{
int i;
double tmpArray
[MAXUSERS
];
for (i=
0; i‹maxRow; i++
)
tmpArray
[i
] = strtod
(data
[i
+1][p_att->No
+1],
NULL);
SortByNumber
(tmpArray
);
// print quartiles
// printf ("\n***\n");
// for (i=0; i‹maxRow; i++)
// printf ("%f \n", tmpArray[i]);
p_att->Quartile
[0] = tmpArray
[0];
p_att->Quartile
[1] = CalculateMedian
(tmpArray,
(int)floor
(maxRow/
2));
p_att->Quartile
[2] = CalculateMedian
(tmpArray, maxRow
);
p_att->Quartile
[3] = CalculateMedian
(tmpArray+
(int)floor
(maxRow/
2),
(int)floor
(maxRow/
2));
p_att->Quartile
[4] = tmpArray
[maxRow
-1];
}
/**************************************************************************
/* Sorting numeric array in ascending order
/**************************************************************************/
void SortByNumber
(double *p_array
)
{
int i,j;
double tmp;
for (i=
0; i‹maxRow; i++
)
for (j=
0; j‹maxRow; j++
)
{
if (*
(p_array+i
) < *
(p_array+j
))
{
tmp = *
(p_array+i
);
*
(p_array+i
) = *
(p_array+j
);
*
(p_array+j
) = tmp;
}
}
}
/**************************************************************************
/* Sorting numeric array in ascending order
/**************************************************************************/
double CalculateMedian
(double *p_array,
int length
)
{
int tmp = length/
2;
if (length%
2 ==
0)
return (*
(p_array+tmp
-1)+*
(p_array+tmp
))/
2;
else
return *
(p_array+
(length
-1)/
2);
}
/**************************************************************************
/* Check the range of the numeric attribute
/**************************************************************************/
int CheckDataRange
(double *p_q
)
{
if (*p_q == *
(p_q
+4))
return EQUALNUMBERS;
else if (*
(p_q
+4) <= LIMIT
)
return SMALLNUMBERS;
else
return LARGENUMBERS;
return 0;
}
/**************************************************************************
/* Print metadata obtained for each attribute
/**************************************************************************/
void PrintAttributeMetadata
(void)
{
int i,j;
struct Attributes *p_att = &allAtt
[0];
for (j=
0; j‹maxCol; j++
)
{
printf("\n\n*****");
printf("\nallAtt[%d].No = %d", j, p_att->No
);
printf("\nallAtt[%d].Name = %s", j, p_att->Name
);
printf("\nallAtt[%d].DataType = %d", j, p_att->DataType
);
if (p_att->DataType != TEXT
)
{
for (i=
0; i<
5; i++
)
{
printf("\nallAtt[%d].Quartile[%d]= %f", j, i, p_att->Quartile
[i
]);
}
}
p_att++;
}
}
/**************************************************************************
/* Calculate the number of occurrences of the same sets of three attributes
/* (i.e. triples) in dataset
/**************************************************************************/
void CalculateOccurrence3
(void)
{
int row1, row2, col1, col2, col3;
int occNo;
char *temp1, *temp2;
int A, B, C;
n_sets =
0;
for (col1=
0; col1‹maxCol
-2; col1++
)
for (col2=col1
+1; col2‹maxCol
-1; col2++
)
for (col3=col2
+1; col3‹maxCol; col3++
)
{
// Save the set of three attributes
setA
[n_sets
].
index = n_sets;
setA
[n_sets
].
att[0] = allAtt
[col1
];
setA
[n_sets
].
att[1] = allAtt
[col2
];
setA
[n_sets
].
att[2] = allAtt
[col3
];
// Checks for same attribute triples and count them
for (row1=
0; row1‹maxRow; row1++
)
{
occNo =
0;
for (row2=
0; row2‹maxRow; row2++
)
{
temp1 = data
[row1
+1][col1
+1];
temp2 = data
[row2
+1][col1
+1];
A = strcmp
(temp1, temp2
);
temp1 = data
[row1
+1][col2
+1];
temp2 = data
[row2
+1][col2
+1];
B = strcmp
(temp1, temp2
);
temp1 = data
[row1
+1][col3
+1];
temp2 = data
[row2
+1][col3
+1];
C = strcmp
(temp1, temp2
);
if (A ==
0 && B ==
0 && C ==
0)
occNo++;
}
user
[row1
].
p[n_sets
] =
(maxRow -
1) - occNo;
}
// Counts total number of sets/columns
n_sets ++;
}
n_sets --;
// printf("\nTotal number of sets is: %d.", n_sets);
for (row1=
0; row1‹maxRow; row1++
)
{
strncpy
(user
[row1
].
ID, data
[row1
+1][0], MAXIDLENGTH
);
// printf("\n\nuser[%d].ID = %s", row1, &user[row1].ID);
for (col1=
0; col1‹maxCol; col1++
)
{
strncpy
(user
[row1
].
attValue[col1
], data
[row1
+1][col1
+1], MAXDATALENGTH
);
// printf("\nuser[%d].attValue[%d] = %s", row1, col1, &user[row1].attValue[col1]);
}
user
[row1
].
lastSet = setA
[GenerateRandomNo
(0, n_sets
)];
// printf("\nuser[%d].lastSet = %d", row1, user[row1].lastSet.index);
}
}
/**************************************************************************
/* Print the number of occurrences of the triples in dataset
/**************************************************************************/
void PrintOccurrence3
(void)
{
int row, col;
for (row=
0; row‹maxRow; row++
)
{
printf("\n\n*** User ID is: %s ***\n", &user
[row
].
ID);
for (col=
0; col<=n_sets; col++
)
{
printf(" %d", user
[row
].
p[col
]);
}
}
}
/**************************************************************************
/* Generate random integer number from the interval [lowerB, upperB)
/**************************************************************************/
int GenerateRandomNo
(int lowerB,
int upperB
)
{
srand
((unsigned int)time
(NULL));
return (lowerB +
(rand
()%
(upperB - lowerB +
1)));
// return (lowerB + (int)(rand()/(((double)RAND_MAX + 1) / (upperB - lowerB + 1))));
}
/**************************************************************************
/* Check does entered ID match any of the existing IDs in dataset
/**************************************************************************/
int CheckUserID
(void)
{
int i;
int checkString;
char *p_str;
static int NoOfTries =
0;
// number of tries in login procedure
char username
[MAXIDLENGTH
]=
"";
printf("\n::::::::::::::::::::::::::::::::::::::::");
printf("\n::: WELCOME TO QID LOGIN SYSTEM! :::");
printf("\n::::::::::::::::::::::::::::::::::::::::");
printf("\n\n::: Login Procedure - Step 1 :::\n");
Start:
printf("\n\n\nEnter username: ");
if ((p_str = gets
(username
)) ==
NULL)
{
printf("\nERROR MESSAGE:");
printf("\n\tError on read\n");
return 1;
}
if (strlen
(username
) == MAXIDLENGTH
)
{
i =
0;
do
{
checkString = strcmp
(username, user
[i
].
ID);
if (!checkString
)
{
userIndex = i;
// continue here with Metropolis algorithm
//*********************************************
Metropolis
(&user
[userIndex
]);
printf("\nUser no[%d] last set is %d.", userIndex, user
[userIndex
].
lastSet.
index);
printf("\nUser no[%d] next set is %d.", userIndex, user
[userIndex
].
nextSet.
index);
//*********************************************
printf("\n\n::: Login Procedure - Step 2 :::\n\n");
StartLoginStep2
(&user
[userIndex
]);
return 0;
}
else
{
i++;
}
} while ((i < maxRow
) &&
(checkString !=
0));
// limit the number of login attempts to NoOfTries at one time
if (i == maxRow
)
{
if (NoOfTries < MAXNOLOGINS -
1)
{
printf("\nWARNING MESSAGE:");
printf("\n\tWrong username. Please, try again!");
NoOfTries ++;
goto Start;
}
else
{
printf("\nWARNING MESSAGE:");
printf("\n\tNo more tries, sorry!\n");
printf("\n::::::::::::::::::::::::::::::::::::::::");
printf("\n::: LOGIN SESSION FINISHED! :::");
printf("\n::::::::::::::::::::::::::::::::::::::::\n\n\n");
NoOfTries =
0;
return 0;
}
}
}
else
{
printf("\nWARNING MESSAGE:");
printf("\n\tYou need to enter %d characters for username.", MAXIDLENGTH
);
printf("\n\tYou've entered username with %d characters.", strlen
(username
));
goto Start;
}
return 0;
}
/**************************************************************************
/* Generate random number of question's set according to given distribution
/**************************************************************************/
void Metropolis
(struct Users *p_user
)
{
int set0, setT;
double ratio, x;
enum Boolean accepted;
set0 = p_user->lastSet.
index;
accepted =
FALSE;
while (!accepted
)
{
setT = GenerateRandomNo
(0, n_sets
);
// printf("\nTotal number of sets is: %d.", n_sets);
// check whether random number is accepted or not
ratio = p_user->p
[setT
] / p_user->p
[set0
];
if (ratio >=
1)
{
accepted =
TRUE;
set0 = setT;
}
else
{
x = rand
();
// GenerateRandomNo(0, n_sets);
if (ratio > x
)
{
accepted =
TRUE;
set0 = setT;
}
}
}
p_user->nextSet = setA
[setT
];
}
/**************************************************************************
/* Start Login Step 2 - question generation and validation of the answers
/**************************************************************************/
void StartLoginStep2
(struct Users *p_user
)
{
RandomiseQuestionSet
(p_user->nextSet.
att);
askedQno =
0;
printf("\nHello user %s!\n", p_user->ID
);
while (askedQno < NOQUESTIONS
)
{
printf("\n::: Q(%d of %d): ", askedQno
+1, NOQUESTIONS
);
printf("%s ", GenerateQuestion
(askedQno, p_user->nextSet.
att[askedQno
]));
scanf
("%s", &answer
[askedQno
]);
askedQno++;
}
CheckAnswers
();
}
/**************************************************************************
/* Generate question for given attribute
/**************************************************************************/
char *GenerateQuestion
(int qNo,
struct Attributes att
)
{
int x;
// temporary solution to choose question acording to the attribute data type
switch (att.
DataType)
{
case TEXT:
x = GenerateRandomNo
(1,
2);
break;
case EQUALNUMBERS:
x = GenerateRandomNo
(10,
11);
break;
case SMALLNUMBERS:
x = GenerateRandomNo
(10,
17);
break;
case LARGENUMBERS:
x =
20;
// GenerateRandomNo(20, 22);
break;
default:
break;
}
// set the random question and save it
// in the set of three questions that going to be asked
SetQuestion
(att, x
);
setQ
[qNo
] = question
[x
];
// create question sentence
return question
[x
].
Form;
}
/**************************************************************************
/* Randomise the order of the questions in the chosen question set
/**************************************************************************/
void RandomiseQuestionSet
(struct Attributes *p_att
)
{
int i, j;
struct Attributes tmp;
// randomise the array
for (i=
0; i<=
1; i++
)
{
// pick a random entry from i to NOQUESTIONS-1
j = GenerateRandomNo
(i, NOQUESTIONS
-1);
// swap the attributes in the set
tmp = *
(p_att+i
);
*
(p_att+i
) = *
(p_att+j
);
*
(p_att+j
) = tmp;
}
}
/**************************************************************************
/* Generate possible questions for given attribute type
/**************************************************************************/
void SetQuestion
(struct Attributes att,
int x
)
{
int qLow, qHigh, qMid;
int nDigits;
switch (att.
DataType)
{
case SMALLNUMBERS:
do {
qLow = GenerateRandomNo
(0,
3);
qHigh = GenerateRandomNo
(1,
4);
} while (att.
Quartile[qHigh
] <= att.
Quartile[qLow
]);
//do {
qMid = GenerateRandomNo
(1,
3);
//} while (att.Quartile[qMid] == att.Quartile[qLow] || att.Quartile[qMid] == att.Quartile[qHigh]);
break;
case LARGENUMBERS:
nDigits = GenerateRandomNo
(4,
6);
break;
case EQUALNUMBERS:
break;
case TEXT:
break;
default:
break;
}
switch (x
)
// list of questions for textual attribute
{
case 1:
question
[1].
No =
1;
question
[1].
Group = att.
DataType;
sprintf
(question
[1].
Form,
"%s%s%s",
"What is your ", att.
Name,
"?");
question
[1].
CorrectAnswer = user
[userIndex
].
attValue[att.
No];
question
[1].
AnswerType = MATCHSTRINGS;
question
[1].
AnswerLength = MAXANSWERLENGTH;
break;
case 2:
question
[2].
No =
2;
question
[2].
Group = att.
DataType;
sprintf
(question
[2].
Form,
"%s%s%s",
"What is the value of your ", att.
Name,
"?");
question
[2].
CorrectAnswer = user
[userIndex
].
attValue[att.
No];
question
[2].
AnswerType = MATCHSTRINGS;
question
[2].
AnswerLength = MAXANSWERLENGTH;
break;
// list of questions for numerical attribute
case 10:
question
[10].
No =
10;
question
[10].
Group = att.
DataType;
sprintf
(question
[10].
Form,
"%s%s%s",
"What is the value of your ", att.
Name,
"?");
question
[10].
CorrectAnswer = user
[userIndex
].
attValue[att.
No];
question
[10].
AnswerType = MATCHNUMBERS;
question
[10].
AnswerLength = MAXANSWERLENGTH;
break;
case 11:
question
[11].
No =
11;
question
[11].
Group = att.
DataType;
sprintf
(question
[11].
Form,
"%s%s%s",
"Please enter the value of your ", att.
Name,
": ");
question
[11].
CorrectAnswer = user
[userIndex
].
attValue[att.
No];
question
[11].
AnswerType = MATCHNUMBERS;
question
[11].
AnswerLength = MAXANSWERLENGTH;
break;
case 12:
question
[12].
No =
12;
question
[12].
Group = att.
DataType;
sprintf
(question
[12].
Form,
"%s%s%s%.2f%s",
"Is your ", att.
Name,
" greater than ", att.
Quartile[qMid
],
"?");
question
[12].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) > att.
Quartile[qMid
]) ?
"Yes" :
"No");
question
[12].
AnswerType = YESNO;
question
[12].
AnswerLength = MAXANSWERLENGTH;
break;
case 13:
question
[13].
No =
13;
question
[13].
Group = att.
DataType;
sprintf
(question
[13].
Form,
"%s%s%s%.2f%s",
"Is your ", att.
Name,
" greater than or equal to ", att.
Quartile[qMid
],
"?");
question
[13].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) >= att.
Quartile[qMid
]) ?
"Yes" :
"No");
question
[13].
AnswerType = YESNO;
question
[13].
AnswerLength = MAXANSWERLENGTH;
break;
case 14:
question
[14].
No =
14;
question
[14].
Group = att.
DataType;
sprintf
(question
[14].
Form,
"%s%s%s%.2f%s",
"Is your ", att.
Name,
" less than ", att.
Quartile[qMid
],
"?");
question
[14].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) < att.
Quartile[qMid
]) ?
"Yes" :
"No");
question
[14].
AnswerType = YESNO;
question
[14].
AnswerLength = MAXANSWERLENGTH;
break;
case 15:
question
[15].
No =
15;
question
[15].
Group = att.
DataType;
sprintf
(question
[15].
Form,
"%s%s%s%.2f%s",
"Is your ", att.
Name,
" less than or equal to ", att.
Quartile[qMid
],
"?");
question
[15].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) <= att.
Quartile[qMid
]) ?
"Yes" :
"No");
question
[15].
AnswerType = YESNO;
question
[15].
AnswerLength = MAXANSWERLENGTH;
break;
case 16:
question
[16].
No =
16;
question
[16].
Group = att.
DataType;
sprintf
(question
[16].
Form,
"%s%s%s%.2f%s%.2f%s",
"Is your ", att.
Name,
" greater than or equal to ", att.
Quartile[qLow
],
" and less than ", att.
Quartile[qHigh
],
"?");
question
[16].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) >= att.
Quartile[qLow
]) &&
(strtod
(user
[userIndex
].
attValue[att.
No],
NULL) < att.
Quartile[qHigh
]) ?
"Yes" :
"No");
question
[16].
AnswerType = YESNO;
question
[16].
AnswerLength = MAXANSWERLENGTH;
break;
case 17:
question
[17].
No =
17;
question
[17].
Group = att.
DataType;
sprintf
(question
[17].
Form,
"%s%s%s%.2f%s%.2f%s",
"Is your ", att.
Name,
" greater than ", att.
Quartile[qLow
],
" and less than or equal to ", att.
Quartile[qHigh
],
"?");
question
[17].
CorrectAnswer =
((strtod
(user
[userIndex
].
attValue[att.
No],
NULL) > att.
Quartile[qLow
]) &&
(strtod
(user
[userIndex
].
attValue[att.
No],
NULL) <= att.
Quartile[qHigh
]) ?
"Yes" :
"No");
question
[17].
AnswerType = YESNO;
question
[17].
AnswerLength = MAXANSWERLENGTH;
break;
case 20:
question
[20].
No =
20;
question
[20].
Group = att.
DataType;
sprintf
(question
[20].
Form,
"%s%d%s%s%s",
"Please enter the last ", nDigits,
" digits of your ", att.
Name,
": ");
question
[20].
CorrectAnswer =
(user
[userIndex
].
attValue[att.
No]+strlen
(user
[userIndex
].
attValue[att.
No])-nDigits
);
question
[20].
AnswerType = MATCHSTRINGS;
question
[20].
AnswerLength = nDigits;
break;
default:
break;
}
}
/**************************************************************************
/* Check the answers obtained for the chosen set of questions
/**************************************************************************/
void CheckAnswers
(void)
{
int i;
int validAnswer
[NOQUESTIONS
];
int finalAnswer =
1;
printf("\n\n\nChecking your answers");
for (i=
0; i‹NOQUESTIONS; i++
)
{
validAnswer
[i
] = IsAnswerCorrect
(answer
[i
], &setQ
[i
]);
printf("\n...");
printf("\nQ%d. Your answer is %s.", i
+1,
(validAnswer
[i
] ?
"correct" :
"incorrect"));
finalAnswer = finalAnswer && validAnswer
[i
];
}
if (finalAnswer
)
{
printf("\n\nCongratulation! You are successfully log in.\n\n");
user
[userIndex
].
lastSet = user
[userIndex
].
nextSet;
}
else
{
printf("\n\nSorry, you've failed to log in.\n\n");
}
}
/**************************************************************************
/* Check is the answer correct depending on the question type
/**************************************************************************/
int IsAnswerCorrect
(char *answer,
struct Questions *pq
)
{
switch (pq->AnswerType
)
{
case YESNO:
return (strcmp
(DefaultAnswerFormat
(answer
), pq->CorrectAnswer
) ==
0 ?
1 :
0);
break;
case MATCHSTRINGS:
return (strcmp
(answer, pq->CorrectAnswer
) ==
0 ?
1 :
0);
break;
case MATCHNUMBERS:
return (strtod
(answer,
NULL) == strtod
(pq->CorrectAnswer,
NULL) ?
1 :
0);
break;
default:
break;
}
return 0;
}
/**************************************************************************
/* Return default value of the answer if the given answer is from the specific array
/**************************************************************************/
char *DefaultAnswerFormat
(char *answer
)
{
int i;
char *YesAnswers
[10] =
{"Yes",
"y",
"True",
"1"};
char *NoAnswers
[10] =
{"No",
"n",
"False",
"0"};
// for any answer from YesAnswers array return "Yes"
for (i =
0; i<
4; i++
) // UBound(YesAnswers)
{
// if (strcmp(LowerCase(answer), LowerCase(YesAnswers[i])) == 0)
if (strcmp
(answer, YesAnswers
[i
]) ==
0)
return YesAnswers
[0];
}
// for any answer from NoAnswers array return "No"
for (i =
0; i<
4; i++
) // UBound(NoAnswers)
{
// if (strcmp(LowerCase(answer), LowerCase(NoAnswers[i])) == 0)
if (strcmp
(answer, NoAnswers
[i
]) ==
0)
return NoAnswers
[0];
}
return "Nan";
}
Back to
top of page.
Student ID,Student Name,Preparation mark,Experiment 1 mark,Experiment 2 mark,Experiment 3 mark,Experiment 4 mark,Final mark,Final mark (in %),Telephone number
308543,CHRISTIAN WAHSWEILER,2,4,4,5,5,20,100,1689828653
308529,MARTIN BACHHAUSEN,2,4,4,5,5,20,100,7906646446
308537,JAN MULLER,2,4,4,5,3,18,90,7773184089
254823,CARL FADHEL,2,4,4,5,3,18,90,7871616480
230904,JAMES ROWE,2,4,4,5,3,18,90,7817225785
250179,ZULKIFLI ABDUL AZIZ,2,2,3,3,2,12,60,1243601147
220003,NURUL A BOSTANUDIN,2,3,3,3,2,13,65,7788458205
215851,JAMES GOOCH,2,4,4,5,5,20,100,1983822249
349131,JISHA MURALIDHARAN,2,2,2,3,3,12,60,7949832366
157699,ALASJAIR INGLE,1,1,2,3,3,10,50,7748401376
229094,ANDREA RALPH,2,4,4,5,3,18,90,1372466028
245558,BIJI BAMGBOYE,1,3,4,3,2,13,65,7917132911
221324,ALLAN LE FEUVRE,2,4,4,5,3,18,90,7702758773
308399,BENJAMIN N.A. COBLLAH,2,2,3,3,3,13,65,7981006302
347649,FATIMAH A. MOLOO,2,2,3,3,3,13,65,7910167335
223126,DOROTHEOS KARAMPELAS,0,2,3,3,3,11,55,7756770654
254012,AHMED ALBALOUSHI ,2,3,2,3,4,14,70,1225873275
237314,KHALIFA ALMARBOUEI,2,3,2,3,4,14,70,1299250795
205025,THEODORE THEODOROPOULOR,0,2,3,3,0,8,40,7828748557
190033,KONSTANTINOS PAPADOPOULOS ,0,2,3,3,0,8,40,7725747091
182635,MARK PEACOCK,2,3,3,5,0,13,65,94779432778
279068,FERGUS WALKER,2,4,4,5,5,20,100,7810250596
345218,NEIL YOUNG,2,4,4,5,5,20,100,94775810923
317040,SITAPORAM PILLAI SARAMANAN,2,4,2,3,2,13,65,7944115676
221008,MANNATHIL MANEESH MOHANAN,2,4,2,3,2,13,65,7717460331
271713,JAMIE HUDSON,2,4,4,4,4,18,90,2088563285
240288,AFSHEEN MORTAZAIR-FAR,2,4,4,4,4,18,90,7731543738
271757,NICK BAKER,2,3,2,4,0,11,55,7765828137
249441,MELCHIABE NIBIGIRA,2,3,3,4,0,12,60,1491681502
216948,ZAW ZAW,2,3,3,2,0,10,50,1494712985
220658,WAAH ZAN,2,3,3,2,0,10,50,7989187665
173086,J. DODDS,2,3,4,2,0,11,55,7852504107
351752,ALBERTO TORRES,0,1,2,1,0,4,20,7931210599
303340,HIZRN DAYANA MOHD HIDZIR,2,3,1,3,0,9,45,7845218890
218731,TAN CHEN LIN,2,3,1,3,0,9,45,7866081288
221326,DAVID PIPE,1,2,3,2,2,10,50,7798730929
268076,IAIN STANLEY,2,3,4,3,2,14,70,7798915912
306920,ANCAN AL-NAIMI,2,3,3,4,2,14,70,7900808215
271228,JASSER AL-DOSARI,2,3,3,4,2,14,70,7708503412
221793,FAHAD AL-AMERI,2,2,3,4,0,11,55,2348036558
289140,HANI AL NAQBI,2,2,3,4,0,11,55,7932962852
237997,NAWAF ALMEHRI,2,2,3,4,2,13,65,9665675112
245980,ALI AL NEYAOI,2,2,3,4,2,13,65,6771774884
236397,SALEM ALRASHEDI,2,2,2,2,2,10,50,1403267925
178869,TONY SMITH,2,1,3,4,3,13,65,7756156045
255948,YIN KLUNG WONG,2,1,3,2,2,10,50,7828448629
231389,EDWARD WALKER,2,2,3,3,0,10,50,2083112269
238589,SOPHIE WASHINGTON,2,2,3,3,0,10,50,7847120212
145647,ALI AL-SHEHRI,1,1,2,2,0,6,30,196334081
221593,ATODELE IBIDAPO,2,1,2,2,0,7,35,1243533491
239471,BEN REED,2,4,4,3,2,15,75,7746410553
271380,HAITHAM ALNAQBI,2,4,4,3,2,15,75,1730893729
220183,MAUNG KYAW NAINH TUN,2,2,3,2,0,9,45,7737549309
145671,AZAM ALMOGREN,2,2,3,2,0,9,45,7816265413
351741,KATIA CACERES MOSQUEIRA,0,1,1,3,3,8,40,2392293807
353043,SCANDURA DANILA,2,1,1,3,3,10,50,299477140
117691,POLYMENAKOS TZANETOS,0,2,1,3,3,9,45,7709897597
229118,HAMMED OKE,2,3,2,3,3,13,65,2380273467
Back to
top of page.