Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recreate Bakery Simulator interactive for Software Engineering chapter #1267

Draft
wants to merge 32 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6bb5930
Add initial files.
courtneycb Nov 5, 2019
1564500
Add README and licence files.
courtneycb Nov 5, 2019
6c63cac
Update contributors list.
courtneycb Nov 5, 2019
5ea5f85
Add placeholder images - these are yet to be remade.
courtneycb Nov 5, 2019
4d3be24
Add customer answers and change html structure.
courtneycb Nov 6, 2019
bdd9587
Add questions.
courtneycb Nov 6, 2019
fe52747
Add dropdown. Styling.
courtneycb Nov 6, 2019
902bea1
Add customer answer functionality.
courtneycb Nov 6, 2019
7f8ae87
Add question count and disable questions already asked.
courtneycb Nov 6, 2019
e6b90fb
WIP. Adding baking stage.
courtneycb Nov 6, 2019
49b3638
Change layout.
courtneycb Nov 7, 2019
8a4902a
Playing around with styling.
courtneycb Nov 7, 2019
1f2c272
WIP. style.
courtneycb Nov 7, 2019
6c9b81a
Add radio buttons.
courtneycb Nov 8, 2019
97428cb
Refactor to use config file.
courtneycb Nov 11, 2019
3adb8b2
Tidy up radio buttons.
courtneycb Nov 11, 2019
f6abc26
WIP.
courtneycb Nov 12, 2019
eb37eb0
Merge branch 'develop' into issue/1182/seng
courtneycb Nov 19, 2019
76834a0
User can select multiple decorations.
courtneycb Nov 19, 2019
d241c42
WIP.
courtneycb Nov 20, 2019
1d0dcda
Retrieve selected options.
courtneycb Nov 20, 2019
f38bd9d
Tidy up variable names and minor fixes.
courtneycb Nov 20, 2019
01c8a2a
Create basic result table.
courtneycb Nov 20, 2019
6e3aa9b
Minor improvements to table.
courtneycb Nov 20, 2019
e340cf2
Add background colour to table for incorrect and correct.
courtneycb Nov 21, 2019
92d4e6c
WIP.
courtneycb Nov 21, 2019
2a7a8d7
can cycle through the different customers.
courtneycb Nov 27, 2019
4dd49f6
Merge branch 'develop' into issue/1182/seng
courtneycb Nov 27, 2019
1240209
comments.
courtneycb Nov 28, 2019
dbef506
Add docstrings
courtneycb Dec 4, 2019
b32106c
Restart once completed last level.
courtneycb Dec 4, 2019
12e2dc6
merge develop
courtneycb May 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions LICENCE-THIRD-PARTY
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ licensed under MIT licence.
third-party-licences/babel.txt
==============================================================================

==============================================================================
Bakery Simulator
------------------------------------------------------------------------------
https://github.com/jakescreen/game-design-final
Copyright 2019 Jake Screen, Kelly Mi, Benjamin Jenny, Sophia Freaney
licensed under MIT licence.
third-party-licences/bakery-simulator.txt
==============================================================================

==============================================================================
before-after.js
------------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions csfieldguide/interactives/content/en/interactives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ available-menu-items:
name: Available Menu Items
awful-calculator:
name: Awful Calculator
bakery-simulator:
name: Bakery Simulator
base-calculator:
name: Base Calculator
big-number-calculator:
Expand Down
4 changes: 4 additions & 0 deletions csfieldguide/interactives/content/structure/interactives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ awful-calculator:
de: interactives/awful-calculator.html
es: interactives/awful-calculator.html
is_interactive: true
bakery-simulator:
languages:
en: interactives/bakery-simulator.html
is_interactive: true
base-calculator:
languages:
en: interactives/base-calculator.html
Expand Down
24 changes: 24 additions & 0 deletions csfieldguide/static/interactives/bakery-simulator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Bakery Simulator interactive

**Created by:**

- Sophia Freaney
- Jake Screen
- Peter Jenny
- Kelly Mi

The original can be found [here](https://github.com/jakescreen/game-design-final).

**Rebuilt by:** Courtney Bracefield

Users of this interactive will learn about the Analysis step of Software Engineering.

## The interactive

The user is tasked with baking a cake for a customer.
There are 3 customers in total: the first gives the least helpful answers, the second gives somewhat helpful answers, and the third gives very helpful information along with a lot of extraneous information.
Once the cake has been constructed, the user receives feedback through the form of a score on how close their cake was to the one the customer wanted.

## Licences

The licence of the original interactive can be found in `LICENCE-THIRD-PARTY` with a full copy available in the `third-party-licences` directory.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.card-text {
margin-bottom: 0.3rem;
}

#dialogue-box {
border: 0.25rem solid #2a3da0;
border-radius: 0.5rem;
background-color: #f8f9fa;
font-size: 1.25rem;
padding: 1rem 2rem;
top: 77%;
height: 8rem;
overflow-y: scroll;
}

