openct-tasks/bebras/2016/2016-FR-11-encoded-image/task_drag_and_drop.js

398 lines
11 KiB
JavaScript

function initTask(subTask) {
var state = {};
var level;
var answer = null;
var data = {
easy: {
maxDigit: 1,
slots: 12,
grid: [
[0, 1, 1, 0],
[1, 0, 0, 1],
[0, 1, 1, 0]
],
gridCellSize: 50
},
medium: {
maxDigit: 4,
slots: 12,
grid: [
[0, 0, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 0],
[1, 1, 0, 0, 1, 1],
[0, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 0, 0]
],
gridCellSize: 30
},
hard: {
maxDigit: 9,
slots: 24,
grid: [
[0, 0, 1, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 1, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 0, 0, 1, 1],
[1, 1, 0, 0, 0, 0, 1, 1],
[0, 0, 1, 1, 1, 1, 0, 0]
],
gridCellSize: 30
}
};
var paper;
var dragAndDrop;
var digitSources;
var answerContainer;
var userGrid;
var targetGrid;
var paperParams = {
width: 760,
height: 600,
userGridCenterX: 200,
targetGridCenterX: 560,
gridY: 340,
gridTextY: 300,
sourcesY: 150,
instructionsY: 50,
answerY: 225,
maxRowSlots: 12
};
var gridParams = {
lineAttr: {
"stroke-width": 1,
stroke: "#000000"
},
rectAttr: {
"stroke-width": 1
},
selectedRectAttr: {
fill: "#555555"
}
};
var textParams = {
attr: {
"font-size": 20
}
};
var digitParams = {
cellSize: 40,
xPad: 20,
textAttr: {
"font-size": 16
},
rectAttr: {
fill: "#dddddd"
},
backgroundAttr: {
fill: "#ffffff"
}
};
subTask.loadLevel = function(curLevel) {
level = curLevel;
};
subTask.getStateObject = function() {
return state;
};
subTask.reloadAnswerObject = function(answerObj) {
answer = answerObj;
};
subTask.resetDisplay = function() {
initPaper();
initDragAndDrop();
initGrids();
};
subTask.getAnswerObject = function() {
return answer;
};
subTask.getDefaultAnswerObject = function() {
return [];
};
subTask.unloadLevel = function(callback) {
if(userGrid) {
userGrid.remove();
}
if(targetGrid) {
targetGrid.remove();
}
if(dragAndDrop) {
dragAndDrop.disable();
}
callback();
};
function initPaper() {
paper = subTask.raphaelFactory.create("anim", "anim", paperParams.width, paperParams.height);
paper.text(paperParams.width / 2, paperParams.instructionsY, taskStrings.instructions).attr(textParams.attr);
paper.text(paperParams.userGridCenterX, paperParams.gridTextY, taskStrings.userGrid).attr(textParams.attr);
paper.text(paperParams.targetGridCenterX, paperParams.gridTextY, taskStrings.targetGrid).attr(textParams.attr);
}
function initDragAndDrop() {
dragAndDrop = DragAndDropSystem({
paper: paper,
actionIfDropped: actionIfDropped,
drop: onDrop
});
digitSources = {};
var leftmostX = paperParams.width / 2 - (data[level].maxDigit + 1) * digitParams.cellSize / 2 - data[level].maxDigit * digitParams.xPad / 2;
for(var digit = 0; digit <= data[level].maxDigit; digit++) {
var centerX = leftmostX + digitParams.cellSize / 2 + digit * (digitParams.cellSize + digitParams.xPad);
digitSources[digit] = dragAndDrop.addContainer({
ident : digit,
type: "source",
cx: centerX,
cy: paperParams.sourcesY,
widthPlace: digitParams.cellSize,
heightPlace: digitParams.cellSize,
sourceElemArray: [drawDigit(digit)]
});
}
var slotPositions = [];
var numRows = Math.ceil(data[level].slots / paperParams.maxRowSlots);
var numCols = Math.min(paperParams.maxRowSlots, data[level].slots);
leftmostX = paperParams.width / 2 - numCols * digitParams.cellSize / 2;
topY = paperParams.answerY - numRows * digitParams.cellSize / 2;
for(var row = 0; row < numRows; row++) {
var slotCenterY = topY + row * digitParams.cellSize + digitParams.cellSize / 2;
for(var col = 0; col < numCols; col++) {
var slotCenterX = leftmostX + col * digitParams.cellSize + digitParams.cellSize / 2;
slotPositions.push([slotCenterX, slotCenterY]);
}
}
answerContainer = dragAndDrop.addContainer({
ident: "container",
cx: paperParams.width / 2,
cy: paperParams.answerY,
widthPlace: digitParams.cellSize,
heightPlace: digitParams.cellSize,
dropMode : "insertBefore",
dragDisplayMode : "preview",
placeBackgroundArray: [drawDigitCellBackground()],
nbPlaces: data[level].slots,
places: slotPositions
});
dragAndDrop.insertObjects("container", 0, $.map(answer, function(digit) {
if(digit == null) {
return null;
}
return {
ident: digit,
elements: [drawDigit(digit)]
};
}));
}
function drawDigitCellBackground() {
return paper.rect(
- digitParams.cellSize / 2,
- digitParams.cellSize / 2,
digitParams.cellSize,
digitParams.cellSize).attr(digitParams.backgroundAttr);
}
function drawDigit(digit) {
paper.setStart();
paper.rect(
- digitParams.cellSize / 2,
- digitParams.cellSize / 2,
digitParams.cellSize,
digitParams.cellSize).attr(digitParams.rectAttr);
paper.text(0, 0, digit).attr(digitParams.textAttr);
return paper.setFinish();
}
function actionIfDropped(srcCont, srcPos, dstCont, dstPos, dropType) {
// Allow throwing objects away.
if (dstCont != "container") {
return dstCont == null;
}
var oldSequence = dragAndDrop.getObjects("container");
// Search for rightmost index for insertion.
var newIndex = 0;
for (var i = 0; i < oldSequence.length; i++) {
if (oldSequence[i] != null) {
newIndex = i + 1;
}
}
// If this element was already here, one more slot is available.
if (srcCont == "container") {
newIndex--;
}
// Allow insertion in the middle of the list.
if (dstPos <= newIndex) {
return true;
}
// Only allow appending the current list, no dropping further away to the right.
if (newIndex < data[level].slots) {
return DragAndDropSystem.action(dstCont, newIndex, 'insert');
}
}
function onDrop(srcContainerID, srcPos, dstContainerID, dstPos, dropType) {
answer = dragAndDrop.getObjects("container");
while(answer.length > 0 && answer[answer.length - 1] === null) {
answer.pop();
}
refreshUserGrid();
}
function initGrids() {
var leftX = paperParams.targetGridCenterX - data[level].grid[0].length * data[level].gridCellSize / 2;
targetGrid = Grid.fromArray("anim", paper, data[level].grid, cellFiller, data[level].gridCellSize, data[level].gridCellSize, leftX, paperParams.gridY, gridParams.lineAttr);
leftX = paperParams.userGridCenterX - data[level].grid[0].length * data[level].gridCellSize / 2;
userGrid = new Grid("anim", paper, data[level].grid.length, data[level].grid[0].length, data[level].gridCellSize, data[level].gridCellSize, leftX, paperParams.gridY, paperParams.lineAttr);
refreshUserGrid();
}
function cellFiller(cellData, paper) {
var row = cellData.row;
var col = cellData.col;
var xPos = cellData.xPos;
var yPos = cellData.yPos;
var element = paper.rect(xPos, yPos, data[level].gridCellSize, data[level].gridCellSize).attr(gridParams.rectAttr);
if(cellData.entry == 1) {
element.attr(gridParams.selectedRectAttr);
}
return [element];
}
function refreshUserGrid() {
refreshGrid(userGrid, answerToTable());
}
function refreshGrid(grid, table) {
for(var row = 0; row < data[level].grid.length; row++) {
for(var col = 0; col < data[level].grid[0].length; col++) {
grid.setCell(cellFiller, {
row: row,
col: col,
entry: table[row][col]
});
}
}
}
function answerToTable() {
var rows = data[level].grid.length;
var cols = data[level].grid[0].length;
var table = Beav.Matrix.make(rows, cols, 0);
var digit, iDigit, row, col, index, tempIndex;
if(level == "easy") {
for(iDigit = 0; iDigit < answer.length; iDigit++) {
digit = answer[iDigit];
row = Math.floor(iDigit / cols);
col = iDigit % cols;
if(digit == 1) {
table[row][col] = 1;
}
}
}
else if(level == "medium") {
index = 0;
for(iDigit = 0; iDigit < answer.length; iDigit++) {
digit = answer[iDigit];
for(tempIndex = 0; tempIndex < digit; tempIndex++) {
row = Math.floor(index / cols);
col = index % cols;
if(row >= rows) {
return table;
}
table[row][col] = (iDigit % 2);
index++;
}
}
}
else if(level == "hard") {
index = 0;
for(iDigit = 0; iDigit < answer.length; iDigit++) {
digit = answer[iDigit];
for(tempIndex = 0; tempIndex < digit; tempIndex++) {
row = Math.floor(index / cols);
col = index % cols;
if(row >= rows) {
return table;
}
if(row === 0) {
table[row][col] = (iDigit % 2);
}
else {
table[row][col] = (table[row - 1][col] + (iDigit % 2)) % 2;
}
index++;
}
}
}
return table;
}
function verifyFormat() {
if(!answer || answer.length === undefined || answer.length === null) {
return false;
}
if(answer.length < 0 || answer.length > data[level].slots) {
return false;
}
for(var iDigit = 0; iDigit < answer.length; iDigit++) {
var num = parseInt(answer[iDigit]);
if(num < 0 || num > data[level].maxDigit) {
return false;
}
}
return true;
}
function getResultAndMessage() {
if(!verifyFormat()) {
return {
successRate: 0,
message: "internal error"
};
}
var table = answerToTable();
if(Beav.Object.eq(table, data[level].grid)) {
return {
successRate: 1,
message: taskStrings.success
};
}
else {
return {
successRate: 0,
message: taskStrings.wrong
};
}
}
subTask.getGrade = function(callback) {
callback(getResultAndMessage());
};
}
initWrapper(initTask, ["easy", "medium", "hard"]);