- 2 lives
- show
solution
on last incorrect - show
correct
on correct attempt - show
incorrect_1st_attempt
on incorrect when life is 2
getDynamicBlock
function getDynamicBlock(lives, inputs, is_correct, global_context_variables) {
const s3 = "name:incorrect_1st_attempt"; // 1st incorrect
const s2 = "solution"; // last incorrect
const s1 = "name:correct"; // correct
let storyId = "";
if (is_correct) storyId = s1;
if (lives == 2 && !is_correct) {
storyId = s3;
}
if (lives == 1 && !is_correct) {
storyId = s2;
}
if (storyId) {
return {
type: "manual_story",
storyId,
};
}
return null;
}
- 3 lives
- show
solution
on last incorrect - show
correct
on correct attempt - show
incorrect_1st_attempt
on incorrect when life is 3 - show
incorrect_2nd_attempt
on incorrect when life is 2 - show
incorrect_3rd_attempt
on incorrect when life is 1
getDynamicBlock
function getDynamicBlock(lives, inputs, is_correct, global_context_variables) {
const s5 = "name:incorrect_3rd_attempt"; // 1st incorrect
const s4 = "name:incorrect_2nd_attempt"; // 1st incorrect
const s3 = "name:incorrect_1st_attempt"; // 1st incorrect
const s2 = "solution"; // last incorrect
const s1 = "name:correct"; // correct
let storyId = "";
if (is_correct) storyId = s1;
if (lives == 5 && !is_correct) {
storyId = s3;
}
if (lives == 4 && !is_correct) {
storyId = s2;
}
if (lives == 3 && !is_correct) {
storyId = s1;
}
if (lives == 1 && !is_correct) {
storyId = s2;
}
if (storyId) {
return {
type: "manual_story",
storyId,
};
}
return null;
}
- Correctness based
- On correct goto ->
C1B2
- default ->
next
getNextBlock
function getNextBlock(history, next, global_context_variables) {
const curr = history[history.length - 1];
if (curr.submission.is_correct) return "C1B2";
return next;
}
Update Feedback pool
function updateFeedbackText(feedbackPool, global_context_variables) {
function replaceValuesInTemplate(template, valueMap) {
function replace(obj) {
if (Array.isArray(obj)) {
return obj.map((item) => replace(item));
} else if (typeof obj === "object" && obj !== null) {
const replacedObj = {};
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === "string") {
const replacedValue = replaceVariablesInString(
obj[key],
valueMap,
);
replacedObj[key] = replacedValue;
} else {
replacedObj[key] = replace(obj[key]);
}
});
return replacedObj;
} else if (typeof obj === "string") {
return replaceVariablesInString(obj, valueMap);
} else {
return obj;
}
}
function replaceVariablesInString(str, valueMap) {
const regex = /@@@(.*?)@@@/g;
const parsedText = str.replace(regex, (match, variableName) => {
const val =
valueMap[variableName] !== undefined
? valueMap[variableName]
: match;
return typeof val == "object" ? JSON.stringify(val) : val;
});
try {
const text = JSON.parse(parsedText);
return typeof text === "number" ? `${text}` : text;
} catch {
return parsedText;
}
}
return [...replace(template)];
}
return replaceValuesInTemplate(feedbackPool, global_context_variables);
}
Update Feedback pool for tap & select (updateFeedbackPool function)
function updateFeedbackText(currentFeedbackData, global_context_variables) {
function replaceValuesInTemplate(template, valueMap) {
function replace(obj) {
if (Array.isArray(obj)) {
return obj.map((item) => replace(item));
} else if (typeof obj === "object" && obj !== null) {
const replacedObj = {};
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === "string") {
const replacedValue = replaceVariablesInString(
obj[key],
valueMap,
);
replacedObj[key] = replacedValue;
} else {
replacedObj[key] = replace(obj[key]);
}
});
return replacedObj;
} else if (typeof obj === "string") {
return replaceVariablesInString(obj, valueMap);
} else {
return obj;
}
}
function replaceVariablesInString(str, valueMap) {
const regex = /@@@(.*?)@@@/g;
const parsedText = str.replace(regex, (match, variableName) => {
const val =
valueMap[variableName] !== undefined
? valueMap[variableName]
: match;
return typeof val == "object" ? JSON.stringify(val) : val;
});
try {
const text = JSON.parse(parsedText);
return typeof text === "number" ? `${text}` : text;
} catch {
return parsedText;
}
}
return [...replace(template)];
}
return replaceValuesInTemplate(currentFeedbackData, global_context_variables);
}
Update Feedback pool for Input
function updateFeedbackText(endFeedback, global_context_variables) {
function replaceValuesInTemplate(template, valueMap) {
function replace(obj) {
if (Array.isArray(obj)) {
return obj.map((item) => replace(item));
} else if (typeof obj === "object" && obj !== null) {
const replacedObj = {};
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === "string") {
const replacedValue = replaceVariablesInString(
obj[key],
valueMap,
);
replacedObj[key] = replacedValue;
} else {
replacedObj[key] = replace(obj[key]);
}
});
return replacedObj;
} else if (typeof obj === "string") {
return replaceVariablesInString(obj, valueMap);
} else {
return obj;
}
}
function replaceVariablesInString(str, valueMap) {
const regex = /@@@(.*?)@@@/g;
const parsedText = str.replace(regex, (match, variableName) => {
const val =
valueMap[variableName] !== undefined
? valueMap[variableName]
: match;
return typeof val == "object" ? JSON.stringify(val) : val;
});
try {
const text = JSON.parse(parsedText);
return typeof text === "number" ? `${text}` : text;
} catch {
return parsedText;
}
}
return [...replace(template)];
}
return replaceValuesInTemplate(endFeedback, global_context_variables);
}
Update Feedback pool for table ( with original/parsed )(updateStartFeedbackPool function)
function updateFeedbackPool(tableData, startFeedback, global_context_variables) {
function replaceValuesInTemplate(template, valueMap) {
function replace(obj) {
if (Array.isArray(obj)) {
return obj.map(item => replace(item));
} else if (typeof obj === 'object' && obj !== null) {
const replacedObj = {};
Object.keys(obj).forEach(key => {
if (typeof obj[key] === 'string') {
const replacedValue = replaceVariablesInString(obj[key], valueMap);
replacedObj[key] = replacedValue;
} else {
replacedObj[key] = replace(obj[key]);
}
});
return replacedObj;
} else if (typeof obj === 'string') {
return replaceVariablesInString(obj, valueMap);
} else {
return obj;
}
}
function replaceVariablesInString(str, valueMap) {
const regex = /@@@(.*?)@@@/g;
const parsedText = str.replace(regex, (match, variableName) => {
const val = valueMap[variableName] !== undefined ? valueMap[variableName] : match;
return typeof val == 'object' ? JSON.stringify(val) : val;
});
try {
const text = JSON.parse(parsedText);
return typeof text === 'number' ? `${text}` : text;
} catch {
return parsedText;
}
}
return replace(template);
}
let feedback = startFeedback;
const isObject = typeof startFeedback == 'object' && !Array.isArray(startFeedback) && startFeedback['original'];
if (isObject) {
feedback = startFeedback['original'] ?? [];
}
let output = replaceValuesInTemplate(feedback, global_context_variables);
return { original: feedback, parsed: output };
}
evaluate
function evaluate(params) {
const { tableData, helpers } = params;
let is_correct = true;
let cell_level_is_correct = [];
tableData.cells.forEach((row, rowIndex) => {
cell_level_is_correct.push([]);
row.forEach((cell, columnIndex) => {
const { cellInputValue, cellIsInput, cellIsLatexBox } =
helpers.getCellInputValue(cell);
console.log(
"evaluate---------",
rowIndex,
columnIndex,
cellIsLatexBox,
cell,
);
if (cellIsInput) {
const cellCorrectValueArr = helpers.getCellCorrectValues(cell);
if (cellIsLatexBox) {
console.log(
"cellIsLatexBox------",
cellCorrectValueArr,
cellInputValue,
);
let correctionState = [];
cellInputValue.forEach((inputValue, iterIndex) => {
// Using `find` to search for a matching element after converting both sides to strings
const isCorrect =
cellCorrectValueArr[iterIndex].find(
(item) => String(item) === String(inputValue),
) !== undefined;
correctionState.push(isCorrect);
});
cell_level_is_correct[rowIndex][columnIndex] =
correctionState;
} else {
if (
cellCorrectValueArr.find(
(corrVal) => corrVal === cellInputValue,
)
) {
cell_level_is_correct[rowIndex][columnIndex] = true;
} else {
cell_level_is_correct[rowIndex][columnIndex] = false;
is_correct = false;
}
}
}
});
});
return {
is_correct,
cell_level_is_correct,
};
}
Reorder evaluate
function checkReorder(params) {
const { tableData } = params;
const correctOrder = [0, 5, 2, 3, 1, 4]; // Predefined correct order of indices
let is_correct = true;
let cell_level_is_correct = [];
// Check if the length of the reorderValue matches the correctOrder to prevent out of bounds errors
if (tableData.reorderValue.length !== correctOrder.length) {
is_correct = false;
} else {
// Iterate and compare each element in the reorderValue array to the correctOrder array
for (let i = 0; i < correctOrder.length; i++) {
if (tableData.reorderValue[i] !== correctOrder[i]) {
is_correct = false;
break; // Exit the loop early if a mismatch is found
}
}
}
return {
is_correct,
cell_level_is_correct
};
}
Tappable evaluate
function evaluate(params) {
const { tableData, helpers } = params;
let is_correct = true;
let cell_level_is_correct = [];
tableData.cells.forEach((row, rowIndex) => {
cell_level_is_correct.push([]);
row.forEach((cell, columnIndex) => {
const { cellIsClick, cellClickValue } =
helpers.getCellInputValue(cell);
const cellCorrectValueArr = helpers.getCellCorrectValues(cell);
console.log(
"evaluate---------",
rowIndex,
columnIndex,
cell,
cellIsClick,
cellClickValue,
cellCorrectValueArr
);
if(cellIsClick){
if (
cellCorrectValueArr.find(
(corrVal) => corrVal === cellClickValue,
)
) {
cell_level_is_correct[rowIndex][columnIndex] = true;
} else {
cell_level_is_correct[rowIndex][columnIndex] = false;
is_correct = false;
}
}
});
});
return {
is_correct,
cell_level_is_correct,
};
}
feedbackFunction
function feedbackFunction(params) {
const { tableData, tableCorrectnessState, helpers, prefix, pixiData } = params;
const totalLives = pixiData.globalContext.parent_variables?.find(i => i.name.includes('total_lives'));
const totalLivesVal = totalLives.default ?? totalLives.value;
let soundArray;
const tableStartSound = `question_audio_checking`;
let tableEndSound = '';
if (tableCorrectnessState.is_correct) {
tableEndSound = `question_audio_correct`;
} else {
if (totalLivesVal == 2) tableEndSound = 'question_audio_incorrect_attempt1';
if (totalLivesVal == 1) tableEndSound = 'question_audio_incorrect_last_attempt';
}
let obj = {};
obj = {
tableStartText: tableStartSound,
textDuring: `${prefix}_table_during_${tableCorrectnessState.is_correct ? 'correct' : 'incorrect'}`,
tableEndText: tableEndSound,
tableEndSticker:tableEndSound,
};
soundArray = {
soundDuring: `${prefix}_table_during_${tableCorrectnessState.is_correct ? 'correct' : 'incorrect'}`
};
return {
tableStartSound,
tableEndSound,
soundArray,
...obj
};
}
partial feedbackFunction
function feedbackFunction(params) {
const { tableData, tableCorrectnessState, helpers, prefix, pixiData } = params;
const totalLives = pixiData.globalContext.parent_variables?.find(i => i.name.includes('total_lives'));
const totalLivesVal = totalLives.default ?? totalLives.value;
let soundArray;
let partialCorrect = tableCorrectnessState?.cell_level_is_correct.flat().some(e => e == true);
console.log('testing', partialCorrect)
const tableStartSound = `question_audio_checking`;
let tableEndSound = '';
if (tableCorrectnessState.is_correct) {
tableEndSound = `question_audio_all_correct`;
} else {
if(partialCorrect) {
if (totalLivesVal == 2) tableEndSound = "question_audio_partial_incorrect_attempt1";
if (totalLivesVal == 1) tableEndSound = "question_audio_partial_incorrect_last_attempt";
} else {
if (totalLivesVal == 2) tableEndSound = "question_audio_all_incorrect_attempt1";
if (totalLivesVal == 1) tableEndSound = "question_audio_all_incorrect_last_attempt";
}
}
let obj = {};
obj = {
tableStartText: tableStartSound,
tableEndText: tableEndSound,
tableEndSticker:tableEndSound,
};
return {
tableStartSound,
tableEndSound,
soundArray,
...obj
};
}
condition feedbackFunction
function feedbackFunction(params) {
const { tableData, tableCorrectnessState, helpers, prefix, all_variables, pixiData } = params;
// Adjusted to read feedbackType from the nested property
const feedbackType = tableData.feedback.type;
const matrix = tableCorrectnessState.cell_level_is_correct;
let soundArray;
const tableStartSound = 'question_audio_checking1';
let tableEndSound = ``;
const totalLives = pixiData.globalContext.parent_variables?.find(i => i.name.includes('total_lives'));
const totalLivesVal = totalLives.default ?? totalLives.value;
const { isRowCorrect, isColumnCorrect } = helpers;
switch (feedbackType) {
case 'CELL':
soundArray = [];
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex++) {
soundArray[rowIndex] = [];
for (let colIndex = 0; colIndex < matrix[rowIndex].length; colIndex++) {
const soundObj = {
soundBegin: `${prefix}_cell_${rowIndex}_${colIndex}_begin_${
matrix[rowIndex][colIndex] ? 'correct' : 'incorrect'
}`,
soundDuring: `${prefix}_cell_${rowIndex}_${colIndex}_during_${
matrix[rowIndex][colIndex] ? 'correct' : 'incorrect'
}`,
soundEnd: `${prefix}_cell_${rowIndex}_${colIndex}_end_${matrix[rowIndex][colIndex] ? 'correct' : 'incorrect'}`
};
if (colIndex === 0 && rowIndex === 0) {
const inputValue = helpers.getCellInputValue(tableData.cells[rowIndex][colIndex]);
if (inputValue === 42) {
soundObj.soundDuring = `${prefix}_cell_${rowIndex}_${colIndex}_during_42_is_incorrect`;
}
}
soundArray[rowIndex][colIndex] = soundObj;
}
}
break;
case 'ROW':
soundArray = [];
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex++) {
const rowCorrectness = isRowCorrect(matrix, rowIndex);
soundArray.push({
soundBegin: `${prefix}_row_${rowIndex}_begin_${rowCorrectness ? 'correct' : 'incorrect'}`,
soundDuring: `${prefix}_row_${rowIndex}_during_${rowCorrectness ? 'correct' : 'incorrect'}`,
soundEnd: `${prefix}_row_${rowIndex}_end_${rowCorrectness ? 'correct' : 'incorrect'}`
});
}
break;
case 'COLUMN':
soundArray = [];
for (let colIndex = 0; colIndex < matrix[0].length; colIndex++) {
const columnCorrectness = isColumnCorrect(matrix, colIndex);
soundArray.push({
soundBegin: `${prefix}_column_${colIndex}_begin_${columnCorrectness ? 'correct' : 'incorrect'}`,
soundDuring: `${prefix}_column_${colIndex}_during_${columnCorrectness ? 'correct' : 'incorrect'}`,
soundEnd: `${prefix}_column_${colIndex}_end_${columnCorrectness ? 'correct' : 'incorrect'}`
});
}
break;
case 'TABLE':
tableEndSound = '';
soundArray = {
soundBegin: tableStartSound,
soundDuring: `${prefix}_table_during_${tableCorrectnessState.is_correct ? 'correct' : 'incorrect'}`,
soundEnd: tableEndSound
};
break;
default:
throw new Error('Invalid feedback type');
}
const statusVar = all_variables.find(i => i.name == 'condition_status');
const status = statusVar?.default ?? statusVar?.value;
console.log(statusVar, status);
if (!status.includes(false) && !tableEndSound) tableEndSound = 'question_audio_all_correct';
if (status.includes(true) && !tableEndSound) tableEndSound = 'question_audio_partial_correct';
if (totalLivesVal == 2 && !tableEndSound) tableEndSound = 'question_audio_all_incorrect_attempt1';
if (totalLivesVal == 1 && !tableEndSound) tableEndSound = 'question_audio_all_incorrect_last_attempt';
soundArray = {
soundBegin: tableStartSound,
soundDuring: ``,
soundEnd: tableEndSound
};
return {
tableStartSound,
tableEndSound,
soundArray
};
}
tappable
function tappable(params) {
const { variable, frameId } = params;
const result = [];
let currentSound = "";
const selectedSound =
"https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667396330.mp3";
const notSelectedSound =
"https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667360304.mp3";
const cellVariable = variable.find(v => v.frame_id == frameId);
const value = cellVariable.selected == 1 ? "#FCF6D7" : "#FFFFFF";
const item = {
type: "UPDATE_FILL",
props: {
...cellVariable,
color: { value },
},
};
if (cellVariable.selected) {
currentSound = selectedSound;
} else {
currentSound = notSelectedSound;
}
result.push(item);
const sound = {
type: "PLAY_SOUND",
props: {
url: currentSound,
},
};
result.push(sound);
return result;
}
Adv Tappable
function tappable(params) {
const { variable, frameId, defaults } = params;
const { tableData } = defaults;
const splitArray = frameId.split(':');
const arrayLength = splitArray.length;
const columnIndex = splitArray[arrayLength - 1];
const rowIndex = splitArray[arrayLength - 2];
const result = [];
let currentSound = '';
const selectedSound = 'https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1711036651467.mp3';
const notSelectedSound = 'https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1711036672317.mp3';
const cellVariable = variable.find(v => v.frame_id == frameId);
const cellValue = Number(tableData.cells[Number(rowIndex)][Number(columnIndex)].text.value.default);
const text = Number(tableData.cells[Number(rowIndex)][Number(columnIndex)].text.value.default) + 1;
const tappable = tableData.cells[Number(rowIndex)][Number(columnIndex)].tappable;
console.log(tappable,'this is tappable')
const currentTap = tappable.tap_count.default ?? 0;
function updateNextCell(colIndex){
if(colIndex != 0){
const nextColumnIndex = Number(colIndex) - 1;
const nextCellValue = Number(tableData.cells[Number(rowIndex)][nextColumnIndex].text.value.default);
const nextText = nextCellValue + 1;
const nextFrameId = splitArray.slice(0,arrayLength - 1).join(':') + ':' + nextColumnIndex;
const nextCellVariable = variable.find(v => v.frame_id == nextFrameId);
if(nextCellValue == 9){
const item = {
type: 'UPDATE_TEXT',
props: {
...nextCellVariable,
text: "0"
}
};
result.push(item);
updateNextCell(nextColumnIndex);
}else {
const item = {
type: 'UPDATE_TEXT',
props: {
...nextCellVariable,
text: nextText,
color: "#1B34FF"
}
};
result.push(item);
}
}
}
if(cellValue == 0 && tappable.tap_count.default != 0){
}else if (text >= 10) {
const item = {
type: 'UPDATE_TEXT',
props: {
...cellVariable,
text: "0"
}
};
updateNextCell(columnIndex);
result.push(item);
currentSound = selectedSound;
} else {
const item = {
type: 'UPDATE_TEXT',
props: {
...cellVariable,
text,
color: "#1B34FF"
}
};
result.push(item);
const count = {
type:"UPDATE_TAP_COUNT",
props:{
...cellVariable,
count: currentTap + 1
}
}
result.push(count);
currentSound = selectedSound;
}
const sound = {
type: 'PLAY_SOUND',
props: {
url: currentSound
}
};
result.push(sound);
return result;
}
Adv Tappable
function tappable(params) {
const { variable, frameId, defaults } = params;
const result = []
let currentSound = "";
const { tableData } = defaults;
const splitArray = frameId.split(':');
const arrayLength = splitArray.length;
const columnIndex = splitArray[arrayLength - 1];
const rowIndex = splitArray[arrayLength - 2];
const selectedSound = "https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667396330.mp3"
const notSelectedSound = "https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667360304.mp3"
const hiddenImage = "https://sets-gamify-assets.s3.ap-south-1.amazonaws.com/dev/home-explore/document/1716901576120.png"
const cellVariable = variable.find(v => v.frame_id == frameId);
const cellValue = tableData.cells[Number(rowIndex)][Number(columnIndex)];
const tappable = cellValue.tappable;
const currentTap = tappable.tap_count.default ?? 0;
const totalTappable = tableData.cells.map(row => row.filter(col => col.tappable?.enabled ?? false)).flat(2)
const tappedCell = totalTappable.filter(cell => Number(cell?.tappable?.tap_count?.default) ?? 0 > 0);
let isNearBy = false;
if(tappedCell.length){
const previousCell = tappedCell[0];
const previousCellId = previousCell.id.split('-');
const previousId = splitArray.slice(0, splitArray.length - 2)
previousId.push(previousCellId[0])
previousId.push(previousCellId[1])
function getIsAdj(row, col) {
return [
[row - 1, col],
[row + 1, col],
[row, col - 1],
[row, col + 1]
];
}
const adj = getIsAdj(Number(previousCellId[0]), Number(previousCellId[1]))
isNearBy = adj.find(e => e[0] === Number(rowIndex) && e[1] === Number(columnIndex));
}
if (tappedCell.length == 0 && tappable.tap_count.default == 0) {
const disableText = {
type: 'UPDATE_TEXT',
props: {
...cellVariable,
text: cellValue.text.value.default,
enabled: false
}
}
const item = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
url: hiddenImage
}
};
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
count: currentTap + 1
}
};
result.push(item);
result.push(disableText);
result.push(count);
} else if (currentTap == 0 && isNearBy) {
const previousCell = tappedCell[0];
const newValue = Number(previousCell.text.value.default) - Number(cellValue.text.value.default);
const disableText = {
type: 'UPDATE_TEXT',
props: {
...cellVariable,
text: newValue
}
};
result.push(disableText);
const background = {
type: 'UPDATE_FILL',
props: {
...cellVariable,
color: { value: 'yellow' }
}
};
result.push(background);
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
count: currentTap + 1
}
};
result.push(count);
const previousCellId = previousCell.id.split('-');
const previousId = splitArray.slice(0, splitArray.length - 2)
previousId.push(previousCellId[0])
previousId.push(previousCellId[1])
const id = previousId.join(':');
const count1 = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
frame_id: id,
count: "0"
}
};
const disableText1 = {
type: 'UPDATE_TEXT',
props: {
...cellVariable,
frame_id: id,
text: cellValue.text.value.default,
enabled: false
}
}
const item1 = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
frame_id: id,
url: hiddenImage
}
};
result.push(item1);
result.push(disableText1);
result.push(count1);
}
const sound = {
type: "PLAY_SOUND",
props: {
url: currentSound
}
};
result.push(sound);
return result;
}
Adv Adv Tappable
function tappable(params) {
const { variable, frameId, defaults, global_context_variables } = params;
const result = [];
let currentSound = '';
const { tableData } = defaults;
const splitArray = frameId.split(':');
const arrayLength = splitArray.length;
const columnIndex = splitArray[arrayLength - 1];
const rowIndex = splitArray[arrayLength - 2];
const selectedSound = 'https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667396330.mp3';
const notSelectedSound = 'https://cdn.homeworkapp.ai/sets-gamify-assets/dev/worksheet/audio/1710667360304.mp3';
const cellVariable = variable.find(v => v.frame_id == frameId);
const cellValue = tableData.cells[Number(rowIndex)][Number(columnIndex)];
const tappable = cellValue.tappable;
const currentTap = tappable.tap_count.default ?? 0;
const button_1 = global_context_variables?.button_1 ?? '';
const button_2 = global_context_variables?.button_2?? '';
if (rowIndex == 0) {
const btn1Part = splitArray.slice(0, splitArray.length - 2);
btn1Part.push(button_1);
const btn1Id = btn1Part.join(':');
const btn2Part = splitArray.slice(0, splitArray.length - 2);
btn2Part.push(button_2);
const btn2Id = btn2Part.join(':');
const nextId = frameId == btn1Id ? btn2Id : btn1Id;
const value = currentTap == 0 ? '#fcf6d7' : '#FFFFFF';
const opValue = value == "#fcf6d7" ? "#FFFFFF" : "#fcf6d7";
const item = {
type: 'UPDATE_FILL',
props: {
...cellVariable,
color: { value }
}
};
const item1 = {
type: 'UPDATE_FILL',
props: {
...cellVariable,
frame_id: nextId,
color: { value: opValue }
}
};
currentSound = selectedSound;
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
count: 1,
value: 'NaN'
}
};
const count1 = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
frame_id: nextId,
count: "0",
value: 'NaN'
}
};
result.push(count);
result.push(item);
result.push(count1);
result.push(item1);
const sound = {
type: 'PLAY_SOUND',
props: {
url: currentSound
}
};
result.push(sound);
return result;
}
const selectedBtn = tableData.cells[0].find(cell=> cell?.tappable?.tap_count?.default > 0);
console.log(selectedBtn,'selectedBtn');
if(!selectedBtn) return result;
const selectedId = selectedBtn.tappable.rowIndex + ":" + selectedBtn.tappable.columnIndex;
const tappableRows = tableData.cells.filter((row,i) => i != 0);
const totalTappable = tappableRows.map(row => row.filter(col => col.tappable?.enabled ?? false)).flat(2);
let tappedCell = totalTappable.filter(cell => Number(cell?.tappable?.tap_count?.default) ?? 0 > 0);
let bunny = '';
let final_image = '';
let circle = '';
let startingCell = '';
let nextStep = 1;
let starting_text = '';
let jump_text = '';
let selected_text = '';
const bunny1 = global_context_variables.bunny1;
const bunny2 = global_context_variables.bunny2;
const circle1 = global_context_variables.circle1;
const circle2 = global_context_variables.circle2;
const nextStep1 = global_context_variables.nextStep_1;
const nextStep2 = global_context_variables.nextStep_2;
const bothBunny = global_context_variables['bunny_1&2'];
const bothCircle = global_context_variables['circle_1&2'];
const startingCell1 = global_context_variables?.starting_cell_1;
const startingCell2 = global_context_variables?.starting_cell_2;
const final_1 = global_context_variables?.final_image_1;
const final_2 = global_context_variables?.final_image_2;
const bothFinal = global_context_variables['final_image_1&2'];
const starting_text1 = global_context_variables.starting_text1 ?? 'This is not the starting point!';
const starting_text2 = global_context_variables.starting_text2 ?? 'This is not the starting point!';
const jump_text1 = global_context_variables.jump_text1 ?? 'Pink bunny can jump only 2 steps at a time!';
const jump_text2 = global_context_variables.jump_text2 ?? 'Pink bunny can jump only 2 steps at a time!';
const selected_text1 = global_context_variables.selected_text1 ?? 'Pink bunny cannot go back! But, you can reset its path';
const selected_text2 = global_context_variables.selected_text2 ?? 'Pink bunny cannot go back! But, you can reset its path';
if(selectedId == button_1){
bunny = bunny1;
circle = circle1;
nextStep = nextStep1;
startingCell = startingCell1;
starting_text = starting_text1;
jump_text = jump_text1;
selected_text = selected_text1;
}
if(selectedId == button_2){
bunny = bunny2;
circle = circle2;
nextStep = nextStep2;
startingCell = startingCell2;
starting_text = starting_text2;
jump_text = jump_text2;
selected_text = selected_text2;
}
let isNearBy = false;
let startingUpdated = false;
let endingCell = global_context_variables?.ending_cell;
let isEndingClicked = false;
let hasJumpCorrect = false;
if (startingCell) {
const startingCellsIds = startingCell.split(',');
if (startingCellsIds.length) {
for (let i = 0; i < startingCellsIds.length; i++) {
const startingCellIds = startingCellsIds[i].split(':');
const startingRow = startingCellIds[0];
const startingColumn = startingCellIds[1];
const startingCellData = tableData.cells[Number(startingRow)][Number(startingColumn)];
const startingCellTappable = startingCellData.imageBackground?.src;
if (
(Number(startingRow) == rowIndex && Number(startingColumn) == columnIndex) ||
startingCellTappable?.default == bunny ||
startingCellTappable?.default == circle ||
startingCellTappable?.default == bothCircle
) {
startingUpdated = true;
}
}
}
}
if (endingCell) {
const endingCellsIds = endingCell.split(',');
if (endingCellsIds.length) {
for (let i = 0; i < endingCellsIds.length; i++) {
const endingCellIds = endingCellsIds[i].split(':');
const startingRow = endingCellIds[0];
const startingColumn = endingCellIds[1];
const endingCellData = tableData.cells[Number(startingRow)][Number(startingColumn)];
const endingCellTappable = endingCellData.imageBackground?.src;
console.log(endingCellData, endingCellTappable,'this is ending',startingRow,rowIndex,startingColumn,columnIndex);
if (Number(startingRow) == rowIndex && Number(startingColumn) == columnIndex) {
isEndingClicked = true;
}
}
}
}
if (tappedCell.length && nextStep) {
const previousCell = totalTappable.find(
cell => cell?.imageBackground?.src?.default == bunny || cell?.imageBackground?.src?.default == bothBunny
);
const preValue = Number(previousCell?.text?.value?.default) || '0';
const nextValue = Number(cellValue.text?.value?.default) || '0';
console.log(nextStep,preValue,nextValue,'nextValue')
if (Number(nextStep) == Math.abs(Number(preValue) - Number(nextValue))) {
hasJumpCorrect = true;
}
}
const noInputNodes = variable.filter(v => v.selected == 'NaN');
for (let i = 0; i < noInputNodes.length; i++) {
const noInputNode = noInputNodes[i];
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...noInputNode,
value: '0'
}
};
result.push(count);
}
if (tappedCell.length) {
const previousCell = tappedCell[0];
const prevRowIndex = previousCell.tappable.rowIndex;
const prevColumnIndex = previousCell.tappable.columnIndex;
const previousId = splitArray.slice(0, splitArray.length - 2);
previousId.push(prevRowIndex);
previousId.push(prevColumnIndex);
function getIsAdj(row, col) {
return [
[row - 1, col],
[row + 1, col],
[row, col - 1],
[row, col + 1]
];
}
const adj = getIsAdj(Number(prevRowIndex), Number(prevColumnIndex));
isNearBy = adj.find(e => e[0] === Number(rowIndex) && e[1] === Number(columnIndex));
} else {
isNearBy = true;
}
const starting = tappableRows
.map(row =>
row.filter(
col =>
col.imageBackground?.src?.default == bothBunny ||
col.imageBackground?.src?.default == bunny1 ||
col.imageBackground?.src?.default == bunny2
)
)
.flat(2);
console.log(tappedCell,starting, currentTap, startingUpdated, isEndingClicked, hasJumpCorrect);
if (
tappedCell.length == 0 &&
currentTap == 0 &&
startingUpdated
) {
const background = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
url: bunny
}
};
result.push(background);
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
count: Number(currentTap) + 1,
value: '1'
}
};
result.push(count);
result.push(background);
currentSound = selectedSound;
console.log('called starting',starting)
if (starting.length) {
const prevRowIndex = starting[0].tappable.rowIndex;
const prevColumnIndex = starting[0].tappable.columnIndex;
const previousId = splitArray.slice(0, splitArray.length - 2);
previousId.push(prevRowIndex);
previousId.push(prevColumnIndex);
const id = previousId.join(':');
const currentImage = starting[0].imageBackground?.src?.default;
let url = '';
if (currentImage == bothBunny) {
url = bunny == bunny1 ? bunny2 : bunny1;
}
const background1 = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
frame_id: id,
url: url
}
};
result.push(background1);
}
} else if (
cellValue?.imageBackground?.src?.default !== circle &&
cellValue?.imageBackground?.src?.default !== bunny &&
cellValue?.imageBackground?.src?.default !== bothBunny &&
cellValue?.imageBackground?.src?.default !== bothCircle &&
hasJumpCorrect && startingUpdated
) {
if (isEndingClicked) {
if(bunny == bunny1){
final_image = final_1;
}else {
final_image = final_2;
}
if(cellValue?.imageBackground?.src?.default == final_1 ||cellValue?.imageBackground?.src?.default == final_2){
final_image = bothFinal;
}
const background = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
url: final_image
}
};
result.push(background);
} else {
const currentImage = cellValue?.imageBackground?.src?.default;
let url = bunny;
if(currentImage == bunny1 || currentImage == bunny2){
url = bothBunny
}
const background = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
url: url
}
};
result.push(background);
}
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
count: Number(currentTap) + 1,
value: '1'
}
};
result.push(count);
const previousCell = totalTappable.find(
cell => cell?.imageBackground?.src?.default == bunny || cell?.imageBackground?.src?.default == bothBunny
);
const prevRowIndex = previousCell.tappable.rowIndex;
const prevColumnIndex = previousCell.tappable.columnIndex;
const previousId = splitArray.slice(0, splitArray.length - 2);
previousId.push(prevRowIndex);
previousId.push(prevColumnIndex);
const id = previousId.join(':');
const count1 = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
frame_id: id,
count: '0',
value: '1'
}
};
let url = "";
const currentImage = previousCell.imageBackground?.src?.default;
if(currentImage == bothBunny) {
url = bunny == bunny1 ? bunny2 : bunny1;
}else if(currentImage == bunny1 || currentImage == bunny2){
let anotherBunnyImage = currentImage == bunny1 ? bunny2 : bunny1;
let anotherBunnyCell = totalTappable.find(cell => cell?.imageBackground?.src?.default == anotherBunnyImage);
const anotherBunnyCellValue = anotherBunnyCell?.text?.value?.default ?? '0';
const currentValue = previousCell?.text?.value?.default ?? '0';
let anotherBunnyNextStep = currentImage == bunny1 ? nextStep2: nextStep1;
const value = Number(currentValue) - Number(anotherBunnyCellValue);
console.log(value, value < 0 ,Number(anotherBunnyCellValue) % Number(anotherBunnyNextStep),
Number(currentValue) % Number(anotherBunnyNextStep),anotherBunnyNextStep,
anotherBunnyCellValue,currentValue,'this is next')
if (
(value < 0 || !anotherBunnyCell) &&
Number(anotherBunnyCellValue) % Number(anotherBunnyNextStep) == 0 &&
Number(currentValue) % Number(anotherBunnyNextStep) == 0
) {
url = bothCircle
}else if(isNaN(anotherBunnyCellValue)) {
// }else {
console.log('called herer')
url = circle
}else if(!isNaN(anotherBunnyCellValue) && !isNaN(currentValue)){
console.log('called 2 else if')
url = circle
}
}
const background1 = {
type: 'UPDATE_IMAGE_BACKGROUND',
props: {
...cellVariable,
frame_id: id,
url: url
}
};
result.push(background1);
result.push(count1);
currentSound = selectedSound;
} else if (cellValue?.imageBackground?.src?.default === bunny) {
currentSound = notSelectedSound;
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
value: '1'
}
};
result.push(count);
const feedback = {
type: 'SHOW_FEEDBACK_TEXT',
props: {
feedback: {
name: 'question_audio_correct',
text: [
{
type: 'p',
children: [
{
text: selected_text
}
]
}
],
duration: 5
}
}
};
result.push(feedback);
} else {
currentSound = notSelectedSound;
const currentActive = tappedCell.length == 0;
const previous = cellValue?.imageBackground?.src?.default == circle;
const feedback = {
type: 'SHOW_FEEDBACK_TEXT',
props: {
feedback: {
name: 'question_audio_correct',
text: [
{
type: 'p',
children: [
{
text: currentActive ? starting_text : previous ? selected_text : jump_text
}
]
}
],
duration: 5
}
}
};
result.push(feedback);
const count = {
type: 'UPDATE_TAP_COUNT',
props: {
...cellVariable,
value: currentActive ? 'NaN' : previous ? '1' : '0'
}
};
result.push(count);
}
const sound = {
type: 'PLAY_SOUND',
props: {
url: currentSound
}
};
result.push(sound);
return result;
}
Sound
function updateStartAudio(
is_correct,
componentsList,
global_context_variables,
) {
return "question_audio_checking";
}
function updateEndAudio(
is_correct,
componentsList,
pixiData,
global_context_variables,
) {
const tempList = Array.isArray(componentsList)
? componentsList
: JSON.parse(componentsList);
if (["true", true, 1, "1"].includes(is_correct)) {
return "question_audio_correct";
}
const totalLives = pixiData.globalContext.parent_variables?.find((i) =>
i.name.includes("total_lives"),
);
const totalLivesVal = totalLives.default ?? totalLives.value;
if (totalLivesVal == 2 && !is_correct) {
return "question_audio_incorrect_attempt1";
}
if (totalLivesVal == 1 && !is_correct) {
return "question_audio_incorrect_attempt2";
}
}
Sound
function updateAttemptAudio(index, componentsList, groqResponse, pixiData) {
const totalLives = pixiData.globalContext.parent_variables?.find((i) =>
i.name.includes("total_lives"),
);
const totalLivesVal = totalLives.default ?? totalLives.value;
if (totalLivesVal == 1) {
switch (groqResponse?.toLowerCase()) {
case 'incorrect':
return 'question_audio_part2_incorrect_last_attempt';
break;
case 'incomplete':
return 'question_audio_part2_incomplete_last_attempt';
break;
case 'idk':
return 'question_audio_part2_idk_last_attempt';
break;
case 'gibberish':
return 'question_audio_part2_gibberish_last_attempt';
break;
default:
break;
}
}
switch (groqResponse?.toLowerCase()) {
case 'correct':
return 'question_audio_part2_correct';
break;
case "incorrect":
return "question_audio_part2_incorrect_attempt1"
break;
case "incomplete":
return "question_audio_part2_incomplete_attempt1"
break
case "idk":
return "question_audio_part2_idk_attempt1"
break
case "gibberish":
return "question_audio_part2_gibberish_attempt1"
break
default:
break;
}
return
}
- Total lives
const totalLives = pixiData.globalContext.parent_variables?.find((i) =>
i.name.includes("total_lives"),
);
const totalLivesVal = totalLives.default ?? totalLives.value;
if (totalLivesVal == 1 && !is_correct) {
return "question_audio_incorrect_attempt2";
}
- Table
a. Drag drop value path via cell
const value =
cell.dragDrop?.value ??
cell.dragDrop?.droppedSource?.props?.drop_value?.value;
b. Helper functions
- To use following create a variable
tableData
add it in variable link
num_1
function nums(obj) {
const key = '1';
function getValue(name) {
try {
return JSON.parse(obj[name]);
} catch {
return obj[name];
}
}
function getStringToNumberMap(tableCells) {
const obj = {};
for (let row = 0; row < tableCells.length; row++) {
for (let col = 0; col < tableCells[row].length; col++) {
const cell = tableCells[row][col];
// Check if the cell contains an indicator string
if (typeof cell === 'string' && cell.includes('Number')) {
let numberKey = cell;
// Determine the direction of the indicator
if (cell.includes('ππ½')) {
// Collect all numbers directly below the indicator
let rowBelow = row + 1;
let numberString = '';
while (rowBelow < tableCells.length && tableCells[rowBelow][col] !== "") {
numberString += tableCells[rowBelow][col];
rowBelow++;
}
if (numberString) {
obj[numberKey] = numberString;
}
} else if (cell.includes('ππ½')) {
// Collect all numbers directly to the right of the indicator
let colRight = col + 1;
let numberString = '';
while (colRight < tableCells[row].length && tableCells[row][colRight] !== "") {
numberString += tableCells[row][colRight];
colRight++;
}
if (numberString) {
obj[numberKey] = numberString;
}
}
}
}
}
return obj;
}
const tableData = getValue('tableData')?.cells;
const nums = getStringToNumberMap((tableData ?? []).map(i => i.map(j => j.value ?? j.text?.value?.default ?? '')));
return nums[Object.keys(nums).find(i => i.includes(key))];
}
number1
function number_1(obj) {
const variable = 'num_1';
function getVal(key) {
try {
return JSON.parse(obj[key]);
} catch {
return obj[key];
}
}
function test(n) {
if (n < 0) return false;
const single_digit = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine'];
const double_digit = [
'Ten',
'Eleven',
'Twelve',
'Thirteen',
'Fourteen',
'Fifteen',
'Sixteen',
'Seventeen',
'Eighteen',
'Nineteen'
];
const below_hundred = ['Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety'];
if (n === 0) return 'Zero';
function translate(n) {
let word = '';
if (n < 10) {
word = single_digit[n] + ' ';
} else if (n < 20) {
word = double_digit[n - 10] + ' ';
} else if (n < 100) {
let rem = translate(n % 10);
word = below_hundred[(n - (n % 10)) / 10 - 2] + ' ' + rem;
} else if (n < 1000) {
word = single_digit[Math.trunc(n / 100)] + ' Hundred ' + translate(n % 100);
} else if (n < 1000000) {
word = translate(parseInt(n / 1000)).trim() + ' Thousand ' + translate(n % 1000);
} else if (n < 1000000000) {
word = translate(parseInt(n / 1000000)).trim() + ' Million ' + translate(n % 1000000);
} else {
word = translate(parseInt(n / 1000000000)).trim() + ' Billion ' + translate(n % 1000000000);
}
return word;
}
let result = translate(n);
return result.trim() + '.';
}
const num = (String(getVal(variable) ?? 0) || '0').replace(/\D/g, '') || 0;
return test(parseInt(String(num).replace(/\D/g, '')));
}
- Component Index
if (pixiData.originalJson.componentIndex == 1) {
//
}
feedback text is not working for start audio
Sound
function updateFeedbackAudio(
variables,
isStart,
conditions,
currConditionIndex,
isConditionCorrect,
global_context_variables,
pixiData
) {
const nums = global_context_variables['nums'];
if (isStart == 'end') {
return;
}
if (isStart) {
return `question_audio_checking_${currConditionIndex + 1}`;
}
if (isConditionCorrect) return `question_audio_condition_${currConditionIndex + 1}_correct`;
if (currConditionIndex == 0) {
return 'question_audio_condition_1_incorrect';
}
if (currConditionIndex == 1) {
return 'question_audio_condition_2_incorrect';
}
}
correntness
function getConditionCorrect(
variables,
conditions,
currConditionIndex,
getValue,
global_context_variables
) {
const tableData = global_context_variables.tableData;
const startingCell = global_context_variables.starting_cell;
const endingCell = global_context_variables.ending_cell;
const ActiveColor = global_context_variables.colour;
const answer = global_context_variables.answer;
const startingCellsIds = startingCell.split(',');
const endingCellsIds = endingCell.split(',');
let startingUpdated = false;
let endingUpdated = false;
if (startingCellsIds.length) {
for (let i = 0; i < startingCellsIds.length; i++) {
const startingCellIds = startingCellsIds[i].split(':');
const startingRow = startingCellIds[0];
const startingColumn = startingCellIds[1];
const startingCellData = tableData.cells[Number(startingRow)][Number(startingColumn)];
const startingCellTappable = startingCellData.fillColor;
console.log(startingCellTappable, 'startingCellTappable');
if (startingCellTappable.default == ActiveColor && startingCellData?.imageBackground?.enabled) {
startingUpdated = true;
break;
}
}
}
if (endingCellsIds.length) {
for (let i = 0; i < endingCellsIds.length; i++) {
const endingCellIds = endingCellsIds[i].split(':');
const endingRow = endingCellIds[0];
const endingColumn = endingCellIds[1];
const endingCellData = tableData.cells[Number(endingRow)][Number(endingColumn)];
const endingCellTappable = endingCellData.fillColor;
console.log(endingCellTappable, 'endingCellTappable');
if (endingCellTappable.default == ActiveColor && !endingCellData?.imageBackground?.enabled) {
endingUpdated = true;
break;
}
}
}
const finalRow = tableData.cells.map(row => row.find(col => col.fillColor.default === ActiveColor && !col?.imageBackground?.enabled)).find(i => i);
console.log(finalRow,'this is final row')
if (currConditionIndex == 0) {
return startingUpdated && endingUpdated;
}
if (currConditionIndex == 1) {
return finalRow && Number(finalRow.text.value.default) == Number(answer);
}
return false;
}
end audio
function updateEndAudio(is_correct, componentsList, pixiData) {
const tempList = Array.isArray(componentsList) ? componentsList : JSON.parse(componentsList);
if (['true', true, 1, '1'].includes(is_correct)) {
return 'question_audio_correct';
}
const totalLives = pixiData.globalContext.parent_variables?.find((i) =>
i.name.includes("total_lives"),
);
const totalLivesVal = totalLives.default ?? totalLives.value;
if (totalLivesVal == 2 && !is_correct) {
return "question_audio_incorrect_1st_attempt";
}
if (totalLivesVal == 1 && !is_correct) {
return "question_audio_incorrect_last_attempt";
}
}
end audio
function getGlobalSound(
is_correct,
zoneIdx,
isStart,
isParent,
dropZones,
correctStatus,
itemClusterIdx,
isItemCluster,
pixiData
) {
const totalLives = pixiData.globalContext.parent_variables?.find(i => i.name.includes('total_lives'));
const totalLivesVal = totalLives.default ?? totalLives.value;
let sound = 'question_audio_checking';
if (!isStart) {
if (totalLivesVal == 2 && !is_correct) sound = 'question_audio_incorrect_try1';
if (totalLivesVal == 1 && !is_correct) sound = 'question_audio_incorrect_try2';
if (is_correct) sound = 'question_audio_correct';
}
if (isParent) return sound;
return '';
}