#question-dropdown {
top: 37%;
left: 78%;
}

#time-to-bake,
#start-asking {
top: 87%;
}

#num-qs-asked-text {
top: 93%;
}

#question-list p:hover {
cursor: pointer;
background-color: #dcddec;
}

#question-list p {
font-size: 1rem;
padding: 0.5rem 2rem;
margin: 0;
}

#layers-radio p,
#flavour-radio p,
#size-radio p {
margin-right: 2rem !important;
}

#icing-colour-radio p,
#decorations-radio p {
margin-right: 0.5rem !important;
}

#shape-radio p {
margin-right: 1rem !important;
}

.correct {
background-color: #cdffd8;
}

.incorrect {
background-color: #ffc2a6;
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
var CONFIG = require('./config.js');

var bakerySim = {};

bakerySim.currentCustomer = 1;
bakerySim.numQuestionsAsked = 0;
bakerySim.maxQuestions = 6;


$(document).ready(function() {
createModal();
createRadioButtons();
$('#start-button').click(function() {
$('#starter-info').addClass('d-none');
loadCustomer();
});
$('#start-asking').click(function() {
$('#customer-answer').addClass('d-none');
$('#question-list').removeClass('d-none');
$('#start-asking').addClass('d-none');
$('#num-qs-asked-text').addClass('d-none');
});
$('#question-list p').click(askQuestion);
$('#bake-cake').click(getCakeCreated);
$('#next-customer').click(loadCustomer);
$('#restart').click(function() {
bakerySim.currentCustomer = 1;
loadCustomer();
});
});


/**
* Reset variables and the content displayed for new customer
*/
function loadCustomer() {
bakerySim.numQuestionsAsked = 0;
$('#num-qs-asked-text').html(CONFIG.NUM_QS_COUNT_TEXT);
$('#background-image').attr('src', bakerySimImages['customer-' + bakerySim.currentCustomer]);
$('#customer-answer').text(CONFIG.CUSTOMER_INTRO).removeClass('d-none');
$('#dialogue-box').removeClass('d-none');
$('#start-asking').removeClass('d-none');
$('#result-table').addClass('d-none');
$('.table-row').remove();
$('#next-customer').addClass('d-none');
$('#restart').addClass('d-none');
$('#question-list p').removeClass('d-none');
}


/**
* Show the customer's answer to question selected
*/
function askQuestion() {
questionID = $(this).attr('id');
$('#question-list').addClass('d-none');
if (bakerySim.currentCustomer == 1) {
$('#customer-answer').text(CONFIG.CUSTOMER_1_ANS[questionID]).removeClass('d-none');
} else if (bakerySim.currentCustomer == 2) {
$('#customer-answer').text(CONFIG.CUSTOMER_2_ANS[questionID]).removeClass('d-none');
} else if (bakerySim.currentCustomer == 3) {
$('#customer-answer').text(CONFIG.CUSTOMER_3_ANS[questionID]).removeClass('d-none');
}

bakerySim.numQuestionsAsked += 1
$('#num-asked').text(bakerySim.numQuestionsAsked);
// hide question so it cannot be asked again
$(this).addClass('d-none');

if (bakerySim.numQuestionsAsked == 6) {
$('#question-list').addClass('d-none');
$('#start-asking').addClass('d-none');
$('#num-qs-asked-text').text(CONFIG.QUESTIONS_MAX_REACHED);
$('#time-to-bake').removeClass('d-none');
} else {
$('#num-qs-asked-text').removeClass('d-none');
$('#start-asking').removeClass('d-none');
}
}


/**
* Check user's cake against what the customer wanted
*/
function checkResult(cakeCreated) {
if (bakerySim.currentCustomer == 1) {
var cakeWanted = CONFIG.CUSTOMER_1_CAKE;
} else if (bakerySim.currentCustomer == 2) {
var cakeWanted = CONFIG.CUSTOMER_2_CAKE;
} else if (bakerySim.currentCustomer == 3) {
var cakeWanted = CONFIG.CUSTOMER_3_CAKE;
}

createResultTable(cakeWanted, cakeCreated);
$('#result-table').removeClass('d-none');
}


/**
* Get values user selected from radio buttons
*/
function getCakeCreated() {
$('#dialogue-box').addClass('d-none');
$('#time-to-bake').addClass('d-none');
var cakeCreated = {};
// loop through each option and get selected value
for (i=0; i < CONFIG.FIELD_NAMES.length; i++) {
var name = CONFIG.FIELD_NAMES[i];
var selected = $('.active input[name=' + name + ']').serialize();
// decorations can have multiple options selected
if (name === 'decorations') {
var decorations = [];
var values = selected.split('&');
for (j=0; j < values.length; j++) {
value = values[j].split('=')[1];
decorations.push(value);
}
cakeCreated[name] = decorations;
} else {
// is not the decorations field
var value = selected.split('=')[1];
cakeCreated[name] = value;
}
}
checkResult(cakeCreated);
}


/**
* Create modal that contains radio buttons for creating cake
*/
function createModal() {
var $modalContainer = $('<div>').addClass('modal').attr({
id: 'baking-options',
tabindex: '-1',
role: 'dialog',
});
var $modalDialog = $('<div>').addClass('modal-dialog modal-lg').attr('role', 'document');
var $modalContent = $('<div>').addClass('modal-content');
var $modalHeader = $('<div>').addClass('modal-header');
var $modalTitle = $('<div>').addClass('modal-title').text(CONFIG.MODAL_TITLE);
var $modalBody = $('<div>').addClass('modal-body text-left').attr('id', 'modal-body');
var $modalFooter = $('<div>').addClass('modal-footer');
var $bakeButton = $('<button>').addClass('btn btn-success').text(gettext('Bake!'));
$bakeButton.attr({
'data-dismiss': 'modal',
'id': 'bake-cake',
});
$modalContainer.append($modalDialog);
$modalDialog.append($modalContent);
$modalContent.append($modalHeader);
$modalHeader.append($modalTitle);
$modalContent.append($modalBody);
$modalContent.append($modalFooter);
$modalFooter.append($bakeButton);
$('#bakery-simulator-container').append($modalContainer);
}


/**
* Create radio buttons for each cake option
*/
function createRadioButtons() {
for (i=0; i < CONFIG.FIELD_OPTIONS.length; i++) {
var option = CONFIG.FIELD_OPTIONS[i];
var $container = $('<div>').addClass('mb-2 col-8').attr('id', option.name + '-radio');
var $title = $('<p>').addClass('d-inline text-left').text(option.title);
$container.append($title);
var $buttonGroup = $('<div>').addClass('btn-group btn-group-toggle').attr('data-toggle', 'buttons');
$container.append($buttonGroup);
// start iterating
for (j=0; j < option.values.length; j++) {
var value = option.values[j];
// shorthand if statement means if it is first radio option make it active
var $radioLabel = $('<label>').text(value).addClass('btn btn-secondary' + ((j == 0) ? ' active' : ''));
var $radioInput = $('<input>').attr({
type: (option.name === 'decorations' ? 'checkbox' : 'radio'),
name: option.name,
value: value,
id: option.name + '-' + value.toLowerCase(),
autocomplete: 'off',
});
// If first radio button add checked attr
if (j == 0) {
$radioInput.attr('checked', 'checked');
}
$radioLabel.append($radioInput);
$buttonGroup.append($radioLabel);
}
$('#modal-body').append($container);
}
}


/**
* Create a table comparing what the customer wanted to what the user selected.
* Background of table row will be green if correct, red if incorrect.
*/
function createResultTable(cakeWanted, cakeCreated) {
var $table = $('#result-table')
for (i=0; i < CONFIG.FIELD_OPTIONS.length; i++) {
fieldDictionary = CONFIG.FIELD_OPTIONS[i];
title = fieldDictionary.title.slice(0, -1); // remove ':' from the title
field = fieldDictionary.name;
var $tbody = $('<tbody>').addClass('table-row');
var $tr = $('<tr>');
var $th = $('<th>').attr('scope', 'row').text(title); // already translated??
var $tdWanted = $('<td>').text(cakeWanted[field]); // already translated??
var $tdCreated = $('<td>').text(cakeCreated[field]); // already translated??
$table.append($tbody);
$tbody.append($tr);
$tr.append($th, $tdWanted, $tdCreated);
// if correct add green background, if incorrect add red background
// if is an array (e.g decorations) calculate set differences
if ($.isArray(cakeWanted[field])) {
var cakeWantedSet = new Set(cakeWanted[field]);
var cakeCreatedSet = new Set(cakeCreated[field]);
var inWantedNotCreated = setDifference(cakeWantedSet, cakeCreatedSet);
var inCreatedNotWanted = setDifference(cakeCreatedSet, cakeWantedSet);
if (inWantedNotCreated.size == 0 && inCreatedNotWanted.size == 0) {
$tr.addClass('correct');
} else {
$tr.addClass('incorrect');
}
}
else if (cakeWanted[field] === cakeCreated[field]) {
$tr.addClass('correct');
} else {
$tr.addClass('incorrect');
}
}
bakerySim.currentCustomer += 1; // should put this somewhere else
// if customer num == 4 (3 is the last customer) show end button not next customer button
if (bakerySim.currentCustomer == 4) {
$('#next-customer').addClass('d-none');
$('#restart').removeClass('d-none');
} else {
$('#next-customer').removeClass('d-none');
}
}


/**
* Calulate a\b
* E.g if a = {1,2,3,4} and b = {5,4,3,2} this function would return {1}
*/
function setDifference(a, b) {
var aMinusB = new Set([...a].filter(x => !b.has(x)));
return aMinusB;
}

Loading