mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2025-02-17 08:50:58 -05:00
Started implementing web-dev goals
This commit is contained in:
parent
69f21514b9
commit
c44c16e5d2
5 changed files with 93 additions and 7 deletions
|
@ -14,18 +14,20 @@ function receiveMessage(event) {
|
||||||
switch (event.data.type) {
|
switch (event.data.type) {
|
||||||
case 'create':
|
case 'create':
|
||||||
create(event.data.dom);
|
create(event.data.dom);
|
||||||
|
checkGoals(event.data.goals);
|
||||||
break;
|
break;
|
||||||
case 'update':
|
case 'update':
|
||||||
if (virtualDOM)
|
if (virtualDOM)
|
||||||
update(event.data.dom);
|
update(event.data.dom);
|
||||||
else
|
else
|
||||||
create(event.data.dom);
|
create(event.data.dom);
|
||||||
|
checkGoals(event.data.goals);
|
||||||
break;
|
break;
|
||||||
case 'log':
|
case 'log':
|
||||||
console.log(event.data.text);
|
console.log(event.data.text);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('Unknown message type:', event.data.type);
|
console.log('Unknown message type:', event.data.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
//event.source.postMessage("hi there yourself! the secret response is: rheeeeet!", event.origin);
|
//event.source.postMessage("hi there yourself! the secret response is: rheeeeet!", event.origin);
|
||||||
|
@ -45,3 +47,73 @@ function update(dom) {
|
||||||
changes.reduce(deku.dom.update(dispatch, context), concreteDOM) // Rerender
|
changes.reduce(deku.dom.update(dispatch, context), concreteDOM) // Rerender
|
||||||
virtualDOM = event.data.dom;
|
virtualDOM = event.data.dom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkGoals(goals) {
|
||||||
|
goals.forEach(function(goal) {
|
||||||
|
var $result = $(goal.html.selector);
|
||||||
|
//console.log('ran selector', goal.html.selector, 'to find element(s)', $result);
|
||||||
|
var success = true;
|
||||||
|
goal.html.valueChecks.forEach(function(check) {
|
||||||
|
//console.log(' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps'), '?', matchesCheck($result, check))
|
||||||
|
success = success && matchesCheck($result, check)
|
||||||
|
});
|
||||||
|
console.log('HTML', goal.id, '-', goal.name, '- succeeds?', success)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function downTheChain(obj, keyChain) {
|
||||||
|
if (!obj)
|
||||||
|
return null;
|
||||||
|
if (!_.isArray(keyChain))
|
||||||
|
return obj[keyChain];
|
||||||
|
var value = obj;
|
||||||
|
while (keyChain.length && value) {
|
||||||
|
if (keyChain[0].match(/\(.*\)$/)) {
|
||||||
|
var args, argsString = keyChain[0].match(/\((.*)\)$/)[1];
|
||||||
|
if (argsString)
|
||||||
|
args = eval(argsString).split(/, ?/g).filter(function(x) { return x !== ""; }); // TODO: can/should we avoid eval here?
|
||||||
|
else
|
||||||
|
args = [];
|
||||||
|
value = value[keyChain[0].split('(')[0]].apply(value, args); // value.text(), value.css('background-color'), etc.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value = value[keyChain[0]];
|
||||||
|
keyChain = keyChain.slice(1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
function matchesCheck(value, check) {
|
||||||
|
var v = downTheChain(value, check.eventProps);
|
||||||
|
if ((check.equalTo != null) && v !== check.equalTo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.notEqualTo != null) && v === check.notEqualTo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.greaterThan != null) && !(v > check.greaterThan)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.greaterThanOrEqualTo != null) && !(v >= check.greaterThanOrEqualTo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.lessThan != null) && !(v < check.lessThan)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.lessThanOrEqualTo != null) && !(v <= check.lessThanOrEqualTo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.containingString != null) && (!v || v.search(check.containingString) === -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.notContainingString != null) && (v != null ? v.search(check.notContainingString) : void 0) !== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.containingRegexp != null) && (!v || v.search(new RegExp(check.containingRegexp)) === -1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((check.notContainingRegexp != null) && (v != null ? v.search(new RegExp(check.notContainingRegexp)) : void 0) !== -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
subscriptions:
|
subscriptions:
|
||||||
'god:new-world-created': 'onNewWorldCreated'
|
'god:new-world-created': 'onNewWorldCreated'
|
||||||
'level:restarted': 'onLevelRestarted'
|
'level:restarted': 'onLevelRestarted'
|
||||||
|
#'tome:html-updated': 'onHTMLUpdated'
|
||||||
|
|
||||||
backgroundSubscriptions:
|
backgroundSubscriptions:
|
||||||
'world:thang-died': 'onThangDied'
|
'world:thang-died': 'onThangDied'
|
||||||
|
@ -114,7 +115,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
goalStates: @goalStates
|
goalStates: @goalStates
|
||||||
goals: @goals
|
goals: @goals
|
||||||
overallStatus: overallStatus
|
overallStatus: overallStatus
|
||||||
timedOut: @world.totalFrames is @world.maxTotalFrames and overallStatus not in ['success', 'failure']
|
timedOut: @world? and (@world.totalFrames is @world.maxTotalFrames and overallStatus not in ['success', 'failure'])
|
||||||
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
Backbone.Mediator.publish('goal-manager:new-goal-states', event)
|
||||||
|
|
||||||
checkOverallStatus: (ignoreIncomplete=false) ->
|
checkOverallStatus: (ignoreIncomplete=false) ->
|
||||||
|
@ -220,6 +221,11 @@ module.exports = class GoalManager extends CocoClass
|
||||||
return unless linesAllowed = who[thang.id] ? who[thang.team]
|
return unless linesAllowed = who[thang.id] ? who[thang.team]
|
||||||
@updateGoalState goalID, thang.id, 'lines', frameNumber if linesUsed > linesAllowed
|
@updateGoalState goalID, thang.id, 'lines', frameNumber if linesUsed > linesAllowed
|
||||||
|
|
||||||
|
#checkHTML: (goal, html) ->
|
||||||
|
# console.log 'should run selector', goal.html.selector, 'to find element(s)'
|
||||||
|
# console.log ' ... and should make sure that the value of', check.eventProps, 'is', _.omit(check, 'eventProps') for check in goal.html.valueChecks
|
||||||
|
# console.log 'should do it with cheerio', window.cheerio
|
||||||
|
|
||||||
wrapUpGoalStates: (finalFrame) ->
|
wrapUpGoalStates: (finalFrame) ->
|
||||||
for goalID, state of @goalStates
|
for goalID, state of @goalStates
|
||||||
if state.status is null
|
if state.status is null
|
||||||
|
@ -264,7 +270,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
||||||
victory = overallStatus is 'success'
|
victory = overallStatus is 'success'
|
||||||
tentative = overallStatus is 'success'
|
tentative = overallStatus is 'success'
|
||||||
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
@world?.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||||
|
|
||||||
updateGoalState: (goalID, thangID, progressObjectName, frameNumber) ->
|
updateGoalState: (goalID, thangID, progressObjectName, frameNumber) ->
|
||||||
# A thang has done something related to the goal!
|
# A thang has done something related to the goal!
|
||||||
|
@ -291,7 +297,7 @@ module.exports = class GoalManager extends CocoClass
|
||||||
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
mostEagerGoal = _.min matchedGoals, 'worldEndsAfter'
|
||||||
victory = overallStatus is 'success'
|
victory = overallStatus is 'success'
|
||||||
tentative = overallStatus is 'success'
|
tentative = overallStatus is 'success'
|
||||||
@world.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
@world?.endWorld victory, mostEagerGoal.worldEndsAfter, tentative if mostEagerGoal isnt Infinity
|
||||||
|
|
||||||
goalIsPositive: (goalID) ->
|
goalIsPositive: (goalID) ->
|
||||||
# Positive goals are completed when all conditions are true (kill all these thangs)
|
# Positive goals are completed when all conditions are true (kill all these thangs)
|
||||||
|
@ -314,6 +320,9 @@ module.exports = class GoalManager extends CocoClass
|
||||||
linesOfCode: 0
|
linesOfCode: 0
|
||||||
codeProblems: 0
|
codeProblems: 0
|
||||||
|
|
||||||
|
#onHTMLUpdated: (e) ->
|
||||||
|
# @checkHTML goal, e.html for goal in @goals when goal.html
|
||||||
|
|
||||||
updateCodeGoalStates: ->
|
updateCodeGoalStates: ->
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,9 @@ GoalSchema = c.object {title: 'Goal', description: 'A goal that the player can a
|
||||||
targets: c.array {title: 'Targets', description: 'The target items which the Thangs must not collect.', minItems: 1}, thang
|
targets: c.array {title: 'Targets', description: 'The target items which the Thangs must not collect.', minItems: 1}, thang
|
||||||
codeProblems: c.array {title: 'Code Problems', description: 'A list of Thang IDs that should not have any code problems, or team names.', uniqueItems: true, minItems: 1, 'default': ['humans']}, thang
|
codeProblems: c.array {title: 'Code Problems', description: 'A list of Thang IDs that should not have any code problems, or team names.', uniqueItems: true, minItems: 1, 'default': ['humans']}, thang
|
||||||
linesOfCode: {title: 'Lines of Code', description: 'A mapping of Thang IDs or teams to how many many lines of code should be allowed (well, statements).', type: 'object', default: {humans: 10}, additionalProperties: {type: 'integer', description: 'How many lines to allow for this Thang.'}}
|
linesOfCode: {title: 'Lines of Code', description: 'A mapping of Thang IDs or teams to how many many lines of code should be allowed (well, statements).', type: 'object', default: {humans: 10}, additionalProperties: {type: 'integer', description: 'How many lines to allow for this Thang.'}}
|
||||||
|
html: c.object {title: 'HTML', description: 'A jQuery selector and what its result should be'},
|
||||||
|
selector: {type: 'string', description: 'jQuery selector to run on the user HTML, like "h1:first-child"'}
|
||||||
|
valueChecks: c.array {title: 'Value checks', description: 'Logical checks on the resulting value for this goal to pass.', format: 'event-prereqs'}, EventPrereqSchema
|
||||||
|
|
||||||
ResponseSchema = c.object {title: 'Dialogue Button', description: 'A button to be shown to the user with the dialogue.', required: ['text']},
|
ResponseSchema = c.object {title: 'Dialogue Button', description: 'A button to be shown to the user with the dialogue.', required: ['text']},
|
||||||
text: {title: 'Title', description: 'The text that will be on the button', 'default': 'Okay', type: 'string', maxLength: 30}
|
text: {title: 'Title', description: 'The text that will be on the button', 'default': 'Okay', type: 'string', maxLength: 30}
|
||||||
|
|
|
@ -269,7 +269,7 @@ module.exports = class PlayLevelView extends RootView
|
||||||
@insertSubView new DuelStatsView level: @level, session: @session, otherSession: @otherSession, supermodel: @supermodel, thangs: @world.thangs if @level.isType('hero-ladder', 'course-ladder')
|
@insertSubView new DuelStatsView level: @level, session: @session, otherSession: @otherSession, supermodel: @supermodel, thangs: @world.thangs if @level.isType('hero-ladder', 'course-ladder')
|
||||||
@insertSubView @controlBar = new ControlBarView {worldName: utils.i18n(@level.attributes, 'name'), session: @session, level: @level, supermodel: @supermodel, courseID: @courseID, courseInstanceID: @courseInstanceID}
|
@insertSubView @controlBar = new ControlBarView {worldName: utils.i18n(@level.attributes, 'name'), session: @session, level: @level, supermodel: @supermodel, courseID: @courseID, courseInstanceID: @courseInstanceID}
|
||||||
@insertSubView @hintsView = new HintsView({ @session, @level, @hintsState }), @$('.hints-view')
|
@insertSubView @hintsView = new HintsView({ @session, @level, @hintsState }), @$('.hints-view')
|
||||||
@insertSubView @webSurface = new WebSurfaceView level: @level if @level.isType('web-dev')
|
@insertSubView @webSurface = new WebSurfaceView {level: @level, @goalManager} if @level.isType('web-dev')
|
||||||
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
|
#_.delay (=> Backbone.Mediator.publish('level:set-debug', debug: true)), 5000 if @isIPadApp() # if me.displayName() is 'Nick'
|
||||||
|
|
||||||
initVolume: ->
|
initVolume: ->
|
||||||
|
|
|
@ -12,6 +12,8 @@ module.exports = class WebSurfaceView extends CocoView
|
||||||
initialize: (options) ->
|
initialize: (options) ->
|
||||||
@state = new State
|
@state = new State
|
||||||
blah: 'blah'
|
blah: 'blah'
|
||||||
|
@goals = (goal for goal in options.goalManager.goals when goal.html)
|
||||||
|
# Consider https://www.npmjs.com/package/css-select to do this on virtualDOM instead of in iframe on concreteDOM
|
||||||
super(options)
|
super(options)
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
@ -34,7 +36,7 @@ module.exports = class WebSurfaceView extends CocoView
|
||||||
# TODO: pull out the actual scripts, styles, and body/elements they are doing so we can merge them with our initial structure on the other side
|
# TODO: pull out the actual scripts, styles, and body/elements they are doing so we can merge them with our initial structure on the other side
|
||||||
virtualDOM = @dekuify html
|
virtualDOM = @dekuify html
|
||||||
messageType = if e.create or not @virtualDOM then 'create' else 'update'
|
messageType = if e.create or not @virtualDOM then 'create' else 'update'
|
||||||
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM}, '*'
|
@iframe.contentWindow.postMessage {type: messageType, dom: virtualDOM, goals: @goals}, '*'
|
||||||
@virtualDOM = virtualDOM
|
@virtualDOM = virtualDOM
|
||||||
|
|
||||||
checkGoals: (dom) ->
|
checkGoals: (dom) ->
|
||||||
|
|
Loading…
Reference in a new issue