From 529dd75f1e50078bc2d9f2c1fa29b6b70760f5f6 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 26 Jan 2023 13:30:22 -0600 Subject: [PATCH 01/37] Finished JBC1 Challenge --- src/challenges/jbc1.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/challenges/jbc1.ts b/src/challenges/jbc1.ts index 19b4d4e7..32348365 100644 --- a/src/challenges/jbc1.ts +++ b/src/challenges/jbc1.ts @@ -18,7 +18,7 @@ export default { }, defaultLanguage: 'c', events: { - canATouched: { + can9Touched: { name: { [LocalizedString.EN_US]: 'Can A Touched' }, description: { [LocalizedString.EN_US]: 'Can A touched' }, }, @@ -44,10 +44,11 @@ export default { success: { exprs: { // Touch Events - canATouched: { + can9Touched: { type: Expr.Type.Event, - eventId: 'canATouched', + eventId: 'can9Touched', }, + // Intersects Events canAIntersects: { type: Expr.Type.Event, @@ -81,7 +82,7 @@ export default { - boxStuff:{ + startingBox:{ type:Expr.Type.And, argIds:['leaveStartBoxOnce', 'returnStartBoxOnce'], }, @@ -95,7 +96,7 @@ export default { //Success Logic = Can A upright, intersects and touched completion: { type: Expr.Type.And, - argIds: ['canATouched', 'aIntersectsUpright', 'boxStuff'], + argIds: ['can9Touched', 'aIntersectsUpright', 'startingBox'], }, }, rootId: 'completion', From 24afecb58679afc2be74d402cc069fadef4c626f Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 26 Jan 2023 13:43:39 -0600 Subject: [PATCH 02/37] Added End Challenge button in challenge view --- src/components/ChallengeMenu.tsx | 9 ++++++++- src/components/ChallengeRoot.tsx | 5 +++++ src/components/SimMenu.tsx | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/ChallengeMenu.tsx b/src/components/ChallengeMenu.tsx index cffd9d24..009b291d 100644 --- a/src/components/ChallengeMenu.tsx +++ b/src/components/ChallengeMenu.tsx @@ -60,6 +60,7 @@ export interface MenuProps extends StyleProps, ThemeProps { onDashboardClick: () => void; onLogoutClick: () => void; + onEndChallengeClick: () => void; simulatorState: SimulatorState; } @@ -72,7 +73,7 @@ type State = MenuState; import KIPR_LOGO_BLACK from '../assets/KIPR-Logo-Black-Text-Clear-Large.png'; import KIPR_LOGO_WHITE from '../assets/KIPR-Logo-White-Text-Clear-Large.png'; -import { faBars, faBook, faClone, faCogs, faCommentDots, faGlobeAmericas, faPlay, faQuestion, faSignOutAlt, faStop, faSync } from '@fortawesome/free-solid-svg-icons'; +import { faBars, faFlagCheckered, faBook, faClone, faCogs, faCommentDots, faGlobeAmericas, faPlay, faQuestion, faSignOutAlt, faStop, faSync } from '@fortawesome/free-solid-svg-icons'; import SceneMenu from './World/SceneMenu'; import ExtraMenu from './ExtraMenu'; @@ -226,6 +227,7 @@ class ChallengeMenu extends React.PureComponent { onDocumentationClick, onDashboardClick, onLogoutClick, + onEndChallengeClick, simulatorState } = props; @@ -263,6 +265,11 @@ class ChallengeMenu extends React.PureComponent { + + End Challenge + + + Layout {subMenu.type === SubMenu.Type.LayoutPicker ? ( diff --git a/src/components/ChallengeRoot.tsx b/src/components/ChallengeRoot.tsx index 24a65f22..db2e5eda 100644 --- a/src/components/ChallengeRoot.tsx +++ b/src/components/ChallengeRoot.tsx @@ -823,6 +823,10 @@ class Root extends React.Component { }); }; + private onEndChallengeClick_ = () => { + window.location.href = `/scene/${this.props.match.params.challengeId}`; + }; + private onResetCode_ = () => { const { challenge } = this.props; if (!challenge) return; @@ -960,6 +964,7 @@ class Root extends React.Component { onDocumentationClick={this.onDocumentationClick} onDashboardClick={this.onDashboardClick} onLogoutClick={this.onLogoutClick} + onEndChallengeClick={this.onEndChallengeClick_} simulatorState={simulatorState} /> {impl} diff --git a/src/components/SimMenu.tsx b/src/components/SimMenu.tsx index 95ab080f..aa64bf61 100644 --- a/src/components/SimMenu.tsx +++ b/src/components/SimMenu.tsx @@ -98,6 +98,7 @@ import { faSignOutAlt, faFlagCheckered, faStop, + faFlag, faSync, } from "@fortawesome/free-solid-svg-icons"; import SceneMenu from "./World/SceneMenu"; @@ -350,7 +351,7 @@ class SimMenu extends React.PureComponent { onClick={onStartChallengeClick} style={{ position: "relative" }} > - Start Challenge + Start Challenge Date: Fri, 27 Jan 2023 10:35:06 -0600 Subject: [PATCH 03/37] Implemented JBC2 challenge logic with testing --- src/challenges/jbc2.ts | 162 +++++++++++++++++ src/scenes/jbc1.ts | 4 - src/scenes/jbc2.ts | 304 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 6 +- 4 files changed, 463 insertions(+), 13 deletions(-) create mode 100644 src/challenges/jbc2.ts diff --git a/src/challenges/jbc2.ts b/src/challenges/jbc2.ts new file mode 100644 index 00000000..22fad48e --- /dev/null +++ b/src/challenges/jbc2.ts @@ -0,0 +1,162 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 2" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 2: Ring Around the Can`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can6Touched: { + name: { [LocalizedString.EN_US]: "Can 6 Touched" }, + description: { [LocalizedString.EN_US]: "Can 6 touched" }, + }, + can6Intersects: { + name: { [LocalizedString.EN_US]: "Can 6 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 6 intersects circle 6" }, + }, + + can6Upright: { + name: { [LocalizedString.EN_US]: "Can 6 Upright" }, + description: { [LocalizedString.EN_US]: "Can 6 upright on circle 6" }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + + rightSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed right side of can 6", + }, + }, + + topSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Top Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed top side of can 6", + }, + }, + + leftSide: { + name: { [LocalizedString.EN_US]: "Robot Passed left Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed left side of can 6", + }, + }, + }, + success: { + exprs: { + // Touch Events + can6Touched: { + type: Expr.Type.Event, + eventId: "can6Touched", + }, + can6NotTouched: { + type: Expr.Type.Not, + argId: "can6Touched", + }, + + //Passing side events + rightSide: { + type: Expr.Type.Event, + eventId: "rightSide", + }, + rightSideOnce: { + type: Expr.Type.Once, + argId: "rightSide", + }, + topSide: { + type: Expr.Type.Event, + eventId: "topSide", + }, + topSideOnce: { + type: Expr.Type.Once, + argId: "topSide", + }, + leftSide: { + type: Expr.Type.Event, + eventId: "leftSide", + }, + leftSideOnce: { + type: Expr.Type.Once, + argId: "leftSide", + }, + + // Intersects Events + can6Intersects: { + type: Expr.Type.Event, + eventId: "can6Intersects", + }, + + //Upright Events + can6Upright: { + type: Expr.Type.Event, + eventId: "can6Upright", + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUpright: { + type: Expr.Type.And, + argIds: ["can6Intersects", "can6Upright"], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + "can6NotTouched", + "IntersectsUpright", + "startingBox", + "rightSideOnce", + "topSideOnce", + "leftSideOnce" + ], + }, + }, + rootId: "completion", + }, + sceneId: "jbc2", +} as Challenge; diff --git a/src/scenes/jbc1.ts b/src/scenes/jbc1.ts index a54569cd..2477c8e8 100644 --- a/src/scenes/jbc1.ts +++ b/src/scenes/jbc1.ts @@ -110,10 +110,6 @@ export const JBC_1: Scene = { z: Distance.centimeters(0), }, }, - - - - }, nodes: { diff --git a/src/scenes/jbc2.ts b/src/scenes/jbc2.ts index 97fa45d5..e7c24de3 100644 --- a/src/scenes/jbc2.ts +++ b/src/scenes/jbc2.ts @@ -1,16 +1,304 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; const baseScene = createBaseSceneSurfaceA(); +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can6) is intersecting circle6, the circle glows + +scene.addOnIntersectionListener('can6', (type, otherNodeId) => { + console.log('Can 6 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can6Intersects', visible); + setNodeVisible('circle6', visible); +}, 'circle6'); + +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; +const robotTouches = ` +scene.onBind = nodeId => { + scene.addOnCollisionListener(nodeId, (otherNodeId, point)=> { + console.log('Can 6 touched!', otherNodeId, point); + scene.setChallengeEventValue(nodeId + 'Touched', true); + }, 'robot'); +}; +`; +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const passedSide = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + switch(otherNodeId){ + case 'rightSideCan': + console.log('Robot passed the right side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('rightSide', type === 'start'); + } + break; + case 'topSideCan': + console.log('Robot passed the top side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('topSide', type === 'start'); + } + break; + case 'leftSideCan': + console.log('Robot passed the left side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leftSide', type === 'start'); + } + break; + } +}, ['rightSideCan', 'topSideCan', 'leftSideCan']); + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +// let startTime = Date.now(); +const EULER_IDENTITY = Rotation.Euler.identity(); +// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright6 = yAngle('can6') < 5; + // if(timeDiff > 1000) { + // console.log('can6 angle: ', yAngle('can6')); + // startTime = currTime; + // } + scene.setChallengeEventValue('can6Upright', upright6); + +}); +`; + export const JBC_2: Scene = { ...baseScene, - name: { [LocalizedString.EN_US]: 'JBC 2' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 2: Ring Around the Can' }, + name: { [LocalizedString.EN_US]: "JBC 2" }, + description: { + [LocalizedString.EN_US]: "Junior Botball Challenge 2: Ring Around the Can", + }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + robotTouches: Script.ecmaScript("Robot Touches", robotTouches), + passedSide: Script.ecmaScript("Passed Side", passedSide), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + + geometry: { + ...baseScene.geometry, + circle6_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + rightSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + + topSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(0.01), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + + leftSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(50), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + }, + nodes: { ...baseScene.nodes, - 'can6': createCanNode(6), - } -}; \ No newline at end of file + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle6: { + type: "object", + geometryId: "circle6_geom", + name: { [LocalizedString.EN_US]: "Circle 6" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + rightSideCan: { + type: "object", + geometryId: "rightSideCan_geom", + name: { [LocalizedString.EN_US]: "Right Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-20), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + topSideCan: { + type: "object", + geometryId: "topSideCan_geom", + name: { [LocalizedString.EN_US]: "Top Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + leftSideCan: { + type: "object", + geometryId: "leftSideCan_geom", + name: { [LocalizedString.EN_US]: "Left Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(52), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can6: { + ...createCanNode(6, { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(57), + }), + scriptIds: ["robotTouches"], + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 09b26d7c..ab1243da 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -14,7 +14,7 @@ import { errorToAsyncError, mutate } from './util'; import test from '../../challenges/test'; import jbc6c from "../../challenges/jbc6c"; import jbc1 from "../../challenges/jbc1"; - +import jbc2 from "../../challenges/jbc2"; export namespace ChallengesAction { export interface LoadChallenge { @@ -130,6 +130,10 @@ const DEFAULT_CHALLENGES: Challenges = { 'jbc1': Async.loaded({ value: jbc1, brief: ChallengeBrief.fromChallenge(jbc1), + }), + 'jbc2': Async.loaded({ + value: jbc2, + brief: ChallengeBrief.fromChallenge(jbc2), }) }; From 070d4bee0064f1bc799debcbff7c56626a0f56e5 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 27 Jan 2023 13:22:30 -0600 Subject: [PATCH 04/37] Implemented JBC2B challenge logic with testing --- src/challenges/jbc2b.ts | 230 ++++++++++++++++++++ src/scenes/jbc2b.ts | 359 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 5 + 3 files changed, 590 insertions(+), 4 deletions(-) create mode 100644 src/challenges/jbc2b.ts diff --git a/src/challenges/jbc2b.ts b/src/challenges/jbc2b.ts new file mode 100644 index 00000000..7d2be495 --- /dev/null +++ b/src/challenges/jbc2b.ts @@ -0,0 +1,230 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 2B" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 2B: Ring Around the Cans, Sr.`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can10Touched: { + name: { [LocalizedString.EN_US]: "Can 10 Touched" }, + description: { [LocalizedString.EN_US]: "Can 10 touched" }, + }, + can11Touched: { + name: { [LocalizedString.EN_US]: "Can 11 Touched" }, + description: { [LocalizedString.EN_US]: "Can 11 touched" }, + }, + can12Touched: { + name: { [LocalizedString.EN_US]: "Can 12 Touched" }, + description: { [LocalizedString.EN_US]: "Can 12 touched" }, + }, + + can10Intersects: { + name: { [LocalizedString.EN_US]: "Can 10 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 10 intersects circle 10" }, + }, + can11Intersects: { + name: { [LocalizedString.EN_US]: "Can 11 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 11 intersects circle 11" }, + }, + can12Intersects: { + name: { [LocalizedString.EN_US]: "Can 12 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 12 intersects circle 12" }, + }, + + can10Upright: { + name: { [LocalizedString.EN_US]: "Can 10 Upright" }, + description: { [LocalizedString.EN_US]: "Can 10 upright on circle 10" }, + }, + can11Upright: { + name: { [LocalizedString.EN_US]: "Can 11 Upright" }, + description: { [LocalizedString.EN_US]: "Can 11 upright on circle 11" }, + }, + can12Upright: { + name: { [LocalizedString.EN_US]: "Can 12 Upright" }, + description: { [LocalizedString.EN_US]: "Can 12 upright on circle 12" }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + + rightSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed right side of can 12", + }, + }, + + topSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Top Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed top side of can 11", + }, + }, + + leftSide: { + name: { [LocalizedString.EN_US]: "Robot Passed left Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed left side of can 10", + }, + }, + }, + success: { + exprs: { + // Touch Events + can10Touched: { + type: Expr.Type.Event, + eventId: "can10Touched", + }, + can10NotTouched: { + type: Expr.Type.Not, + argId: "can10Touched", + }, + can11Touched: { + type: Expr.Type.Event, + eventId: "can11Touched", + }, + can11NotTouched: { + type: Expr.Type.Not, + argId: "can11Touched", + }, + can12Touched: { + type: Expr.Type.Event, + eventId: "can12Touched", + }, + can12NotTouched: { + type: Expr.Type.Not, + argId: "can12Touched", + }, + cansNotTouched: { + type: Expr.Type.And, + argIds: ["can10NotTouched", "can11NotTouched", "can12NotTouched"], + }, + + //Passing side events + rightSide: { + type: Expr.Type.Event, + eventId: "rightSide", + }, + rightSideOnce: { + type: Expr.Type.Once, + argId: "rightSide", + }, + topSide: { + type: Expr.Type.Event, + eventId: "topSide", + }, + topSideOnce: { + type: Expr.Type.Once, + argId: "topSide", + }, + leftSide: { + type: Expr.Type.Event, + eventId: "leftSide", + }, + leftSideOnce: { + type: Expr.Type.Once, + argId: "leftSide", + }, + + // Intersects Events + can10Intersects: { + type: Expr.Type.Event, + eventId: "can10Intersects", + }, + can11Intersects: { + type: Expr.Type.Event, + eventId: "can11Intersects", + }, + can12Intersects: { + type: Expr.Type.Event, + eventId: "can12Intersects", + }, + cansIntersects: { + type: Expr.Type.And, + argIds: ["can10Intersects", "can11Intersects", "can12Intersects"], + }, + + //Upright Events + can10Upright: { + type: Expr.Type.Event, + eventId: "can10Upright", + }, + can11Upright: { + type: Expr.Type.Event, + eventId: "can11Upright", + }, + can12Upright: { + type: Expr.Type.Event, + eventId: "can12Upright", + }, + cansUpright: { + type: Expr.Type.And, + argIds: ["can10Upright", "can11Upright", "can12Upright"], + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUpright: { + type: Expr.Type.And, + argIds: ["cansIntersects", "cansUpright"], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + "cansNotTouched", + "IntersectsUpright", + "startingBox", + "rightSideOnce", + "topSideOnce", + "leftSideOnce", + ], + }, + }, + rootId: "completion", + }, + sceneId: "jbc2b", +} as Challenge; diff --git a/src/scenes/jbc2b.ts b/src/scenes/jbc2b.ts index accad53e..5c52fd95 100644 --- a/src/scenes/jbc2b.ts +++ b/src/scenes/jbc2b.ts @@ -1,18 +1,369 @@ import Scene from "../state/State/Scene"; import LocalizedString from '../util/LocalizedString'; - import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; +import Script from "../state/State/Scene/Script"; + const baseScene = createBaseSceneSurfaceA(); +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can10) is intersecting circle10, the circle glows + +scene.addOnIntersectionListener('can10', (type, otherNodeId) => { + console.log('Can 10 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can10Intersects', visible); + setNodeVisible('circle10', visible); +}, 'circle10'); + +// When the can (can11) is intersecting circle11, the circle glows + +scene.addOnIntersectionListener('can11', (type, otherNodeId) => { + console.log('Can 11 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can11Intersects', visible); + setNodeVisible('circle11', visible); +}, 'circle11'); + + +// When the can (can12) is intersecting circle12, the circle glows + +scene.addOnIntersectionListener('can12', (type, otherNodeId) => { + console.log('Can 12 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can12Intersects', visible); + setNodeVisible('circle12', visible); +}, 'circle12'); +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; +const robotTouches = ` +scene.onBind = nodeId => { + scene.addOnCollisionListener(nodeId, (otherNodeId, point)=> { + console.log(nodeId + 'touched!', otherNodeId, point); + scene.setChallengeEventValue(nodeId + 'Touched', true); + }, 'robot'); +}; +`; +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const passedSide = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + switch(otherNodeId){ + case 'rightSideCan': + console.log('Robot passed the right side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('rightSide', type === 'start'); + } + break; + case 'topSideCan': + console.log('Robot passed the top side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('topSide', type === 'start'); + } + break; + case 'leftSideCan': + console.log('Robot passed the left side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leftSide', type === 'start'); + } + break; + } +}, ['rightSideCan', 'topSideCan', 'leftSideCan']); + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +// let startTime = Date.now(); +const EULER_IDENTITY = Rotation.Euler.identity(); +// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright10 = yAngle('can10') < 5; + const upright11 = yAngle('can11') < 5; + const upright12 = yAngle('can12') < 5; + // if(timeDiff > 1000) { + // console.log('can6 angle: ', yAngle('can6')); + // startTime = currTime; + // } + scene.setChallengeEventValue('can10Upright', upright10); + scene.setChallengeEventValue('can11Upright', upright11); + scene.setChallengeEventValue('can12Upright', upright12); +}); +`; + export const JBC_2B: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 2B' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 2B: Ring Around the Can, Sr.' }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + robotTouches: Script.ecmaScript("Robot Touches", robotTouches), + passedSide: Script.ecmaScript("Passed Side", passedSide), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + geometry: { + ...baseScene.geometry, + circle10_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle11_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle12_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + rightSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + + topSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(0.01), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + + leftSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + }, + nodes: { ...baseScene.nodes, - 'can10': createCanNode(10), - 'can11': createCanNode(11), - 'can12': createCanNode(12), + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle10: { + type: "object", + geometryId: "circle10_geom", + name: { [LocalizedString.EN_US]: "Circle 10" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(19.3), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle11: { + type: "object", + geometryId: "circle11_geom", + name: { [LocalizedString.EN_US]: "Circle 11" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(106.6), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle12: { + type: "object", + geometryId: "circle12_geom", + name: { [LocalizedString.EN_US]: "Circle 12" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-19.2), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + rightSideCan: { + type: "object", + geometryId: "rightSideCan_geom", + name: { [LocalizedString.EN_US]: "Right Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-50), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + topSideCan: { + type: "object", + geometryId: "topSideCan_geom", + name: { [LocalizedString.EN_US]: "Top Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + leftSideCan: { + type: "object", + geometryId: "leftSideCan_geom", + name: { [LocalizedString.EN_US]: "Left Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(50), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + ...baseScene.nodes, + 'can10': {...createCanNode(10), scriptIds: ["robotTouches"]}, + 'can11': {...createCanNode(11), scriptIds: ["robotTouches"]}, + 'can12': {...createCanNode(12), scriptIds: ["robotTouches"]}, } }; \ No newline at end of file diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index ab1243da..51dcd84a 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -15,6 +15,7 @@ import test from '../../challenges/test'; import jbc6c from "../../challenges/jbc6c"; import jbc1 from "../../challenges/jbc1"; import jbc2 from "../../challenges/jbc2"; +import jbc2b from "../../challenges/jbc2b"; export namespace ChallengesAction { export interface LoadChallenge { @@ -134,6 +135,10 @@ const DEFAULT_CHALLENGES: Challenges = { 'jbc2': Async.loaded({ value: jbc2, brief: ChallengeBrief.fromChallenge(jbc2), + }), + 'jbc2b': Async.loaded({ + value: jbc2b, + brief: ChallengeBrief.fromChallenge(jbc2b), }) }; From 3cfc80ca47a1b3984d0b18b6ce9c09c10b472282 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 30 Jan 2023 09:18:16 -0600 Subject: [PATCH 05/37] Started JBC6 Challenge --- src/challenges/jbc6.ts | 97 +++++++++++++++ src/scenes/jbc6.ts | 209 ++++++++++++++++++++++++++++++-- src/state/reducer/challenges.ts | 6 + 3 files changed, 302 insertions(+), 10 deletions(-) create mode 100644 src/challenges/jbc6.ts diff --git a/src/challenges/jbc6.ts b/src/challenges/jbc6.ts new file mode 100644 index 00000000..96ab7364 --- /dev/null +++ b/src/challenges/jbc6.ts @@ -0,0 +1,97 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 6" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 6: Load 'Em Up`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can2Upright: { + name: { [LocalizedString.EN_US]: "Can 2 Upright" }, + description: { [LocalizedString.EN_US]: "Can 2 upright" }, + }, + can9Upright: { + name: { [LocalizedString.EN_US]: "Can 9 Upright" }, + description: { [LocalizedString.EN_US]: "Can 9 upright" }, + }, + can10Upright: { + name: { [LocalizedString.EN_US]: "Can 10 Upright" }, + description: { [LocalizedString.EN_US]: "Can 10 upright" }, + }, + + can2Intersects: { + name: { [LocalizedString.EN_US]: "Can 2 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 2 intersects green garage" }, + }, + can9Intersects: { + name: { [LocalizedString.EN_US]: "Can 9 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 9 intersects blue garage" }, + }, + can10Intersects: { + name: { [LocalizedString.EN_US]: "Can 10 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 10 intersects yellow garage" }, + }, + }, + success: { + exprs: { + //Upright Events + can2Upright: { + type: Expr.Type.Event, + eventId: "can2Upright", + }, + can9Upright: { + type: Expr.Type.Event, + eventId: "can9Upright", + }, + can10Upright: { + type: Expr.Type.Event, + eventId: "can10Upright", + }, + cansUpright: { + type: Expr.Type.And, + argIds: ["can2Upright", "can9Upright", "can10Upright"], + }, + + + //Intersects Events + can2Intersects: { + type: Expr.Type.Event, + eventId: "can2Intersects", + }, + can9Intersects: { + type: Expr.Type.Event, + eventId: "can9Intersects", + }, + can10Intersects: { + type: Expr.Type.Event, + eventId: "can10Intersects", + }, + cansIntersects: { + type: Expr.Type.And, + argIds: ["can2Intersects", "can9Intersects", "can10Intersects"], + }, + + + // Success logic + completion: { + type: Expr.Type.And, + argIds: ["cansUpright", "cansIntersects"], + }, + }, + rootId: "completion", + }, + sceneId: "jbc6", +} as Challenge; diff --git a/src/scenes/jbc6.ts b/src/scenes/jbc6.ts index 1fd345bf..f7a990eb 100644 --- a/src/scenes/jbc6.ts +++ b/src/scenes/jbc6.ts @@ -1,18 +1,207 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import { createBaseSceneSurfaceA, createCanNode } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; +import Script from "../state/State/Scene/Script"; const baseScene = createBaseSceneSurfaceA(); + +const garageIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can2) is intersecting the green garage, the garage glows + +scene.addOnIntersectionListener('can2', (type, otherNodeId) => { + console.log('Can 2 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can2Intersects', visible); + setNodeVisible('greenGarage', visible); +}, 'greenGarage'); + +// When the can (can9) is intersecting the blue garage, the garage glows + +scene.addOnIntersectionListener('can9', (type, otherNodeId) => { + console.log('Can 9 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can9Intersects', visible); + setNodeVisible('circle9', visible); +}, 'circle9'); + + +// // When the can (can10) is intersecting the yellow garage, the garage glows + +// scene.addOnIntersectionListener('can12', (type, otherNodeId) => { +// console.log('Can 12 placed!', type, otherNodeId); +// const visible = type === 'start'; +// scene.setChallengeEventValue('can12Intersects', visible); +// setNodeVisible('circle12', visible); +// }, 'circle12'); +`; + + +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +// let startTime = Date.now(); +const EULER_IDENTITY = Rotation.Euler.identity(); +// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright2 = yAngle('can2') < 5; + const upright9 = yAngle('can9') < 5; + const upright10 = yAngle('can10') < 5; + // if(timeDiff > 1000) { + // console.log('can6 angle: ', yAngle('can6')); + // startTime = currTime; + // } + scene.setChallengeEventValue('can2Upright', upright2); + scene.setChallengeEventValue('can9Upright', upright9); + scene.setChallengeEventValue('can10Upright', upright10); +}); +`; + export const JBC_6: Scene = { ...baseScene, - name: { [LocalizedString.EN_US]: 'JBC 6' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 6: Load 'Em Up` }, + name: { [LocalizedString.EN_US]: "JBC 6" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 6: Load 'Em Up`, + }, + scripts: { + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + garageIntersects: Script.ecmaScript("Garage Intersects", garageIntersects), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + greenGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(20), + y: Distance.centimeters(0.1), + z: Distance.centimeters(20), + }, + }, + + blueGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(20), + y: Distance.centimeters(0.1), + z: Distance.centimeters(20), + }, + }, + }, nodes: { ...baseScene.nodes, - 'can2': createCanNode(2), - 'can9': createCanNode(9), - 'can10': createCanNode(10), - } -}; \ No newline at end of file + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + greenGarage: { + type: "object", + geometryId: "greenGarage_geom", + name: { [LocalizedString.EN_US]: "Green Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53.2), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + blueGarage: { + type: "object", + geometryId: "blueGarage_geom", + name: { [LocalizedString.EN_US]: "Blue Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53.2), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + ...baseScene.nodes, + can2: createCanNode(2), + can9: createCanNode(9), + can10: createCanNode(10), + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 51dcd84a..03a2226e 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -16,6 +16,8 @@ import jbc6c from "../../challenges/jbc6c"; import jbc1 from "../../challenges/jbc1"; import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; +import jbc6 from "../../challenges/jbc6"; + export namespace ChallengesAction { export interface LoadChallenge { @@ -139,6 +141,10 @@ const DEFAULT_CHALLENGES: Challenges = { 'jbc2b': Async.loaded({ value: jbc2b, brief: ChallengeBrief.fromChallenge(jbc2b), + }), + 'jbc6': Async.loaded({ + value: jbc6, + brief: ChallengeBrief.fromChallenge(jbc6), }) }; From 60ff7b90f2efaf194181ac525ea44de627951fd3 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 30 Jan 2023 11:59:55 -0600 Subject: [PATCH 06/37] Adjusting Blue Garage geom --- src/ScriptManager/index.ts | 4 ++-- src/SharedRegistersRobot.ts | 2 +- src/scenes/jbc6.ts | 38 +++++++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/ScriptManager/index.ts b/src/ScriptManager/index.ts index 010ee322..d788d87b 100644 --- a/src/ScriptManager/index.ts +++ b/src/ScriptManager/index.ts @@ -10,7 +10,7 @@ import { v4 as uuid } from 'uuid'; import construct from '../util/construct'; import { Ids, ScriptSceneBinding } from './ScriptSceneBinding'; import { AxisAngle, Quaternion, ReferenceFrame, Vector3 as RawVector3 } from '../math'; - +import {SharedRegistersRobot} from '../SharedRegistersRobot'; class ScriptManager { private scene_: Scene; @@ -261,7 +261,7 @@ namespace ScriptManager { // eslint-disable-next-line @typescript-eslint/no-implied-eval - new Function("scene, Rotation, AxisAngle, Vector3, Quaternion, ReferenceFrame", `"use strict"; ${this.script_.code}`)(this, Rotation, AxisAngle, RawVector3, Quaternion, ReferenceFrame); + new Function("scene, Rotation, AxisAngle, Vector3, Quaternion, ReferenceFrame, SharedRegistersRobot", `"use strict"; ${this.script_.code}`)(this, Rotation, AxisAngle, RawVector3, Quaternion, ReferenceFrame, SharedRegistersRobot); } get programStatus() { diff --git a/src/SharedRegistersRobot.ts b/src/SharedRegistersRobot.ts index 762ab848..a9c91a44 100644 --- a/src/SharedRegistersRobot.ts +++ b/src/SharedRegistersRobot.ts @@ -6,7 +6,7 @@ import { clamp } from './math'; import RegisterState from './RegisterState'; import SharedRegisters from './SharedRegisters'; -class SharedRegistersRobot implements AbstractRobot { +export class SharedRegistersRobot implements AbstractRobot { private sharedResisters_: SharedRegisters; private static readonly POSITION_GOAL_SCALING = 250; diff --git a/src/scenes/jbc6.ts b/src/scenes/jbc6.ts index f7a990eb..b60194fb 100644 --- a/src/scenes/jbc6.ts +++ b/src/scenes/jbc6.ts @@ -2,8 +2,11 @@ import Scene from "../state/State/Scene"; import LocalizedString from "../util/LocalizedString"; import { createBaseSceneSurfaceA, createCanNode } from "./jbcBase"; import { Color } from "../state/State/Scene/Color"; -import { Distance } from "../util"; +import { Distance , Angle} from "../util"; import Script from "../state/State/Scene/Script"; +import { Euler } from "../math"; +import { Rotation } from "../unit-math"; +import {SharedRegistersRobot} from '../SharedRegistersRobot'; const baseScene = createBaseSceneSurfaceA(); @@ -13,7 +16,7 @@ const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { ...scene.nodes[nodeId], visible }); - +//const sharedRegistersRobot_ = SharedRegistersRobot; // When the can (can2) is intersecting the green garage, the garage glows scene.addOnIntersectionListener('can2', (type, otherNodeId) => { @@ -29,8 +32,8 @@ scene.addOnIntersectionListener('can9', (type, otherNodeId) => { console.log('Can 9 placed!', type, otherNodeId); const visible = type === 'start'; scene.setChallengeEventValue('can9Intersects', visible); - setNodeVisible('circle9', visible); -}, 'circle9'); + setNodeVisible('blueGarage', visible); +}, 'blueGarage'); // // When the can (can10) is intersecting the yellow garage, the garage glows @@ -109,9 +112,9 @@ export const JBC_6: Scene = { blueGarage_geom: { type: "box", size: { - x: Distance.centimeters(20), + x: Distance.centimeters(16), y: Distance.centimeters(0.1), - z: Distance.centimeters(20), + z: Distance.centimeters(18), }, }, }, @@ -167,7 +170,7 @@ export const JBC_6: Scene = { position: { x: Distance.centimeters(0), y: Distance.centimeters(-6.9), - z: Distance.centimeters(53.2), + z: Distance.centimeters(53), }, }, material: { @@ -186,9 +189,16 @@ export const JBC_6: Scene = { visible: false, origin: { position: { - x: Distance.centimeters(0), + x: Distance.centimeters(-13.4), y: Distance.centimeters(-6.9), - z: Distance.centimeters(53.2), + z: Distance.centimeters(94), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(45), + z: Angle.degrees(0), }, }, material: { @@ -200,8 +210,12 @@ export const JBC_6: Scene = { }, }, ...baseScene.nodes, - can2: createCanNode(2), - can9: createCanNode(9), - can10: createCanNode(10), + can2: {...createCanNode(2), scriptIds: ["garageIntersects"]}, + can9: {...createCanNode(9,{ + x: Distance.centimeters(0.3), + y: Distance.centimeters(0), + z: Distance.centimeters(85), + }), scriptIds: ["garageIntersects"]}, + can10: {...createCanNode(10), scriptIds: ["garageIntersects"]}, }, }; From 82ffe6ba862abff62fb84febaefdd5acc165520e Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 7 Feb 2023 08:53:16 -0600 Subject: [PATCH 07/37] Finished JBC7 logic with rough testing. May need further indepth testing for edge case scenarios --- src/ScriptManager/index.ts | 10 +- src/challenges/jbc2c.ts | 158 +++++++++++++++ src/challenges/jbc4.ts | 227 +++++++++++++++++++++ src/challenges/jbc7.ts | 147 ++++++++++++++ src/scenes/jbc2c.ts | 323 ++++++++++++++++++++++++++++- src/scenes/jbc4.ts | 327 +++++++++++++++++++++++++++++- src/scenes/jbc6.ts | 54 +++-- src/scenes/jbc7.ts | 279 +++++++++++++++++++++++-- src/state/State/Challenge/Expr.ts | 2 +- src/state/reducer/challenges.ts | 15 ++ 10 files changed, 1492 insertions(+), 50 deletions(-) create mode 100644 src/challenges/jbc2c.ts create mode 100644 src/challenges/jbc4.ts create mode 100644 src/challenges/jbc7.ts diff --git a/src/ScriptManager/index.ts b/src/ScriptManager/index.ts index d788d87b..022c4e12 100644 --- a/src/ScriptManager/index.ts +++ b/src/ScriptManager/index.ts @@ -29,7 +29,7 @@ class ScriptManager { onSelectedNodeIdChange?: (id: string) => void; onChallengeSetEventValue?: (eventId: string, value: boolean) => void; - + onChallengeGetEventValue?: (eventId: string, value: boolean) => boolean; private programStatus_: 'running' | 'stopped' = 'stopped'; get programStatus() { return this.programStatus_; } set programStatus(status: 'running' | 'stopped') { @@ -485,8 +485,16 @@ namespace ScriptManager { setChallengeEventValue(eventId: string, value: boolean) { if (!this.manager_.onChallengeSetEventValue) return; this.manager_.onChallengeSetEventValue(eventId, value); + this.getChallengeEventValue(eventId,value); + } + + getChallengeEventValue(eventId: string, value: boolean) { + if (!this.manager_.onChallengeGetEventValue) return; + return value; } } + + } export default ScriptManager; \ No newline at end of file diff --git a/src/challenges/jbc2c.ts b/src/challenges/jbc2c.ts new file mode 100644 index 00000000..6faf7306 --- /dev/null +++ b/src/challenges/jbc2c.ts @@ -0,0 +1,158 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 2" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 2C: Back It Up`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can6Intersects: { + name: { [LocalizedString.EN_US]: "Can 6 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 6 intersects circle 6" }, + }, + + can6Upright: { + name: { [LocalizedString.EN_US]: "Can 6 Upright" }, + description: { [LocalizedString.EN_US]: "Can 6 upright on circle 6" }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + + driveBackwards: { + name: { [LocalizedString.EN_US]: "Robot Driving Backwards" }, + description: { [LocalizedString.EN_US]: "Robot is driving backwards" }, + }, + + rightSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed right side of can 6", + }, + }, + + topSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Top Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed top side of can 6", + }, + }, + + leftSide: { + name: { [LocalizedString.EN_US]: "Robot Passed left Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed left side of can 6", + }, + }, + }, + success: { + exprs: { + //Driving Backwards events + driveBackwards: { + type: Expr.Type.Event, + eventId: "driveBackwards", + }, + //Passing side events + rightSide: { + type: Expr.Type.Event, + eventId: "rightSide", + }, + rightSideOnce: { + type: Expr.Type.Once, + argId: "rightSide", + }, + topSide: { + type: Expr.Type.Event, + eventId: "topSide", + }, + topSideOnce: { + type: Expr.Type.Once, + argId: "topSide", + }, + leftSide: { + type: Expr.Type.Event, + eventId: "leftSide", + }, + leftSideOnce: { + type: Expr.Type.Once, + argId: "leftSide", + }, + + // Intersects Events + can6Intersects: { + type: Expr.Type.Event, + eventId: "can6Intersects", + }, + + //Upright Events + can6Upright: { + type: Expr.Type.Event, + eventId: "can6Upright", + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUpright: { + type: Expr.Type.And, + argIds: ["can6Intersects", "can6Upright"], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + "driveBackwards", + "IntersectsUpright", + "startingBox", + "rightSideOnce", + "topSideOnce", + "leftSideOnce", + ], + }, + }, + rootId: "completion", + }, + sceneId: "jbc2c", +} as Challenge; diff --git a/src/challenges/jbc4.ts b/src/challenges/jbc4.ts new file mode 100644 index 00000000..3a4a17cd --- /dev/null +++ b/src/challenges/jbc4.ts @@ -0,0 +1,227 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 4" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 4: Figure Eight`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can4Intersects: { + name: { [LocalizedString.EN_US]: "Can 4 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 4 intersects circle 4" }, + }, + can9Intersects: { + name: { [LocalizedString.EN_US]: "Can 9 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 9 intersects circle 9" }, + }, + + can4Upright: { + name: { [LocalizedString.EN_US]: "Can 4 Upright" }, + description: { [LocalizedString.EN_US]: "Can 4 upright on circle 4" }, + }, + can9Upright: { + name: { [LocalizedString.EN_US]: "Can 9 Upright" }, + description: { [LocalizedString.EN_US]: "Can 9 upright on circle 9" }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + + rightSide4: { + name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed right side of can 4", + }, + }, + + rightSide9: { + name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed right side of can 9", + }, + }, + + middleCheck: { + name: { [LocalizedString.EN_US]: "Robot Passed Middle" }, + description: { + [LocalizedString.EN_US]: "Robot passed between cans 4 and 9", + }, + }, + + topSide: { + name: { [LocalizedString.EN_US]: "Robot Passed Top Side" }, + description: { + [LocalizedString.EN_US]: "Robot passed top side of can 9", + }, + }, + + leftSide4: { + name: { [LocalizedString.EN_US]: "Robot Passed Left" }, + description: { + [LocalizedString.EN_US]: "Robot passed left side of can 4", + }, + }, + leftSide9: { + name: { [LocalizedString.EN_US]: "Robot Passed Left" }, + description: { + [LocalizedString.EN_US]: "Robot passed left side of can 9", + }, + }, + }, + success: { + exprs: { + //Passing side events + rightSide4: { + type: Expr.Type.Event, + eventId: "rightSide4", + }, + rightSide4Once: { + type: Expr.Type.Once, + argId: "rightSide4", + }, + rightSide9: { + type: Expr.Type.Event, + eventId: "rightSide9", + }, + rightSide9Once: { + type: Expr.Type.Once, + argId: "rightSide9", + }, + leftSide4: { + type: Expr.Type.Event, + eventId: "leftSide4", + }, + leftSide4Once: { + type: Expr.Type.Once, + argId: "leftSide4", + }, + leftSide9: { + type: Expr.Type.Event, + eventId: "leftSide9", + }, + leftSide9Once: { + type: Expr.Type.Once, + argId: "leftSide9", + }, + middleCheck: { + type: Expr.Type.Event, + eventId: "middleCheck", + }, + middleCheckOnce: { + type: Expr.Type.Once, + argId: "middleCheck", + }, + topSide: { + type: Expr.Type.Event, + eventId: "topSide", + }, + topSideOnce: { + type: Expr.Type.Once, + argId: "topSide", + }, + + + + + left4ThenMiddle: { + type: Expr.Type.And, + argIds: ["leftSide4Once", "middleCheckOnce"], + }, + + left4MiddleRight9: { + type: Expr.Type.And, + argIds: ["left4ThenMiddle", "rightSide9Once"], + }, + + + + + // Intersects Events + can4Intersects: { + type: Expr.Type.Event, + eventId: "can4Intersects", + }, + can9Intersects: { + type: Expr.Type.Event, + eventId: "can9Intersects", + }, + + //Upright Events + can4Upright: { + type: Expr.Type.Event, + eventId: "can4Upright", + }, + can9Upright: { + type: Expr.Type.Event, + eventId: "can9Upright", + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUpright4: { + type: Expr.Type.And, + argIds: ["can4Intersects", "can4Upright"], + }, + IntersectsUpright9: { + type: Expr.Type.And, + argIds: ["can9Intersects", "can9Upright"], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + "IntersectsUpright4", + "IntersectsUpright9", + "startingBox", + "left4ThenMiddle" + + ], + }, + }, + rootId: "completion", + }, + sceneId: "jbc4", +} as Challenge; diff --git a/src/challenges/jbc7.ts b/src/challenges/jbc7.ts new file mode 100644 index 00000000..c1c7aad7 --- /dev/null +++ b/src/challenges/jbc7.ts @@ -0,0 +1,147 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 7" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 7: Bulldozer Mania`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + canAIntersects: { + name: { [LocalizedString.EN_US]: "Can A Intersects" }, + description: { [LocalizedString.EN_US]: "Can A behind start line" }, + }, + canBIntersects: { + name: { [LocalizedString.EN_US]: "Can B Intersects" }, + description: { [LocalizedString.EN_US]: "Can B behind start line" }, + }, + canCIntersects: { + name: { [LocalizedString.EN_US]: "Can C Intersects" }, + description: { [LocalizedString.EN_US]: "Can C behind start line" }, + }, + + canAUpright: { + name: { [LocalizedString.EN_US]: "Can A Upright" }, + description: { + [LocalizedString.EN_US]: "Can A upright behind start line", + }, + }, + canBUpright: { + name: { [LocalizedString.EN_US]: "Can B Upright" }, + description: { + [LocalizedString.EN_US]: "Can B upright behind start line", + }, + }, + canCUpright: { + name: { [LocalizedString.EN_US]: "Can C Upright" }, + description: { + [LocalizedString.EN_US]: "Can C upright behind start line", + }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + }, + success: { + exprs: { + // Intersects Events + canAIntersects: { + type: Expr.Type.Event, + eventId: "canAIntersects", + }, + canBIntersects: { + type: Expr.Type.Event, + eventId: "canBIntersects", + }, + canCIntersects: { + type: Expr.Type.Event, + eventId: "canCIntersects", + }, + + //Upright Events + canAUpright: { + type: Expr.Type.Event, + eventId: "canAUpright", + }, + canBUpright: { + type: Expr.Type.Event, + eventId: "canBUpright", + }, + canCUpright: { + type: Expr.Type.Event, + eventId: "canCUpright", + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUprightA: { + type: Expr.Type.And, + argIds: ["canAIntersects", "canAUpright"], + }, + IntersectsUprightB: { + type: Expr.Type.And, + argIds: ["canBIntersects", "canBUpright"], + }, + IntersectsUprightC: { + type: Expr.Type.And, + argIds: ["canCIntersects", "canCUpright"], + }, + AllIntersectsUpright: { + type: Expr.Type.And, + argIds: [ + "IntersectsUprightA", + "IntersectsUprightB", + "IntersectsUprightC", + ], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: ["startingBox", "AllIntersectsUpright"], + }, + }, + rootId: "completion", + }, + sceneId: "jbc7", +} as Challenge; diff --git a/src/scenes/jbc2c.ts b/src/scenes/jbc2c.ts index 75cddead..76b969f0 100644 --- a/src/scenes/jbc2c.ts +++ b/src/scenes/jbc2c.ts @@ -1,16 +1,323 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; +import { SharedRegistersRobot } from "../SharedRegistersRobot"; +import Robot from "../state/State/Robot"; +import SharedRegisters from "../SharedRegisters"; +const baseScene = createBaseSceneSurfaceA(); -import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); -const baseScene = createBaseSceneSurfaceA(); +// When the can (can6) is intersecting circle6, the circle glows + +scene.addOnIntersectionListener('can6', (type, otherNodeId) => { + console.log('Can 6 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can6Intersects', visible); + setNodeVisible('circle6', visible); +}, 'circle6'); + +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; +const robotTouches = ` +scene.onBind = nodeId => { + scene.addOnCollisionListener(nodeId, (otherNodeId, point)=> { + console.log('Can 6 touched!', otherNodeId, point); + scene.setChallengeEventValue(nodeId + 'Touched', true); + }, 'robot'); +}; +`; +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const passedSide = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + switch(otherNodeId){ + case 'rightSideCan': + console.log('Robot passed the right side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('rightSide', type === 'start'); + } + break; + case 'topSideCan': + console.log('Robot passed the top side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('topSide', type === 'start'); + } + break; + case 'leftSideCan': + console.log('Robot passed the left side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leftSide', type === 'start'); + } + break; + } +}, ['rightSideCan', 'topSideCan', 'leftSideCan']); + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +// let startTime = Date.now(); +const EULER_IDENTITY = Rotation.Euler.identity(); +// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright6 = yAngle('can6') < 5; + // if(timeDiff > 1000) { + // console.log('can6 angle: ', yAngle('can6')); + // startTime = currTime; + // } + scene.setChallengeEventValue('can6Upright', upright6); + +}); +`; + +const goingBackwards = ` +scene.addOnRenderListener(() => { + const sharedRegistersRobot_ = SharedRegistersRobot; + if (sharedRegistersRobot_.robot.getMotor(0)) + //scene.setChallengeEventValue('can6Upright', upright6); + console.log('Going backwards!'); +}); + +`; + +const sharedRegistersRobot_ = SharedRegistersRobot; +const robot = baseScene.nodes.robot; +const sharedRegisters_ = new SharedRegisters(); + +//console.log(sharedRegistersRobot_); export const JBC_2C: Scene = { ...baseScene, - name: { [LocalizedString.EN_US]: 'JBC 2C' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 2C: Back It Up' }, + name: { [LocalizedString.EN_US]: "JBC 2C" }, + description: { + [LocalizedString.EN_US]: "Junior Botball Challenge 2C: Back It Up", + }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + goingBackwards: Script.ecmaScript("Going Backwards", goingBackwards), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + robotTouches: Script.ecmaScript("Robot Touches", robotTouches), + passedSide: Script.ecmaScript("Passed Side", passedSide), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + + geometry: { + ...baseScene.geometry, + circle6_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + rightSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + + topSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(0.01), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + + leftSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(50), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + }, + nodes: { ...baseScene.nodes, - 'can6': createCanNode(6), - } -}; \ No newline at end of file + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle6: { + type: "object", + geometryId: "circle6_geom", + name: { [LocalizedString.EN_US]: "Circle 6" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + rightSideCan: { + type: "object", + geometryId: "rightSideCan_geom", + name: { [LocalizedString.EN_US]: "Right Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-20), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + topSideCan: { + type: "object", + geometryId: "topSideCan_geom", + name: { [LocalizedString.EN_US]: "Top Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + leftSideCan: { + type: "object", + geometryId: "leftSideCan_geom", + name: { [LocalizedString.EN_US]: "Left Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(52), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can6: { + ...createCanNode(6, { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(57), + }), + scriptIds: ["robotTouches"], + }, + }, +}; diff --git a/src/scenes/jbc4.ts b/src/scenes/jbc4.ts index 8fb26b26..d9ed5201 100644 --- a/src/scenes/jbc4.ts +++ b/src/scenes/jbc4.ts @@ -1,17 +1,326 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; const baseScene = createBaseSceneSurfaceA(); +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can4) is intersecting circle4, the circle glows + +scene.addOnIntersectionListener('can4', (type, otherNodeId) => { + console.log('Can 4 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can4Intersects', visible); + setNodeVisible('circle4', visible); +}, 'circle4'); + +// When the can (can9) is intersecting circle9, the circle glows + +scene.addOnIntersectionListener('can9', (type, otherNodeId) => { + console.log('Can 9 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can9Intersects', visible); + setNodeVisible('circle9', visible); +}, 'circle9'); + +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; + +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const passedSide = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + switch(otherNodeId){ + case 'leftCan4': + console.log('Robot passed the left side of can 4!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leftSide4', type === 'start'); + } + break; + case 'middle': + console.log('Robot passed between cans 4 and 9!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('middleCheck', type === 'start'); + } + break; + // case 'leftSideCan': + // console.log('Robot passed the left side of the can!', type, otherNodeId); + // if(scene.programStatus === 'running'){ + // scene.setChallengeEventValue('leftSide', type === 'start'); + // } + // break; + } +}, ['leftCan4','middle']); + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +// let startTime = Date.now(); +const EULER_IDENTITY = Rotation.Euler.identity(); +// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright4 = yAngle('can4') < 5; + const upright9 = yAngle('can9') < 5; + // if(timeDiff > 1000) { + // console.log('can6 angle: ', yAngle('can6')); + // startTime = currTime; + // } + scene.setChallengeEventValue('can4Upright', upright4); + scene.setChallengeEventValue('can9Upright', upright9); +}); +`; + export const JBC_4: Scene = { ...baseScene, - name: { [LocalizedString.EN_US]: 'JBC 4' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 4: Figure Eight' }, + name: { [LocalizedString.EN_US]: "JBC 4" }, + description: { + [LocalizedString.EN_US]: "Junior Botball Challenge 4: Figure Eight", + }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + passedSide: Script.ecmaScript("Passed Side", passedSide), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + + geometry: { + ...baseScene.geometry, + circle4_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle9_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + leftCan4_geom:{ + type: "box", + size: { + x: Distance.centimeters(150), + y: Distance.centimeters(1), + z: Distance.centimeters(5), + }, + }, + middle_geom:{ + type: "box", + size: { + x: Distance.centimeters(-1), + y: Distance.centimeters(-8), + z: Distance.centimeters(30), + }, + }, + rightCan9_geom:{ + type: "box", + size: { + x: Distance.centimeters(150), + y: Distance.centimeters(1), + z: Distance.centimeters(5), + }, + }, + }, + nodes: { ...baseScene.nodes, - 'can4': createCanNode(4), - 'can9': createCanNode(9), - } -}; \ No newline at end of file + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle4: { + type: "object", + geometryId: "circle4_geom", + name: { [LocalizedString.EN_US]: "Circle 4" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(42.7), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle9: { + type: "object", + geometryId: "circle9_geom", + name: { [LocalizedString.EN_US]: "Circle 9" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + + leftCan4: { + type: "object", + geometryId: "leftCan4_geom", + name: { [LocalizedString.EN_US]: "Left of Can 4" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(50), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(42.7), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + middle: { + type: "object", + geometryId: "middle_geom", + name: { [LocalizedString.EN_US]: "Between cans 4 and 9" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(70), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + rightCan9: { + type: "object", + geometryId: "rightCan9_geom", + name: { [LocalizedString.EN_US]: "Right side of can 9" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(70), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + + + can4: {...createCanNode(4),scriptIds: ["passedSide"]}, + can9: {...createCanNode(9),scriptIds: ["passedSide"]}, + }, +}; diff --git a/src/scenes/jbc6.ts b/src/scenes/jbc6.ts index b60194fb..4324982e 100644 --- a/src/scenes/jbc6.ts +++ b/src/scenes/jbc6.ts @@ -36,14 +36,14 @@ scene.addOnIntersectionListener('can9', (type, otherNodeId) => { }, 'blueGarage'); -// // When the can (can10) is intersecting the yellow garage, the garage glows - -// scene.addOnIntersectionListener('can12', (type, otherNodeId) => { -// console.log('Can 12 placed!', type, otherNodeId); -// const visible = type === 'start'; -// scene.setChallengeEventValue('can12Intersects', visible); -// setNodeVisible('circle12', visible); -// }, 'circle12'); +// When the can (can10) is intersecting the yellow garage, the garage glows + +scene.addOnIntersectionListener('can10', (type, otherNodeId) => { + console.log('Can 10 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can10Intersects', visible); + setNodeVisible('yellowGarage', visible); +}, 'yellowGarage'); `; @@ -110,6 +110,14 @@ export const JBC_6: Scene = { }, blueGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(16), + y: Distance.centimeters(0.1), + z: Distance.centimeters(16), + }, + }, + yellowGarage_geom: { type: "box", size: { x: Distance.centimeters(16), @@ -186,21 +194,43 @@ export const JBC_6: Scene = { type: "object", geometryId: "blueGarage_geom", name: { [LocalizedString.EN_US]: "Blue Garage" }, - visible: false, + visible: true, origin: { position: { x: Distance.centimeters(-13.4), y: Distance.centimeters(-6.9), - z: Distance.centimeters(94), + z: Distance.centimeters(96), }, orientation: { type: 'euler', x: Angle.degrees(0), - y: Angle.degrees(45), + y: Angle.degrees(-45), z: Angle.degrees(0), }, }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + + + }, + yellowGarage: { + type: "object", + geometryId: "yellowGarage_geom", + name: { [LocalizedString.EN_US]: "Yellow Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.8), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(78), + }, + }, material: { type: "pbr", emissive: { @@ -214,7 +244,7 @@ export const JBC_6: Scene = { can9: {...createCanNode(9,{ x: Distance.centimeters(0.3), y: Distance.centimeters(0), - z: Distance.centimeters(85), + z: Distance.centimeters(85.4), }), scriptIds: ["garageIntersects"]}, can10: {...createCanNode(10), scriptIds: ["garageIntersects"]}, }, diff --git a/src/scenes/jbc7.ts b/src/scenes/jbc7.ts index 2b64c814..8740ab01 100644 --- a/src/scenes/jbc7.ts +++ b/src/scenes/jbc7.ts @@ -1,27 +1,268 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; +import Expr from "../state/State/Challenge/Expr"; const baseScene = createBaseSceneSurfaceA(); +const startBoxIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +let count = 0; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + //count++; + //console.log(count); + + + if(type === 'start'){ + console.log(nodeId + " entered start box!"); + count++; + } + + else if (count != 0 && type === "end"){ + console.log(nodeId + " left start box :("); + count--; + } + else if (count > 3){ + count = 0; + } + + switch (count){ + case 0: + scene.setChallengeEventValue('canAIntersects', false); + scene.setChallengeEventValue('canBIntersects', false); + scene.setChallengeEventValue('canCIntersects', false); + break; + case 1: + scene.setChallengeEventValue('canAIntersects', true); + scene.setChallengeEventValue('canBIntersects', false); + scene.setChallengeEventValue('canCIntersects', false); + break; + case 2: + scene.setChallengeEventValue('canAIntersects', true); + scene.setChallengeEventValue('canBIntersects', true); + scene.setChallengeEventValue('canCIntersects', false); + break; + case 3: + scene.setChallengeEventValue('canAIntersects', true); + scene.setChallengeEventValue('canBIntersects', true); + scene.setChallengeEventValue('canCIntersects', true); + break; + + } + console.log("Intersecting Count: " + count + " (" +nodeId + ")"); + }, 'startBox'); + + +}; +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; + +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const uprightCans = ` + +let count = 0; +console.log("Beginning Upright Count: " + count); +scene.onBind = nodeId => { + + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + const EULER_IDENTITY = Rotation.Euler.identity(); + const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + const upright = yAngle(nodeId) < 5; + + + if(upright && type === "start"){ + count++; + } + else if(upright && (count != 0) && type === "end"){ + count--; + } + else if(!upright && (count != 0) && type === "start"){ + count--; + } + switch (count){ + case 0: + scene.setChallengeEventValue('canAUpright', false); + scene.setChallengeEventValue('canBUpright', false); + scene.setChallengeEventValue('canCUpright', false); + break; + case 1: + scene.setChallengeEventValue('canAUpright', true); + scene.setChallengeEventValue('canBUpright', false); + scene.setChallengeEventValue('canCUpright', false); + break; + case 2: + scene.setChallengeEventValue('canAUpright', true); + scene.setChallengeEventValue('canBUpright', true); + scene.setChallengeEventValue('canCUpright', false); + break; + case 3: + scene.setChallengeEventValue('canAUpright', true); + scene.setChallengeEventValue('canBUpright', true); + scene.setChallengeEventValue('canCUpright', true); + break; + + } + console.log("Upright Count: " + count + " (" +nodeId + ")"); + + + + }, 'startBox'); +}; +`; + export const JBC_7: Scene = { ...baseScene, - name: { [LocalizedString.EN_US]: 'JBC 7' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 7: Bulldozer Mania` }, + name: { [LocalizedString.EN_US]: "JBC 7" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 7: Bulldozer Mania`, + }, + scripts: { + startBoxIntersects: Script.ecmaScript( + "Start Box Intersects", + startBoxIntersects + ), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(30), + }, + }, + }, + nodes: { + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-3), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, ...baseScene.nodes, - 'can1': createCanNode(1), - 'can2': createCanNode(2), - 'can3': createCanNode(3), - 'can4': createCanNode(4), - 'can5': createCanNode(5), - 'can6': createCanNode(6), - 'can7': createCanNode(7), - 'can8': createCanNode(8), - 'can9': createCanNode(9), - 'can10': createCanNode(10), - 'can11': createCanNode(11), - 'can12': createCanNode(12), - } -}; \ No newline at end of file + can1: { + ...createCanNode(1), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can2: { + ...createCanNode(2), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can3: { + ...createCanNode(3), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can4: { + ...createCanNode(4), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can5: { + ...createCanNode(5), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can6: { + ...createCanNode(6), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can7: { + ...createCanNode(7), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can8: { + ...createCanNode(8), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can9: { + ...createCanNode(9), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can10: { + ...createCanNode(10), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can11: { + ...createCanNode(11), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + can12: { + ...createCanNode(12), + scriptIds: ["startBoxIntersects", "uprightCans"], + }, + }, +}; diff --git a/src/state/State/Challenge/Expr.ts b/src/state/State/Challenge/Expr.ts index 48e4486a..269854de 100644 --- a/src/state/State/Challenge/Expr.ts +++ b/src/state/State/Challenge/Expr.ts @@ -21,7 +21,7 @@ namespace Expr { eventId: string; } - namespace Event { + export namespace Event { export const evaluate = (event: Event, context: EvaluationContext): boolean => { const eventState = context.eventStates[event.eventId]; return eventState === undefined ? false : eventState; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 03a2226e..269be1e7 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -16,7 +16,10 @@ import jbc6c from "../../challenges/jbc6c"; import jbc1 from "../../challenges/jbc1"; import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; +import jbc2c from "../../challenges/jbc2c"; +import jbc4 from "../../challenges/jbc4"; import jbc6 from "../../challenges/jbc6"; +import jbc7 from "../../challenges/jbc7"; export namespace ChallengesAction { @@ -142,9 +145,21 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc2b, brief: ChallengeBrief.fromChallenge(jbc2b), }), + 'jbc2c': Async.loaded({ + value: jbc2c, + brief: ChallengeBrief.fromChallenge(jbc2c), + }), + 'jbc4': Async.loaded({ + value: jbc4, + brief: ChallengeBrief.fromChallenge(jbc4), + }), 'jbc6': Async.loaded({ value: jbc6, brief: ChallengeBrief.fromChallenge(jbc6), + }), + 'jbc7': Async.loaded({ + value: jbc7, + brief: ChallengeBrief.fromChallenge(jbc7), }) }; From 4224b69120b560980ca69aae6466ebc01d31b479 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 7 Feb 2023 13:32:38 -0600 Subject: [PATCH 08/37] Finished JBC4 logic with testing --- src/challenges/jbc4.ts | 114 +++------------------------------ src/scenes/jbc4.ts | 140 ++++++++++++++++++++++------------------- 2 files changed, 83 insertions(+), 171 deletions(-) diff --git a/src/challenges/jbc4.ts b/src/challenges/jbc4.ts index 3a4a17cd..0fdff8bb 100644 --- a/src/challenges/jbc4.ts +++ b/src/challenges/jbc4.ts @@ -47,114 +47,24 @@ export default { description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, }, - rightSide4: { - name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, + figureEight: { + name: { [LocalizedString.EN_US]: "Robot Figure Eight" }, description: { - [LocalizedString.EN_US]: "Robot passed right side of can 4", - }, - }, - - rightSide9: { - name: { [LocalizedString.EN_US]: "Robot Passed Right Side" }, - description: { - [LocalizedString.EN_US]: "Robot passed right side of can 9", - }, - }, - - middleCheck: { - name: { [LocalizedString.EN_US]: "Robot Passed Middle" }, - description: { - [LocalizedString.EN_US]: "Robot passed between cans 4 and 9", - }, - }, - - topSide: { - name: { [LocalizedString.EN_US]: "Robot Passed Top Side" }, - description: { - [LocalizedString.EN_US]: "Robot passed top side of can 9", - }, - }, - - leftSide4: { - name: { [LocalizedString.EN_US]: "Robot Passed Left" }, - description: { - [LocalizedString.EN_US]: "Robot passed left side of can 4", - }, - }, - leftSide9: { - name: { [LocalizedString.EN_US]: "Robot Passed Left" }, - description: { - [LocalizedString.EN_US]: "Robot passed left side of can 9", + [LocalizedString.EN_US]: "Robot did a figure eight around cans 4 and 9", }, }, }, success: { exprs: { - //Passing side events - rightSide4: { - type: Expr.Type.Event, - eventId: "rightSide4", - }, - rightSide4Once: { - type: Expr.Type.Once, - argId: "rightSide4", - }, - rightSide9: { - type: Expr.Type.Event, - eventId: "rightSide9", - }, - rightSide9Once: { - type: Expr.Type.Once, - argId: "rightSide9", - }, - leftSide4: { - type: Expr.Type.Event, - eventId: "leftSide4", - }, - leftSide4Once: { - type: Expr.Type.Once, - argId: "leftSide4", - }, - leftSide9: { - type: Expr.Type.Event, - eventId: "leftSide9", - }, - leftSide9Once: { - type: Expr.Type.Once, - argId: "leftSide9", - }, - middleCheck: { - type: Expr.Type.Event, - eventId: "middleCheck", - }, - middleCheckOnce: { - type: Expr.Type.Once, - argId: "middleCheck", - }, - topSide: { + //Figure Eight Event + figureEight: { type: Expr.Type.Event, - eventId: "topSide", + eventId: "figureEight", }, - topSideOnce: { + figureEightOnce: { type: Expr.Type.Once, - argId: "topSide", - }, - - - - - left4ThenMiddle: { - type: Expr.Type.And, - argIds: ["leftSide4Once", "middleCheckOnce"], - }, - - left4MiddleRight9: { - type: Expr.Type.And, - argIds: ["left4ThenMiddle", "rightSide9Once"], + argId: "figureEight", }, - - - // Intersects Events can4Intersects: { @@ -212,13 +122,7 @@ export default { //Success Logic = Can A upright, intersects and touched completion: { type: Expr.Type.And, - argIds: [ - "IntersectsUpright4", - "IntersectsUpright9", - "startingBox", - "left4ThenMiddle" - - ], + argIds: ["IntersectsUpright4", "IntersectsUpright9", "startingBox","figureEightOnce"], }, }, rootId: "completion", diff --git a/src/scenes/jbc4.ts b/src/scenes/jbc4.ts index d9ed5201..40abb590 100644 --- a/src/scenes/jbc4.ts +++ b/src/scenes/jbc4.ts @@ -55,48 +55,63 @@ scene.addOnIntersectionListener('robot', (type, otherNodeId) => { `; const passedSide = ` -scene.addOnIntersectionListener('robot', (type, otherNodeId) => { - switch(otherNodeId){ - case 'leftCan4': - console.log('Robot passed the left side of can 4!', type, otherNodeId); - if(scene.programStatus === 'running'){ - scene.setChallengeEventValue('leftSide4', type === 'start'); - } - break; - case 'middle': - console.log('Robot passed between cans 4 and 9!', type, otherNodeId); - if(scene.programStatus === 'running'){ - scene.setChallengeEventValue('middleCheck', type === 'start'); - } - break; - // case 'leftSideCan': - // console.log('Robot passed the left side of the can!', type, otherNodeId); - // if(scene.programStatus === 'running'){ - // scene.setChallengeEventValue('leftSide', type === 'start'); - // } - // break; - } -}, ['leftCan4','middle']); + +let count = 0; +let position = 0; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + if(otherNodeId == "startBox"){ + count = 0; + position = 0; + } + + if(type === "start"){ + position++; + console.log(count + ":" + otherNodeId + ":" + type + ":Position:" +position ); + } + + //Sets values for second crossing in the middle + if(count == 2 && (otherNodeId == "n1")){ + count++; + position = 3; + console.log(count + ":" + otherNodeId + ":" + type); + } + if(type==="start" && (otherNodeId == "n" +position)){ + count++; + console.log(count + ":" + otherNodeId + ":" + type); + + } + + //Passed three checkmarks and recently passed the middle checkmark + if(count == 3 && otherNodeId == "n1"){ + scene.setChallengeEventValue('figureEight', true); + } + else{ + scene.setChallengeEventValue('figureEight', false); + } + + if(position == 0 ){ + count = 0; + } + + + }, ['startBox', 'n1', 'n2']); +}; `; const uprightCans = ` // When a can is standing upright, the upright condition is met. -// let startTime = Date.now(); const EULER_IDENTITY = Rotation.Euler.identity(); -// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); - scene.addOnRenderListener(() => { - // const currTime = Date.now(); - // const timeDiff = currTime - startTime; + const upright4 = yAngle('can4') < 5; const upright9 = yAngle('can9') < 5; - // if(timeDiff > 1000) { - // console.log('can6 angle: ', yAngle('can6')); - // startTime = currTime; - // } + scene.setChallengeEventValue('can4Upright', upright4); scene.setChallengeEventValue('can9Upright', upright9); }); @@ -145,7 +160,7 @@ export const JBC_4: Scene = { }, }, - leftCan4_geom:{ + leftCan4_geom: { type: "box", size: { x: Distance.centimeters(150), @@ -153,7 +168,7 @@ export const JBC_4: Scene = { z: Distance.centimeters(5), }, }, - middle_geom:{ + middle_geom: { type: "box", size: { x: Distance.centimeters(-1), @@ -161,7 +176,23 @@ export const JBC_4: Scene = { z: Distance.centimeters(30), }, }, - rightCan9_geom:{ + rightCan9_geom: { + type: "box", + size: { + x: Distance.centimeters(150), + y: Distance.centimeters(1), + z: Distance.centimeters(5), + }, + }, + topCan9_geom: { + type: "box", + size: { + x: Distance.centimeters(-1), + y: Distance.centimeters(-8), + z: Distance.centimeters(50), + }, + }, + rightCan4_geom: { type: "box", size: { x: Distance.centimeters(150), @@ -234,7 +265,6 @@ export const JBC_4: Scene = { }, }, - startBox: { type: "object", geometryId: "startBox_geom", @@ -255,29 +285,7 @@ export const JBC_4: Scene = { }, }, }, - - - leftCan4: { - type: "object", - geometryId: "leftCan4_geom", - name: { [LocalizedString.EN_US]: "Left of Can 4" }, - visible: false, - origin: { - position: { - x: Distance.centimeters(50), - y: Distance.centimeters(-6.9), - z: Distance.centimeters(42.7), - }, - }, - material: { - type: "pbr", - emissive: { - type: "color3", - color: Color.rgb(255, 255, 255), - }, - }, - }, - middle: { + n1: { type: "object", geometryId: "middle_geom", name: { [LocalizedString.EN_US]: "Between cans 4 and 9" }, @@ -297,16 +305,17 @@ export const JBC_4: Scene = { }, }, }, - rightCan9: { + + n2: { type: "object", - geometryId: "rightCan9_geom", - name: { [LocalizedString.EN_US]: "Right side of can 9" }, + geometryId: "topCan9_geom", + name: { [LocalizedString.EN_US]: "Top side of can 9" }, visible: true, origin: { position: { x: Distance.centimeters(0), y: Distance.centimeters(-6.9), - z: Distance.centimeters(70), + z: Distance.centimeters(115), }, }, material: { @@ -318,9 +327,8 @@ export const JBC_4: Scene = { }, }, - - - can4: {...createCanNode(4),scriptIds: ["passedSide"]}, - can9: {...createCanNode(9),scriptIds: ["passedSide"]}, + + can4: { ...createCanNode(4) }, + can9: { ...createCanNode(9), scriptIds: ["passedSide"] }, }, }; From 31e4224da8732cf67831b6155cacbc82d6527334 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 9 Feb 2023 12:33:23 -0600 Subject: [PATCH 09/37] Finished JBC4B logic with testing --- src/challenges/jbc4b.ts | 193 ++++++++++++++ src/scenes/jbc4b.ts | 443 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 5 + 3 files changed, 635 insertions(+), 6 deletions(-) create mode 100644 src/challenges/jbc4b.ts diff --git a/src/challenges/jbc4b.ts b/src/challenges/jbc4b.ts new file mode 100644 index 00000000..5943b776 --- /dev/null +++ b/src/challenges/jbc4b.ts @@ -0,0 +1,193 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 4B" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 4B: Barrel Racing`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can5Intersects: { + name: { [LocalizedString.EN_US]: "Can 5 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 5 intersects circle 5" }, + }, + can8Intersects: { + name: { [LocalizedString.EN_US]: "Can 8 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 8 intersects circle 8" }, + }, + can9Intersects: { + name: { [LocalizedString.EN_US]: "Can 9 Intersects" }, + description: { [LocalizedString.EN_US]: "Can 9 intersects circle 9" }, + }, + + can5Upright: { + name: { [LocalizedString.EN_US]: "Can 5 Upright" }, + description: { [LocalizedString.EN_US]: "Can 5 upright on circle 5" }, + }, + can8Upright: { + name: { [LocalizedString.EN_US]: "Can 8 Upright" }, + description: { [LocalizedString.EN_US]: "Can 8 upright on circle 8" }, + }, + can9Upright: { + name: { [LocalizedString.EN_US]: "Can 9 Upright" }, + description: { [LocalizedString.EN_US]: "Can 9 upright on circle 9" }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: "Robot Left Start" }, + description: { [LocalizedString.EN_US]: "Robot left starting box" }, + }, + returnStartBox: { + name: { [LocalizedString.EN_US]: "Robot Rentered Start" }, + description: { [LocalizedString.EN_US]: "Robot reentered starting box" }, + }, + + clockwise8: { + name: { [LocalizedString.EN_US]: "Can 8 Clockwise" }, + description: { + [LocalizedString.EN_US]: "Robot drove clockwise around can 8", + }, + }, + counterClockwise5: { + name: { [LocalizedString.EN_US]: "Can 5 Counter Clockwise" }, + description: { + [LocalizedString.EN_US]: "Robot drove counter clockwise around can 5", + }, + }, + counterClockwise9: { + name: { [LocalizedString.EN_US]: "Can 9 Counter Clockwise" }, + description: { + [LocalizedString.EN_US]: "Robot drove counter clockwise around can 9", + }, + }, + }, + success: { + exprs: { + //Clockwise Events + clockwise8: { + type: Expr.Type.Event, + eventId: "clockwise8", + }, + clockwise8Once: { + type: Expr.Type.Once, + argId: "clockwise8", + }, + + //Counter Clockwise Events + counterClockwise5: { + type: Expr.Type.Event, + eventId: "counterClockwise5", + }, + counterClockwise5Once: { + type: Expr.Type.Once, + argId: "counterClockwise5", + }, + counterClockwise9: { + type: Expr.Type.Event, + eventId: "counterClockwise9", + }, + counterClockwise9Once: { + type: Expr.Type.Once, + argId: "counterClockwise9", + }, + + clockMovements: { + type: Expr.Type.And, + argIds: ["clockwise8Once", "counterClockwise5Once","counterClockwise9Once"], + }, + + + // Intersects Events + can5Intersects: { + type: Expr.Type.Event, + eventId: "can5Intersects", + }, + can8Intersects: { + type: Expr.Type.Event, + eventId: "can8Intersects", + }, + can9Intersects: { + type: Expr.Type.Event, + eventId: "can9Intersects", + }, + + //Upright Events + can5Upright: { + type: Expr.Type.Event, + eventId: "can5Upright", + }, + can8Upright: { + type: Expr.Type.Event, + eventId: "can8Upright", + }, + can9Upright: { + type: Expr.Type.Event, + eventId: "can9Upright", + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: "leaveStartBox", + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: "leaveStartBox", + }, + + returnStartBox: { + type: Expr.Type.Event, + eventId: "returnStartBox", + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: "returnStartBox", + }, + startingBox: { + type: Expr.Type.And, + argIds: ["leaveStartBoxOnce", "returnStartBoxOnce"], + }, + + //Intersects and upright logic + IntersectsUpright5: { + type: Expr.Type.And, + argIds: ["can5Intersects", "can5Upright"], + }, + IntersectsUpright8: { + type: Expr.Type.And, + argIds: ["can8Intersects", "can8Upright"], + }, + IntersectsUpright9: { + type: Expr.Type.And, + argIds: ["can9Intersects", "can9Upright"], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + "IntersectsUpright5", + "IntersectsUpright8", + "IntersectsUpright9", + "startingBox", + "clockMovements" + ], + }, + }, + rootId: "completion", + }, + sceneId: "jbc4b", +} as Challenge; diff --git a/src/scenes/jbc4b.ts b/src/scenes/jbc4b.ts index 448e220e..084ff90b 100644 --- a/src/scenes/jbc4b.ts +++ b/src/scenes/jbc4b.ts @@ -1,18 +1,449 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; const baseScene = createBaseSceneSurfaceA(); +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can5) is intersecting circle4, the circle glows + +scene.addOnIntersectionListener('can5', (type, otherNodeId) => { + console.log('Can 5 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can5Intersects', visible); + setNodeVisible('circle5', visible); +}, 'circle5'); +// When the can (can8) is intersecting circle4, the circle glows + +scene.addOnIntersectionListener('can8', (type, otherNodeId) => { + console.log('Can 8 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can8Intersects', visible); + setNodeVisible('circle8', visible); +}, 'circle8'); + +// When the can (can9) is intersecting circle9, the circle glows + +scene.addOnIntersectionListener('can9', (type, otherNodeId) => { + console.log('Can 9 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can9Intersects', visible); + setNodeVisible('circle9', visible); +}, 'circle9'); + +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; + +const enterStartBox = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; + +const passedSide = ` + +let count = 0; +let position = 0; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + if(otherNodeId == "startBox"){ + count = 0; + position = 0; + } + + if(type === "start"){ + position++; + console.log(count + ":" + otherNodeId + ":" + type + ":Position:" +position ); + } + + + if(type==="start" && (otherNodeId == "n" +position)){ + count++; + console.log(count + ":" + otherNodeId + ":" + type); + + } + + if(count == 2 && otherNodeId == "n2"){ + scene.setChallengeEventValue('clockwise8', true); + } + else if (count == 4 && otherNodeId == "n4"){ + scene.setChallengeEventValue('counterClockwise5', true); + } + else if(count == 6 && otherNodeId == "n6"){ + scene.setChallengeEventValue('counterClockwise9', true); + } + if(position == 0 ){ + count = 0; + } + + + }, ['startBox', 'n1', 'n2', 'n3', 'n4', 'n5', 'n6']); +}; + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + +scene.addOnRenderListener(() => { + + const upright5 = yAngle('can5') < 5; + const upright8 = yAngle('can8') < 5; + const upright9 = yAngle('can9') < 5; + + scene.setChallengeEventValue('can5Upright', upright5); + scene.setChallengeEventValue('can8Upright', upright8); + scene.setChallengeEventValue('can9Upright', upright9); +}); +`; export const JBC_4B: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 4B' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 4B: Barrel Racing' }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + passedSide: Script.ecmaScript("Passed Side", passedSide), + leftStartBox: Script.ecmaScript("Robot Left Start", leftStartBox), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + geometry: { + ...baseScene.geometry, + circle5_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle8_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle9_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + rightCan8_geom: { + type: "box", + size: { + x: Distance.centimeters(80), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0.1), + }, + }, + leftCan8_geom: { + type: "box", + size: { + x: Distance.centimeters(5), + y: Distance.centimeters(0.1), + z: Distance.centimeters(20), + }, + }, + topCan5_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0.1), + }, + }, + leftCan5_geom: { + type: "box", + size: { + x: Distance.centimeters(80), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0.1), + }, + }, + topCan9_geom: { + type: "box", + size: { + x: Distance.centimeters(0.1), + y: Distance.centimeters(0.1), + z: Distance.centimeters(1), + }, + }, + leftCan9_geom: { + type: "box", + size: { + x: Distance.centimeters(0.1), + y: Distance.centimeters(0.1), + z: Distance.centimeters(1), + }, + }, + }, + nodes: { + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle5: { + type: "object", + geometryId: "circle5_geom", + name: { [LocalizedString.EN_US]: "Circle 5" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(14.3), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle8: { + type: "object", + geometryId: "circle8_geom", + name: { [LocalizedString.EN_US]: "Circle 8" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-26), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65.5), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle9: { + type: "object", + geometryId: "circle9_geom", + name: { [LocalizedString.EN_US]: "Circle 9" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n2: { + type: "object", + geometryId: "leftCan8_geom", + name: { [LocalizedString.EN_US]: "Can 8" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-37), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(43), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n1: { + type: "object", + geometryId: "rightCan8_geom", + name: { [LocalizedString.EN_US]: "Can 8" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-80), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65.5), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n3: { + type: "object", + geometryId: "topCan5_geom", + name: { [LocalizedString.EN_US]: "Can 5" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(75), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(67.7), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n4: { + type: "object", + geometryId: "leftCan5_geom", + name: { [LocalizedString.EN_US]: "Can 5" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(75), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n5: { + type: "object", + geometryId: "topCan9_geom", + name: { [LocalizedString.EN_US]: "Can 9" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-5), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(110), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + + + }, + n6: { + type: "object", + geometryId: "leftCan9_geom", + name: { [LocalizedString.EN_US]: "Can 9" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(8), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(110), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + + + }, + ...baseScene.nodes, - 'can5': createCanNode(5), - 'can8': createCanNode(8), - 'can9': createCanNode(9), + can5: { ...createCanNode(5), scriptIds: ["passedSide"] }, + can8: createCanNode(8), + can9: createCanNode(9), } }; \ No newline at end of file diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 269be1e7..de181f19 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -18,6 +18,7 @@ import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; import jbc2c from "../../challenges/jbc2c"; import jbc4 from "../../challenges/jbc4"; +import jbc4b from "../../challenges/jbc4b"; import jbc6 from "../../challenges/jbc6"; import jbc7 from "../../challenges/jbc7"; @@ -153,6 +154,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc4, brief: ChallengeBrief.fromChallenge(jbc4), }), + 'jbc4b': Async.loaded({ + value: jbc4b, + brief: ChallengeBrief.fromChallenge(jbc4b), + }), 'jbc6': Async.loaded({ value: jbc6, brief: ChallengeBrief.fromChallenge(jbc6), From a205707c6d1b5b7a38820ffc021f96e17b5d76de Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 10 Feb 2023 10:03:18 -0600 Subject: [PATCH 10/37] Implemented JBC7B logic with some testing. Further edge case testing may be required --- src/challenges/jbc7b.ts | 202 +++++++++++++ src/scenes/jbc7b.ts | 511 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 5 + 3 files changed, 702 insertions(+), 16 deletions(-) create mode 100644 src/challenges/jbc7b.ts diff --git a/src/challenges/jbc7b.ts b/src/challenges/jbc7b.ts new file mode 100644 index 00000000..933847ed --- /dev/null +++ b/src/challenges/jbc7b.ts @@ -0,0 +1,202 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 7B' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 7B: Cover Your Bases`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + robotNoTouchFirst: { + name: { [LocalizedString.EN_US]: "Robot Doesn't Touch " }, + description: { + [LocalizedString.EN_US]: "Robot doesn't touch a can at the start", + }, + }, + canAIntersects: { + name: { [LocalizedString.EN_US]: 'Can A Intersects' }, + description: { [LocalizedString.EN_US]: 'Can A in a circle' }, + }, + canBIntersects: { + name: { [LocalizedString.EN_US]: 'Can B Intersects' }, + description: { [LocalizedString.EN_US]: 'Can B in a circle' }, + }, + canCIntersects: { + name: { [LocalizedString.EN_US]: 'Can C Intersects' }, + description: { [LocalizedString.EN_US]: 'Can C in a circle' }, + }, + canDIntersects: { + name: { [LocalizedString.EN_US]: 'Can D Intersects' }, + description: { [LocalizedString.EN_US]: 'Can D in a circle' }, + }, + canEIntersects: { + name: { [LocalizedString.EN_US]: 'Can E Intersects' }, + description: { [LocalizedString.EN_US]: 'Can E in a circle' }, + }, + + canAUpright: { + name: { [LocalizedString.EN_US]: 'Can A Upright' }, + description: { + [LocalizedString.EN_US]: 'Can A upright in a circle', + }, + }, + canBUpright: { + name: { [LocalizedString.EN_US]: 'Can B Upright' }, + description: { + [LocalizedString.EN_US]: 'Can B upright in a circle', + }, + }, + canCUpright: { + name: { [LocalizedString.EN_US]: 'Can C Upright' }, + description: { + [LocalizedString.EN_US]: 'Can C upright in a circle', + }, + }, + canDUpright: { + name: { [LocalizedString.EN_US]: 'Can D Upright' }, + description: { + [LocalizedString.EN_US]: 'Can D upright in a circle', + }, + }, + canEUpright: { + name: { [LocalizedString.EN_US]: 'Can E Upright' }, + description: { + [LocalizedString.EN_US]: 'Can E upright in a circle', + }, + }, + + leaveStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Left Start' }, + description: { [LocalizedString.EN_US]: 'Robot left starting box' }, + }, + + }, + success: { + exprs: { + //Touch Events + robotNoTouchFirst: { + type: Expr.Type.Event, + eventId: 'robotNoTouchFirst', + }, + robotNoTouchFirstOnce: { + type: Expr.Type.Once, + argId: 'robotNoTouchFirst', + }, + robotNoTouchFirstOnceNot: { + type: Expr.Type.Not, + argId: 'robotNoTouchFirstOnce', + }, + + // Intersects Events + canAIntersects: { + type: Expr.Type.Event, + eventId: 'canAIntersects', + }, + canBIntersects: { + type: Expr.Type.Event, + eventId: 'canBIntersects', + }, + canCIntersects: { + type: Expr.Type.Event, + eventId: 'canCIntersects', + }, + canDIntersects: { + type: Expr.Type.Event, + eventId: 'canDIntersects', + }, + canEIntersects: { + type: Expr.Type.Event, + eventId: 'canEIntersects', + }, + + //Upright Events + canAUpright: { + type: Expr.Type.Event, + eventId: 'canAUpright', + }, + canBUpright: { + type: Expr.Type.Event, + eventId: 'canBUpright', + }, + canCUpright: { + type: Expr.Type.Event, + eventId: 'canCUpright', + }, + canDUpright: { + type: Expr.Type.Event, + eventId: 'canDUpright', + }, + canEUpright: { + type: Expr.Type.Event, + eventId: 'canEUpright', + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: 'leaveStartBox', + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: 'leaveStartBox', + }, + startingBox: { + type: Expr.Type.And, + argIds: ['leaveStartBoxOnce'], + }, + + //Intersects and upright logic + IntersectsUprightA: { + type: Expr.Type.And, + argIds: ['canAIntersects', 'canAUpright'], + }, + IntersectsUprightB: { + type: Expr.Type.And, + argIds: ['canBIntersects', 'canBUpright'], + }, + IntersectsUprightC: { + type: Expr.Type.And, + argIds: ['canCIntersects', 'canCUpright'], + }, + IntersectsUprightD: { + type: Expr.Type.And, + argIds: ['canDIntersects', 'canDUpright'], + }, + IntersectsUprightE: { + type: Expr.Type.And, + argIds: ['canEIntersects', 'canEUpright'], + }, + AllIntersectsUpright: { + type: Expr.Type.And, + argIds: [ + 'IntersectsUprightA', + 'IntersectsUprightB', + 'IntersectsUprightC', + 'IntersectsUprightD', + 'IntersectsUprightE', + ], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: ['robotNoTouchFirstOnceNot','startingBox', 'AllIntersectsUpright'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc7b', +} as Challenge; diff --git a/src/scenes/jbc7b.ts b/src/scenes/jbc7b.ts index 3b2c4947..d54e5c6d 100644 --- a/src/scenes/jbc7b.ts +++ b/src/scenes/jbc7b.ts @@ -1,39 +1,518 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import { ReferenceFrame } from '../unit-math'; -import { Distance } from "../util"; +import { Distance } from '../util'; import LocalizedString from '../util/LocalizedString'; - +import Script from '../state/State/Scene/Script'; import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; const baseScene = createBaseSceneSurfaceA(); +const startBoxIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); +let circles = []; +let count = 0; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + //count++; + //console.log(count); + console.log("Circles = " + circles); + + if(count == 0){ + circles = []; + } + + if(type === 'start' && (circles.includes(otherNodeId) == false)){ + console.log(nodeId + " is on " + otherNodeId); + + + setNodeVisible(otherNodeId, true); + circles.push(otherNodeId); + count++; + + } + + + if (count != 0 && type === "end"){ + if((circles.includes(otherNodeId) == true)){ + console.log(nodeId + " left " + otherNodeId +" :("); + + setNodeVisible(otherNodeId, false); + const removeIndex = circles.indexOf(otherNodeId); + const x = circles.splice(removeIndex,1); + count--; + } + } + else if (count > 5){ + count = 0; + } + + switch (count){ + case 0: + scene.setChallengeEventValue('canAIntersects', false); + scene.setChallengeEventValue('canBIntersects', false); + scene.setChallengeEventValue('canCIntersects', false); + scene.setChallengeEventValue('canDIntersects', false); + scene.setChallengeEventValue('canEIntersects', false); + break; + case 1: + scene.setChallengeEventValue('canAIntersects', true); + scene.setChallengeEventValue('canBIntersects', false); + scene.setChallengeEventValue('canCIntersects', false); + scene.setChallengeEventValue('canDIntersects', false); + scene.setChallengeEventValue('canEIntersects', false); + break; + case 2: + scene.setChallengeEventValue('canBIntersects', true); + scene.setChallengeEventValue('canCIntersects', false); + scene.setChallengeEventValue('canDIntersects', false); + scene.setChallengeEventValue('canEIntersects', false); + break; + case 3: + scene.setChallengeEventValue('canCIntersects', true); + scene.setChallengeEventValue('canDIntersects', false); + scene.setChallengeEventValue('canEIntersects', false); + break; + case 4: + + scene.setChallengeEventValue('canDIntersects', true); + scene.setChallengeEventValue('canEIntersects', false); + break; + case 5: + + scene.setChallengeEventValue('canEIntersects', true); + break; + + } + console.log("Intersecting Count: " + count + " (" +nodeId + ")"); + }, ['circle1', 'circle2', 'circle3', 'circle4', 'circle5', 'circle6', 'circle7']); + + +}; +`; + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; + +const enterStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot returned start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('returnStartBox', type === 'start'); + } +}, 'startBox'); +`; +const uprightCans = ` +let circles = []; +let count = 0; +console.log("Beginning Upright Count: " + count); +scene.onBind = nodeId => { + + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + const EULER_IDENTITY = Rotation.Euler.identity(); + const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + const upright = yAngle(nodeId) < 5; + + if(count == 0){ + circles = []; + } + if(upright && type === "start" && (circles.includes(otherNodeId) == false)){ + count++; + circles.push(otherNodeId); + if(!upright && (count != 0) && type === "end"){ + count--; + const removeIndex = circles.indexOf(otherNodeId); + const x = circles.splice(removeIndex,1); + } + } + else if(upright && (count != 0) && type === "end"){ + + if((circles.includes(otherNodeId) == true)){ + count--; + const removeIndex = circles.indexOf(otherNodeId); + const x = circles.splice(removeIndex,1); + } + + } + + switch (count){ + case 0: + scene.setChallengeEventValue('canAUpright', false); + scene.setChallengeEventValue('canBUpright', false); + scene.setChallengeEventValue('canCUpright', false); + scene.setChallengeEventValue('canDUpright', false); + scene.setChallengeEventValue('canEUpright', false); + break; + case 1: + scene.setChallengeEventValue('canAUpright', true); + scene.setChallengeEventValue('canBUpright', false); + scene.setChallengeEventValue('canCUpright', false); + scene.setChallengeEventValue('canDUpright', false); + scene.setChallengeEventValue('canEUpright', false); + break; + case 2: + scene.setChallengeEventValue('canBUpright', true); + scene.setChallengeEventValue('canCUpright', false); + scene.setChallengeEventValue('canDUpright', false); + scene.setChallengeEventValue('canEUpright', false); + break; + case 3: + scene.setChallengeEventValue('canCUpright', true); + scene.setChallengeEventValue('canDUpright', false); + scene.setChallengeEventValue('canEUpright', false); + break; + case 4: + scene.setChallengeEventValue('canDUpright', true); + scene.setChallengeEventValue('canEUpright', false); + break; + case 5: + scene.setChallengeEventValue('canEUpright', true); + break; + + + } + console.log("Upright Count: " + count + " (" +nodeId + ") in " + otherNodeId); + + + + }, ['circle1', 'circle2', 'circle3', 'circle4', 'circle5', 'circle6', 'circle7']); +}; +`; const ROBOT_ORIGIN: ReferenceFrame = { ...baseScene.nodes['robot'].origin, position: { ...baseScene.nodes['robot'].origin.position, - z: Distance.centimeters(-8) + z: Distance.centimeters(-8), }, }; export const JBC_7B: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 7B' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 7B: Cover Your Bases` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 7B: Cover Your Bases`, + }, + scripts: { + startBoxIntersects: Script.ecmaScript( + 'Start Box Intersects', + startBoxIntersects + ), + uprightCans: Script.ecmaScript('Upright Cans', uprightCans), + leftStartBox: Script.ecmaScript('Robot Left Start', leftStartBox), + enterStartBox: Script.ecmaScript('Robot Reentered Start', enterStartBox), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(30), + }, + }, + circle1_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle2_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle3_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle4_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle5_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle6_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + circle7_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + }, nodes: { ...baseScene.nodes, + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-3), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle1: { + type: 'object', + geometryId: 'circle1_geom', + name: { [LocalizedString.EN_US]: 'Circle 1' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(22.7), //can 1 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(35.2), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle2: { + type: 'object', + geometryId: 'circle2_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28.8), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle3: { + type: 'object', + geometryId: 'circle3_geom', + name: { [LocalizedString.EN_US]: 'Circle 3' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-16.2), //can 3 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(25.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle4: { + type: 'object', + geometryId: 'circle4_geom', + name: { [LocalizedString.EN_US]: 'Circle 4' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 4 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(42.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle5: { + type: 'object', + geometryId: 'circle5_geom', + name: { [LocalizedString.EN_US]: 'Circle 5' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(14.3), //can 5 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle6: { + type: 'object', + geometryId: 'circle6_geom', + name: { [LocalizedString.EN_US]: 'Circle 6' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 6 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle7: { + type: 'object', + geometryId: 'circle7_geom', + name: { [LocalizedString.EN_US]: 'Circle 7' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-13.8), //can 7 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, // The normal starting position of the robot covers the tape // Start the robot back a bit so that a can fits on the tape in front of the robot - 'robot': { + robot: { ...baseScene.nodes['robot'], startingOrigin: ROBOT_ORIGIN, - origin: ROBOT_ORIGIN - }, - 'can1': createCanNode(1, { x: Distance.centimeters(24), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can2': createCanNode(2, { x: Distance.centimeters(16), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can3': createCanNode(3, { x: Distance.centimeters(8), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can4': createCanNode(4, { x: Distance.centimeters(0), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can5': createCanNode(5, { x: Distance.centimeters(-8), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can6': createCanNode(7, { x: Distance.centimeters(-16), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), - 'can7': createCanNode(6, { x: Distance.centimeters(-24), y: Distance.centimeters(0), z: Distance.centimeters(15.5) }), + origin: ROBOT_ORIGIN, + }, + can1: { + ...createCanNode(1, { + x: Distance.centimeters(24), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can2: { + ...createCanNode(2, { + x: Distance.centimeters(16), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can3: { + ...createCanNode(3, { + x: Distance.centimeters(8), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can4: { + ...createCanNode(4, { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can5: { + ...createCanNode(5, { + x: Distance.centimeters(-8), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can6: { + ...createCanNode(5, { + x: Distance.centimeters(-16), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, + can7: { + ...createCanNode(7, { + x: Distance.centimeters(-24), + y: Distance.centimeters(0), + z: Distance.centimeters(15.5), + }), + scriptIds: ['startBoxIntersects', 'uprightCans'], + }, }, -}; \ No newline at end of file +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index de181f19..5416ed9a 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -21,6 +21,7 @@ import jbc4 from "../../challenges/jbc4"; import jbc4b from "../../challenges/jbc4b"; import jbc6 from "../../challenges/jbc6"; import jbc7 from "../../challenges/jbc7"; +import jbc7b from "../../challenges/jbc7b"; export namespace ChallengesAction { @@ -165,6 +166,10 @@ const DEFAULT_CHALLENGES: Challenges = { 'jbc7': Async.loaded({ value: jbc7, brief: ChallengeBrief.fromChallenge(jbc7), + }), + 'jbc7b': Async.loaded({ + value: jbc7b, + brief: ChallengeBrief.fromChallenge(jbc7b), }) }; From b73681078a82fa3667188272be284848a5aafd5d Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 13 Feb 2023 12:11:02 -0600 Subject: [PATCH 11/37] Finished implementing JBC8 logic with testing --- src/challenges/jbc8.ts | 153 ++++++++++ src/scenes/jbc8.ts | 521 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 7 +- 3 files changed, 675 insertions(+), 6 deletions(-) create mode 100644 src/challenges/jbc8.ts diff --git a/src/challenges/jbc8.ts b/src/challenges/jbc8.ts new file mode 100644 index 00000000..882c5ada --- /dev/null +++ b/src/challenges/jbc8.ts @@ -0,0 +1,153 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 8' }, + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 8: Serpentine', + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + start: { + name: { [LocalizedString.EN_US]: 'Robot Begins In start' }, + description: { [LocalizedString.EN_US]: 'Robot begins in starting box' }, + }, + passed1: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 1' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 1' }, + }, + passed2: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 2' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 2' }, + }, + passed3: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 3' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 3' }, + }, + passed4: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 4' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 4' }, + }, + passed5: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 5' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 5' }, + }, + passed6: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 6' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 6' }, + }, + passed7: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 7' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 7' }, + }, + passed8: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 8' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 8' }, + }, + }, + success: { + exprs: { + //Start Box Event + start: { + type: Expr.Type.Event, + eventId: 'start', + }, + startOnce: { + type: Expr.Type.Once, + argId: 'start', + }, + + //Passed Through Circles Events + passed1: { + type: Expr.Type.Event, + eventId: 'passed1', + }, + passed1Once: { + type: Expr.Type.Once, + argId: 'passed1', + }, + + passed2: { + type: Expr.Type.Event, + eventId: 'passed2', + }, + passed2Once: { + type: Expr.Type.Once, + argId: 'passed2', + }, + passed3: { + type: Expr.Type.Event, + eventId: 'passed3', + }, + passed3Once: { + type: Expr.Type.Once, + argId: 'passed3', + }, + passed4: { + type: Expr.Type.Event, + eventId: 'passed4', + }, + passed4Once: { + type: Expr.Type.Once, + argId: 'passed4', + }, + passed5: { + type: Expr.Type.Event, + eventId: 'passed5', + }, + passed5Once: { + type: Expr.Type.Once, + argId: 'passed5', + }, + passed6: { + type: Expr.Type.Event, + eventId: 'passed6', + }, + passed6Once: { + type: Expr.Type.Once, + argId: 'passed6', + }, + passed7: { + type: Expr.Type.Event, + eventId: 'passed7', + }, + passed7Once: { + type: Expr.Type.Once, + argId: 'passed7', + }, + passed8: { + type: Expr.Type.Event, + eventId: 'passed8', + }, + passed8Once: { + type: Expr.Type.Once, + argId: 'passed8', + }, + + + passedSerpentine: { + type: Expr.Type.And, + argIds: ["passed1Once", "passed2Once","passed3Once", "passed4Once", "passed5Once", "passed6Once", "passed7Once", "passed8Once"], + }, + + // Success logic + completion: { + type: Expr.Type.And, + argIds: ['startOnce', 'passedSerpentine'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc8', +} as Challenge; diff --git a/src/scenes/jbc8.ts b/src/scenes/jbc8.ts index a65722a3..3cc326fe 100644 --- a/src/scenes/jbc8.ts +++ b/src/scenes/jbc8.ts @@ -1,12 +1,523 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA } from './jbcBase'; +import Script from '../state/State/Scene/Script'; +import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import { Distance } from '../util'; const baseScene = createBaseSceneSurfaceA(); +const beginsStart = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot begins in start box!', type, otherNodeId); + if(type === "start"){ + scene.setChallengeEventValue('start', true); + } + +}, 'startBox'); +`; + +const passedSide = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); +let circles = ['circle1','circle2','circle3','circle4','circle5','circle6','circle7','circle8']; +let count = 0; +let position = 0; + +scene.onBind = nodeId => { + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + const visible = type === 'start'; + if(otherNodeId == "startBox"){ + count = 0; + position = 0; + } + + if(type === "start" && (circles.includes(otherNodeId) == false)){ + position++; + console.log(count + ":" + otherNodeId + ":" + type + ":Position:" +position ); + } + + if(type==="start" && (count == position -1) && (otherNodeId == "n" +position)){ + count++; + console.log(count + ":" + otherNodeId + ":" + type); + + } + + switch(count){ + case 1: + if(otherNodeId == "n1"){ + setNodeVisible('circle1',true); + scene.setChallengeEventValue('passed1', true); + } + break; + case 2: + if(otherNodeId == "n2"){ + setNodeVisible('circle2',true); + scene.setChallengeEventValue('passed2', true); + } + break; + case 3: + if(otherNodeId == "n3"){ + setNodeVisible('circle3',true); + scene.setChallengeEventValue('passed3', true); + } + break; + case 4: + if(otherNodeId == "n4"){ + setNodeVisible('circle4',true); + scene.setChallengeEventValue('passed4', true); + } + break; + case 5: + if(otherNodeId == "n5"){ + setNodeVisible('circle5',true); + scene.setChallengeEventValue('passed5', true); + } + break; + case 6: + if(otherNodeId == "n6"){ + setNodeVisible('circle6',true); + scene.setChallengeEventValue('passed6', true); + } + break; + case 7: + if(otherNodeId == "n7"){ + setNodeVisible('circle7',true); + scene.setChallengeEventValue('passed7', true); + } + break; + case 8: + if(otherNodeId == "n8"){ + setNodeVisible('circle8',true); + scene.setChallengeEventValue('passed8', true); + } + break; + } + + + if(position == 0 ){ + count = 0; + } + + + }, ['startBox', 'circle1','circle2','circle3','circle4','circle5','circle6','circle7','circle8', + 'n1','n2','n3','n4','n5','n6','n7','n8']); +}; + +`; +//'n2','n3','n4','n5','n6','n7','n8' export const JBC_8: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 8' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 8: Serpentine' }, -}; \ No newline at end of file + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 8: Serpentine', + }, + scripts: { + passedSide: Script.ecmaScript('Passed Side', passedSide), + beginsStart: Script.ecmaScript('Robot Begins In Start', beginsStart), + }, + geometry: { + ...baseScene.geometry, + circle_geom: { + type: 'cylinder', + radius: Distance.centimeters(1), + height: Distance.centimeters(0.1), + }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(0.01), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + }, + nodes: { + ...baseScene.nodes, + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-14), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle1: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 1' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(22.7), //can 1 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(35.2), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 1' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(23.5), //can 1 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(32.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle2: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28.8), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(26.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle3: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 3' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-16.2), //can 3 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(25.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 3' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-16.2), //can 3 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(22.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle4: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 4' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 4 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(42.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n4: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 4' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-3), //can 4 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(45), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle5: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 5' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(14.3), //can 5 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n5: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 5' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(17), //can 5 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(59), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle6: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 6' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 6 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n6: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 6' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-6), //can 6 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(60), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle7: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 7' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-13.8), //can 7 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n7: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 7' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-18), //can 7 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(59), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle8: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 8' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-26), //can 8 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n8: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 8' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-26), //can 8 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(62), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can8: { + ...createCanNode(8, { + x: Distance.centimeters(-26), //can 8 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65.5), + },false,false), + scriptIds: ['passedSide'], + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 5416ed9a..1d1dbac8 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -22,6 +22,7 @@ import jbc4b from "../../challenges/jbc4b"; import jbc6 from "../../challenges/jbc6"; import jbc7 from "../../challenges/jbc7"; import jbc7b from "../../challenges/jbc7b"; +import jbc8 from "../../challenges/jbc8"; export namespace ChallengesAction { @@ -170,7 +171,11 @@ const DEFAULT_CHALLENGES: Challenges = { 'jbc7b': Async.loaded({ value: jbc7b, brief: ChallengeBrief.fromChallenge(jbc7b), - }) + }), + 'jbc8': Async.loaded({ + value: jbc8, + brief: ChallengeBrief.fromChallenge(jbc8), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From cbfb1630271a1f0e942ca0a25dc334e6b849d446 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 13 Feb 2023 12:27:06 -0600 Subject: [PATCH 12/37] Turned testing geometries off in JBC8 --- src/scenes/jbc8.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/scenes/jbc8.ts b/src/scenes/jbc8.ts index 3cc326fe..968c6e58 100644 --- a/src/scenes/jbc8.ts +++ b/src/scenes/jbc8.ts @@ -175,7 +175,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'startBox_geom', name: { [LocalizedString.EN_US]: 'Start Box' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), @@ -215,7 +215,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 1' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(23.5), //can 1 @@ -255,7 +255,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 2' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), //can 2 @@ -295,7 +295,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 3' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-16.2), //can 3 @@ -335,7 +335,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 4' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-3), //can 4 @@ -375,7 +375,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 5' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(17), //can 5 @@ -415,7 +415,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 6' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-6), //can 6 @@ -455,7 +455,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 7' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-18), //can 7 @@ -495,7 +495,7 @@ export const JBC_8: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Circle 8' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-26), //can 8 From 9ab60afb44a4f6cc6fea8279628baa458b8b7a15 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 13 Feb 2023 15:07:36 -0600 Subject: [PATCH 13/37] Finished JBC2C logic and testing --- src/scenes/jbc2c.ts | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/scenes/jbc2c.ts b/src/scenes/jbc2c.ts index 76b969f0..b20b6e70 100644 --- a/src/scenes/jbc2c.ts +++ b/src/scenes/jbc2c.ts @@ -5,8 +5,7 @@ import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; import { Color } from "../state/State/Scene/Color"; import { Distance } from "../util"; import { SharedRegistersRobot } from "../SharedRegistersRobot"; -import Robot from "../state/State/Robot"; -import SharedRegisters from "../SharedRegisters"; + const baseScene = createBaseSceneSurfaceA(); const circleIntersects = ` @@ -82,20 +81,12 @@ scene.addOnIntersectionListener('robot', (type, otherNodeId) => { const uprightCans = ` // When a can is standing upright, the upright condition is met. -// let startTime = Date.now(); const EULER_IDENTITY = Rotation.Euler.identity(); -// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); - scene.addOnRenderListener(() => { - // const currTime = Date.now(); - // const timeDiff = currTime - startTime; + const upright6 = yAngle('can6') < 5; - // if(timeDiff > 1000) { - // console.log('can6 angle: ', yAngle('can6')); - // startTime = currTime; - // } scene.setChallengeEventValue('can6Upright', upright6); }); @@ -103,19 +94,16 @@ scene.addOnRenderListener(() => { const goingBackwards = ` scene.addOnRenderListener(() => { - const sharedRegistersRobot_ = SharedRegistersRobot; - if (sharedRegistersRobot_.robot.getMotor(0)) - //scene.setChallengeEventValue('can6Upright', upright6); - console.log('Going backwards!'); -}); -`; + if(scene.nodes['robot'].state.motors[0].direction === 1 && scene.nodes['robot'].state.motors[3].direction === 1){ + scene.setChallengeEventValue('driveBackwards', false); + } + else { + scene.setChallengeEventValue('driveBackwards', true); + } +});`; -const sharedRegistersRobot_ = SharedRegistersRobot; -const robot = baseScene.nodes.robot; -const sharedRegisters_ = new SharedRegisters(); -//console.log(sharedRegistersRobot_); export const JBC_2C: Scene = { ...baseScene, From c59f78f6882632e086ed73d7db693da58b847fdf Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 14 Feb 2023 09:24:26 -0600 Subject: [PATCH 14/37] Finished JBC2D implementation and testing' --- src/challenges/jbc2c.ts | 2 +- src/challenges/jbc2d.ts | 187 +++++++++++++++++++ src/scenes/jbc2c.ts | 2 +- src/scenes/jbc2d.ts | 308 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 5 + 5 files changed, 498 insertions(+), 6 deletions(-) create mode 100644 src/challenges/jbc2d.ts diff --git a/src/challenges/jbc2c.ts b/src/challenges/jbc2c.ts index 6faf7306..dca2764e 100644 --- a/src/challenges/jbc2c.ts +++ b/src/challenges/jbc2c.ts @@ -4,7 +4,7 @@ import Expr from "../state/State/Challenge/Expr"; import LocalizedString from "../util/LocalizedString"; export default { - name: { [LocalizedString.EN_US]: "JBC Challenge 2" }, + name: { [LocalizedString.EN_US]: "JBC Challenge 2C" }, description: { [LocalizedString.EN_US]: `Junior Botball Challenge 2C: Back It Up`, }, diff --git a/src/challenges/jbc2d.ts b/src/challenges/jbc2d.ts new file mode 100644 index 00000000..0a32772a --- /dev/null +++ b/src/challenges/jbc2d.ts @@ -0,0 +1,187 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 2D' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 2C: Ring Around the Can and Back It Up`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + can6Intersects: { + name: { [LocalizedString.EN_US]: 'Can 6 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 6 intersects circle 6' }, + }, + + can6Upright: { + name: { [LocalizedString.EN_US]: 'Can 6 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 6 upright on circle 6' }, + }, + + returnStartBox1: { + name: { [LocalizedString.EN_US]: 'Robot Rentered Start 1' }, + description: { + [LocalizedString.EN_US]: + 'Robot reentered starting box after going forwards', + }, + }, + + returnStartBox2: { + name: { [LocalizedString.EN_US]: 'Robot Rentered Start 2' }, + description: { + [LocalizedString.EN_US]: + 'Robot reentered starting box after going backwards', + }, + }, + + driveBackwards: { + name: { [LocalizedString.EN_US]: 'Robot Driving Backwards' }, + description: { [LocalizedString.EN_US]: 'Robot is driving backwards' }, + }, + driveForwards: { + name: { [LocalizedString.EN_US]: 'Robot Driving Forwards' }, + description: { [LocalizedString.EN_US]: 'Robot is driving forwards' }, + }, + + rightSide: { + name: { [LocalizedString.EN_US]: 'Robot Passed Right Side' }, + description: { + [LocalizedString.EN_US]: 'Robot passed right side of can 6', + }, + }, + + topSide: { + name: { [LocalizedString.EN_US]: 'Robot Passed Top Side' }, + description: { + [LocalizedString.EN_US]: 'Robot passed top side of can 6', + }, + }, + + leftSide: { + name: { [LocalizedString.EN_US]: 'Robot Passed left Side' }, + description: { + [LocalizedString.EN_US]: 'Robot passed left side of can 6', + }, + }, + }, + success: { + exprs: { + //Driving Backwards events + driveBackwards: { + type: Expr.Type.Event, + eventId: 'driveBackwards', + }, + driveBackwardsOnce: { + type: Expr.Type.Once, + argId: 'driveBackwards', + }, + driveForwards: { + type: Expr.Type.Event, + eventId: 'driveForwards', + }, + driveForwardsOnce: { + type: Expr.Type.Once, + argId: 'driveForwards', + }, + driving: { + type: Expr.Type.And, + argIds: ['driveForwardsOnce', 'driveBackwardsOnce'], + }, + + //Passing side events + rightSide: { + type: Expr.Type.Event, + eventId: 'rightSide', + }, + rightSideOnce: { + type: Expr.Type.Once, + argId: 'rightSide', + }, + topSide: { + type: Expr.Type.Event, + eventId: 'topSide', + }, + topSideOnce: { + type: Expr.Type.Once, + argId: 'topSide', + }, + leftSide: { + type: Expr.Type.Event, + eventId: 'leftSide', + }, + leftSideOnce: { + type: Expr.Type.Once, + argId: 'leftSide', + }, + + // Intersects Events + can6Intersects: { + type: Expr.Type.Event, + eventId: 'can6Intersects', + }, + + //Upright Events + can6Upright: { + type: Expr.Type.Event, + eventId: 'can6Upright', + }, + + //Start Box Events + + returnStartBox1: { + type: Expr.Type.Event, + eventId: 'returnStartBox1', + }, + returnStartBox1Once: { + type: Expr.Type.Once, + argId: 'returnStartBox1', + }, + returnStartBox2: { + type: Expr.Type.Event, + eventId: 'returnStartBox2', + }, + returnStartBox2Once: { + type: Expr.Type.Once, + argId: 'returnStartBox2', + }, + + startingBox: { + type: Expr.Type.And, + argIds: ['returnStartBox1Once', 'returnStartBox2Once'], + }, + + //Intersects and upright logic + IntersectsUpright: { + type: Expr.Type.And, + argIds: ['can6Intersects', 'can6Upright'], + }, + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + 'driving', + 'IntersectsUpright', + 'startingBox', + 'rightSideOnce', + 'topSideOnce', + 'leftSideOnce', + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc2d', +} as Challenge; diff --git a/src/scenes/jbc2c.ts b/src/scenes/jbc2c.ts index b20b6e70..d03b7208 100644 --- a/src/scenes/jbc2c.ts +++ b/src/scenes/jbc2c.ts @@ -4,7 +4,7 @@ import Script from "../state/State/Scene/Script"; import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; import { Color } from "../state/State/Scene/Color"; import { Distance } from "../util"; -import { SharedRegistersRobot } from "../SharedRegistersRobot"; + const baseScene = createBaseSceneSurfaceA(); diff --git a/src/scenes/jbc2d.ts b/src/scenes/jbc2d.ts index 1a31d9dc..f5384eed 100644 --- a/src/scenes/jbc2d.ts +++ b/src/scenes/jbc2d.ts @@ -1,16 +1,316 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; -import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; const baseScene = createBaseSceneSurfaceA(); + +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can6) is intersecting circle6, the circle glows + +scene.addOnIntersectionListener('can6', (type, otherNodeId) => { + console.log('Can 6 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can6Intersects', visible); + setNodeVisible('circle6', visible); +}, 'circle6'); + +`; + +const robotTouches = ` +scene.onBind = nodeId => { + scene.addOnCollisionListener(nodeId, (otherNodeId, point)=> { + console.log('Can 6 touched!', otherNodeId, point); + scene.setChallengeEventValue(nodeId + 'Touched', true); + }, 'robot'); +}; +`; +const enterStartBox = ` + +scene.onBind = nodeId => { + let count = 0; + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + if(scene.programStatus === 'running' && count == 0 && type === 'start'){ + scene.setChallengeEventValue('returnStartBox1', type === 'start'); + console.log('Robot returned start box the 1st time!', type, otherNodeId); + count = 1; + } + else if(scene.programStatus === 'running' && count == 1 && type === 'start'){ + scene.setChallengeEventValue('returnStartBox2', type === 'start'); + console.log('Robot returned start box the 2nd time!', type, otherNodeId); + count = 0; + } + }, 'startBox'); +}; +`; + +const passedSide = ` +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + switch(otherNodeId){ + case 'rightSideCan': + console.log('Robot passed the right side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('rightSide', type === 'start'); + } + break; + case 'topSideCan': + console.log('Robot passed the top side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('topSide', type === 'start'); + } + break; + case 'leftSideCan': + console.log('Robot passed the left side of the can!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leftSide', type === 'start'); + } + break; + } +}, ['rightSideCan', 'topSideCan', 'leftSideCan']); + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + +scene.addOnRenderListener(() => { + + const upright6 = yAngle('can6') < 5; + scene.setChallengeEventValue('can6Upright', upright6); + +}); +`; + +const goingBackwards = ` + +scene.addOnRenderListener(() => { + + //robot going forwards + if(scene.nodes['robot'].state.motors[0].direction == 1 || scene.nodes['robot'].state.motors[3].direction == 1){ + scene.setChallengeEventValue('driveForwards', true); + } + + //robot going backwards + else if (scene.nodes['robot'].state.motors[0].direction === 2 && scene.nodes['robot'].state.motors[3].direction ===2){ + scene.setChallengeEventValue('driveBackwards', true); + } + +}); + +`; + + + export const JBC_2D: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 2D' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 2D: Ring Around the Can and Back It Up' }, + scripts: { + circleIntersects: Script.ecmaScript("Circle Intersects", circleIntersects), + goingBackwards: Script.ecmaScript("Going Backwards", goingBackwards), + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + robotTouches: Script.ecmaScript("Robot Touches", robotTouches), + passedSide: Script.ecmaScript("Passed Side", passedSide), + enterStartBox: Script.ecmaScript("Robot Reentered Start", enterStartBox), + }, + + geometry: { + ...baseScene.geometry, + circle6_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + rightSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(30), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + + topSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(0.01), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + + leftSideCan_geom: { + type: "box", + size: { + x: Distance.centimeters(50), + y: Distance.centimeters(0.1), + z: Distance.meters(0.05), + }, + }, + }, + nodes: { ...baseScene.nodes, - 'can6': createCanNode(6), - } + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle6: { + type: "object", + geometryId: "circle6_geom", + name: { [LocalizedString.EN_US]: "Circle 6" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + rightSideCan: { + type: "object", + geometryId: "rightSideCan_geom", + name: { [LocalizedString.EN_US]: "Right Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-20), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + topSideCan: { + type: "object", + geometryId: "topSideCan_geom", + name: { [LocalizedString.EN_US]: "Top Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + leftSideCan: { + type: "object", + geometryId: "leftSideCan_geom", + name: { [LocalizedString.EN_US]: "Left Side Can" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(52), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can6: { + ...createCanNode(6, { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(57), + }), + scriptIds: ["robotTouches", "enterStartBox", "goingBackwards"], + }, + }, }; \ No newline at end of file diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 1d1dbac8..7cecec76 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -17,6 +17,7 @@ import jbc1 from "../../challenges/jbc1"; import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; import jbc2c from "../../challenges/jbc2c"; +import jbc2d from "../../challenges/jbc2d"; import jbc4 from "../../challenges/jbc4"; import jbc4b from "../../challenges/jbc4b"; import jbc6 from "../../challenges/jbc6"; @@ -152,6 +153,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc2c, brief: ChallengeBrief.fromChallenge(jbc2c), }), + 'jbc2d': Async.loaded({ + value: jbc2d, + brief: ChallengeBrief.fromChallenge(jbc2d), + }), 'jbc4': Async.loaded({ value: jbc4, brief: ChallengeBrief.fromChallenge(jbc4), From c2721cdae0cfee316034c9510824ccc9ce29e074 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 16 Feb 2023 08:58:03 -0600 Subject: [PATCH 15/37] Finished JBC8B logic and testing --- src/challenges/jbc5.ts | 133 +++++++++++ src/challenges/jbc8b.ts | 117 ++++++++++ src/scenes/jbc5.ts | 105 ++++++++- src/scenes/jbc8b.ts | 383 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 11 +- 5 files changed, 740 insertions(+), 9 deletions(-) create mode 100644 src/challenges/jbc5.ts create mode 100644 src/challenges/jbc8b.ts diff --git a/src/challenges/jbc5.ts b/src/challenges/jbc5.ts new file mode 100644 index 00000000..79870705 --- /dev/null +++ b/src/challenges/jbc5.ts @@ -0,0 +1,133 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 5' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 5: Dance Party`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + leaveStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Left Start' }, + description: { [LocalizedString.EN_US]: 'Robot left starting box' }, + }, + clockwise360: { + name: { [LocalizedString.EN_US]: 'Robot 360 Clockwise' }, + description: { + [LocalizedString.EN_US]: 'Robot turned 360 degrees clockwise', + }, + }, + counterClockwise360: { + name: { [LocalizedString.EN_US]: 'Robot 360 Counter Clockwise' }, + description: { + [LocalizedString.EN_US]: 'Robot turned 360 degrees counter clockwise', + }, + }, + driveForward: { + name: { [LocalizedString.EN_US]: 'Robot Drove Forward' }, + description: { + [LocalizedString.EN_US]: 'Robot drove forward', + }, + }, + driveBackward: { + name: { [LocalizedString.EN_US]: 'Robot Drove Backward' }, + description: { + [LocalizedString.EN_US]: 'Robot drove backward', + }, + }, + waveServo: { + name: { [LocalizedString.EN_US]: 'Robot Wave Servo' }, + description: { + [LocalizedString.EN_US]: 'Robot waved servo up and down at least once', + }, + }, + }, + success: { + exprs: { + //Waving Event + waveServo: { + type: Expr.Type.Event, + eventId: 'waveServo', + }, + waveServoOnce: { + type: Expr.Type.Once, + argId: 'waveServo', + }, + + //Turning Events + clockwise360: { + type: Expr.Type.Event, + eventId: 'clockwise360', + }, + clockwise360Once: { + type: Expr.Type.Once, + argId: 'clockwise360', + }, + counterClockwise360: { + type: Expr.Type.Event, + eventId: 'counterClockwise360', + }, + counterClockwise360Once: { + type: Expr.Type.Once, + argId: 'counterClockwise360', + }, + turning: { + type: Expr.Type.And, + argIds: ['clockwise360Once', 'counterClockwise360Once'], + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: 'leaveStartBox', + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: 'leaveStartBox', + }, + + //Driving Events + driveForward: { + type: Expr.Type.Event, + eventId: 'driveForward', + }, + driveForwardOnce: { + type: Expr.Type.Once, + argId: 'driveForward', + }, + driveBackward: { + type: Expr.Type.Event, + eventId: 'driveBackward', + }, + driveBackwardOnce: { + type: Expr.Type.Once, + argId: 'driveBackward', + }, + + driving: { + type: Expr.Type.And, + argIds: ['driveForwardOnce', 'driveBackwardOnce'], + }, + + completion: { + type: Expr.Type.And, + argIds: ['leaveStartBoxOnce', 'turning', 'driving', 'waveServoOnce'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc5', +} as Challenge; diff --git a/src/challenges/jbc8b.ts b/src/challenges/jbc8b.ts new file mode 100644 index 00000000..bf0c88cf --- /dev/null +++ b/src/challenges/jbc8b.ts @@ -0,0 +1,117 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 8B' }, + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 8B: Serpentine Jr.', + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + start: { + name: { [LocalizedString.EN_US]: 'Robot Begins In start' }, + description: { [LocalizedString.EN_US]: 'Robot begins in starting box' }, + }, + passed1: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 1' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 1' }, + }, + passed2: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 2' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 2' }, + }, + passed3: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 3' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 3' }, + }, + passed4: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 4' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 4' }, + }, + passed5: { + name: { [LocalizedString.EN_US]: 'Robot Touched Circle 5' }, + description: { [LocalizedString.EN_US]: 'Robot passed through circle 5' }, + }, + }, + success: { + exprs: { + //Start Box Event + start: { + type: Expr.Type.Event, + eventId: 'start', + }, + startOnce: { + type: Expr.Type.Once, + argId: 'start', + }, + + //Passed Through Circles Events + passed1: { + type: Expr.Type.Event, + eventId: 'passed1', + }, + passed1Once: { + type: Expr.Type.Once, + argId: 'passed1', + }, + + passed2: { + type: Expr.Type.Event, + eventId: 'passed2', + }, + passed2Once: { + type: Expr.Type.Once, + argId: 'passed2', + }, + passed3: { + type: Expr.Type.Event, + eventId: 'passed3', + }, + passed3Once: { + type: Expr.Type.Once, + argId: 'passed3', + }, + passed4: { + type: Expr.Type.Event, + eventId: 'passed4', + }, + passed4Once: { + type: Expr.Type.Once, + argId: 'passed4', + }, + passed5: { + type: Expr.Type.Event, + eventId: 'passed5', + }, + passed5Once: { + type: Expr.Type.Once, + argId: 'passed5', + }, + + + passedSerpentine: { + type: Expr.Type.And, + argIds: ["passed1Once", "passed2Once","passed3Once", "passed4Once", "passed5Once"], + }, + + // Success logic + completion: { + type: Expr.Type.And, + argIds: ['startOnce', 'passedSerpentine'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc8b', +} as Challenge; diff --git a/src/scenes/jbc5.ts b/src/scenes/jbc5.ts index ef37e846..9e78f275 100644 --- a/src/scenes/jbc5.ts +++ b/src/scenes/jbc5.ts @@ -1,12 +1,111 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA } from './jbcBase'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance } from "../util"; +import { ReferenceFrame, Rotation, Vector3 } from "../unit-math"; const baseScene = createBaseSceneSurfaceA(); + + + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; + + + + +const goingBackwards = ` + +scene.addOnRenderListener(() => { + const EULER_IDENTITY = Rotation.Euler.identity(); + const xAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.X, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.X)); + + console.log("Robot orientation: " + xAngle('robot')); +}); + +`; + + export const JBC_5: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 5' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 5: Dance Party' }, + scripts: { + goingBackwards: Script.ecmaScript("Going Backwards", goingBackwards), + leftStartBox: Script.ecmaScript("Robot Reentered Start", leftStartBox), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + }, + nodes: { + ...baseScene.nodes, + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + }, }; \ No newline at end of file diff --git a/src/scenes/jbc8b.ts b/src/scenes/jbc8b.ts index cc97789a..e53a2c94 100644 --- a/src/scenes/jbc8b.ts +++ b/src/scenes/jbc8b.ts @@ -1,12 +1,385 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA } from './jbcBase'; +import Script from '../state/State/Scene/Script'; +import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import { Distance } from '../util'; const baseScene = createBaseSceneSurfaceA(); +const beginsStart = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot begins in start box!', type, otherNodeId); + if(type === "start"){ + scene.setChallengeEventValue('start', true); + } + +}, 'startBox'); +`; + +const passedSide = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); +let circles = ['circle1','circle2','circle3','circle4','circle5']; +let count = 0; +let position = 0; + +scene.onBind = nodeId => { + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + const visible = type === 'start'; + if(otherNodeId == "startBox"){ + count = 0; + position = 0; + } + + if(type === "start" && (circles.includes(otherNodeId) == false)){ + position++; + console.log(count + ":" + otherNodeId + ":" + type + ":Position:" +position ); + } + + if(type==="start" && (count == position -1) && (otherNodeId == "n" +position)){ + count++; + console.log(count + ":" + otherNodeId + ":" + type); + + } + + switch(count){ + case 1: + if(otherNodeId == "n1"){ + setNodeVisible('circle1',true); + scene.setChallengeEventValue('passed1', true); + } + break; + case 2: + if(otherNodeId == "n2"){ + setNodeVisible('circle2',true); + scene.setChallengeEventValue('passed2', true); + } + break; + case 3: + if(otherNodeId == "n3"){ + setNodeVisible('circle3',true); + scene.setChallengeEventValue('passed3', true); + } + break; + case 4: + if(otherNodeId == "n4"){ + setNodeVisible('circle4',true); + scene.setChallengeEventValue('passed4', true); + } + break; + case 5: + if(otherNodeId == "n5"){ + setNodeVisible('circle5',true); + scene.setChallengeEventValue('passed5', true); + } + break; + } + + + if(position == 0 ){ + count = 0; + } + + + }, ['startBox', 'circle1','circle2','circle3','circle4','circle5', + 'n1','n2','n3','n4','n5']); +}; + +`; + export const JBC_8B: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 8B' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 8B: Serpentine Jr.' }, -}; \ No newline at end of file + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 8B: Serpentine Jr.', + }, + scripts: { + passedSide: Script.ecmaScript('Passed Side', passedSide), + beginsStart: Script.ecmaScript('Robot Begins In Start', beginsStart), + }, + geometry: { + ...baseScene.geometry, + circle_geom: { + type: 'cylinder', + radius: Distance.centimeters(1), + height: Distance.centimeters(0.1), + }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(0.01), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + }, + nodes: { + ...baseScene.nodes, + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-14), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle1: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 1' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(22.7), //can 1 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(35.2), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 1' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(23.5), //can 1 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(32.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle2: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28.8), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(26.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle3: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 3' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-16.2), //can 3 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(25.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 3' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-16.2), //can 3 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(22.5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle4: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 4' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 4 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(42.7), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n4: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 4' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-3), //can 4 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(45), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle5: { + type: 'object', + geometryId: 'circle_geom', + name: { [LocalizedString.EN_US]: 'Circle 5' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(14.3), //can 5 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(56.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n5: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Circle 5' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(17), //can 5 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(59), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can8: { + ...createCanNode(8, { + x: Distance.centimeters(-26), //can 8 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65.5), + },false,false), + scriptIds: ['passedSide'], + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 7cecec76..3cd4dbcb 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -18,13 +18,14 @@ import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; import jbc2c from "../../challenges/jbc2c"; import jbc2d from "../../challenges/jbc2d"; +import jbc5 from "../../challenges/jbc5"; import jbc4 from "../../challenges/jbc4"; import jbc4b from "../../challenges/jbc4b"; import jbc6 from "../../challenges/jbc6"; import jbc7 from "../../challenges/jbc7"; import jbc7b from "../../challenges/jbc7b"; import jbc8 from "../../challenges/jbc8"; - +import jbc8b from "../../challenges/jbc8b"; export namespace ChallengesAction { export interface LoadChallenge { @@ -157,6 +158,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc2d, brief: ChallengeBrief.fromChallenge(jbc2d), }), + 'jbc5': Async.loaded({ + value: jbc5, + brief: ChallengeBrief.fromChallenge(jbc5), + }), 'jbc4': Async.loaded({ value: jbc4, brief: ChallengeBrief.fromChallenge(jbc4), @@ -181,6 +186,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc8, brief: ChallengeBrief.fromChallenge(jbc8), }), + 'jbc8b': Async.loaded({ + value: jbc8b, + brief: ChallengeBrief.fromChallenge(jbc8b), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From c663f4c3ce6035d191d430136d17e5df97c6ab8b Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 16 Feb 2023 11:05:09 -0600 Subject: [PATCH 16/37] Finished JBC10 logic and testing --- src/challenges/jbc10.ts | 89 +++++++++++++++++ src/scenes/jbc10.ts | 170 ++++++++++++++++++++++++++++++-- src/state/reducer/challenges.ts | 5 + 3 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 src/challenges/jbc10.ts diff --git a/src/challenges/jbc10.ts b/src/challenges/jbc10.ts new file mode 100644 index 00000000..ec40ba8b --- /dev/null +++ b/src/challenges/jbc10.ts @@ -0,0 +1,89 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 10' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 10: Solo Joust`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + + can1Upright: { + name: { [LocalizedString.EN_US]: 'Can A Upright' }, + description: { + [LocalizedString.EN_US]: 'Can A upright in a circle', + }, + }, + leaveStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Left Start' }, + description: { [LocalizedString.EN_US]: 'Robot left starting box' }, + }, + robotTouchingLine: { + name: { [LocalizedString.EN_US]: 'Robot Touching Line B' }, + description: { [LocalizedString.EN_US]: 'Robot is touching line B' }, + }, + + }, + success: { + exprs: { + + + //Upright Events + can1Upright: { + type: Expr.Type.Event, + eventId: 'can1Upright', + }, + can1NotUpright: { + type: Expr.Type.Not, + argId: 'can1Upright', + }, + + //Line B Event + robotTouchingLine: { + type: Expr.Type.Event, + eventId: 'robotTouchingLine', + }, + robotNotTouchingLine: { + type: Expr.Type.Not, + argId: 'robotTouchingLine', + }, + + //Can 1 Not Upright and Robot Not Touching Line B + NotUprightNotTouching: { + type: Expr.Type.And, + argIds: ['can1NotUpright', 'robotNotTouchingLine'], + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: 'leaveStartBox', + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: 'leaveStartBox', + }, + + + completion: { + type: Expr.Type.And, + argIds: ['leaveStartBoxOnce', 'NotUprightNotTouching'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc10', +} as Challenge; diff --git a/src/scenes/jbc10.ts b/src/scenes/jbc10.ts index 7cfc3a8a..0c17a517 100644 --- a/src/scenes/jbc10.ts +++ b/src/scenes/jbc10.ts @@ -1,17 +1,173 @@ -import Scene from "../state/State/Scene"; -import { Distance } from "../util"; +import Scene from '../state/State/Scene'; +import { ReferenceFrame } from '../unit-math'; +import { Distance } from '../util'; import LocalizedString from '../util/LocalizedString'; - +import Script from '../state/State/Scene/Script'; import { createBaseSceneSurfaceB, createCanNode } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; const baseScene = createBaseSceneSurfaceB(); +const lineBIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// If the robot touches Line B, failed challenge + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot Touching Line B!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('robotTouchingLine', visible); +}, 'lineB'); + +`; + + +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + +scene.addOnRenderListener(() => { + + const upright1 = yAngle('can1') < 5; + scene.setChallengeEventValue('can1Upright', upright1); + +}); +`; +const ROBOT_ORIGIN: ReferenceFrame = { + ...baseScene.nodes['robot'].origin, + position: { + ...baseScene.nodes['robot'].origin.position, + x: Distance.centimeters(-15), + }, +}; export const JBC_10: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 10' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 10: Solo Joust' }, + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 10: Solo Joust', + }, + scripts: { + uprightCans: Script.ecmaScript('Upright Cans', uprightCans), + leftStartBox: Script.ecmaScript('Robot Left Start', leftStartBox), + lineBIntersects: Script.ecmaScript('Robot Line B', lineBIntersects), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(1.77), + y: Distance.centimeters(0.1), + z: Distance.centimeters(30), + }, + }, + lineB_geom: { + type: 'box', + size: { + x: Distance.centimeters(0.5), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + }, nodes: { ...baseScene.nodes, - 'can1': createCanNode(1, { x: Distance.centimeters(11), y: Distance.centimeters(0), z: Distance.centimeters(91) }), - } -}; \ No newline at end of file + robot: { + ...baseScene.nodes['robot'], + startingOrigin: ROBOT_ORIGIN, + origin: ROBOT_ORIGIN, + }, + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-90), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-3), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + lineB: { + type: 'object', + geometryId: 'lineB_geom', + name: { [LocalizedString.EN_US]: 'Line B' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can1: { + ...createCanNode(1,{ + x: Distance.centimeters(11), + y: Distance.centimeters(0), + z: Distance.centimeters(91), + }), + scriptIds: ["startBoxIntersects", "uprightCans", "lineBIntersects"], + + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 3cd4dbcb..ec1283af 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -26,6 +26,7 @@ import jbc7 from "../../challenges/jbc7"; import jbc7b from "../../challenges/jbc7b"; import jbc8 from "../../challenges/jbc8"; import jbc8b from "../../challenges/jbc8b"; +import jbc10 from "../../challenges/jbc10"; export namespace ChallengesAction { export interface LoadChallenge { @@ -190,6 +191,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc8b, brief: ChallengeBrief.fromChallenge(jbc8b), }), + 'jbc10': Async.loaded({ + value: jbc10, + brief: ChallengeBrief.fromChallenge(jbc10), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 8ea05e9a3a5228583247719e28317ced550d4258 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 17 Feb 2023 10:53:57 -0600 Subject: [PATCH 17/37] Started JBC5 logic and testing. PWM has a bug so will continue when fixed --- src/scenes/jbc5.ts | 84 +++++++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/scenes/jbc5.ts b/src/scenes/jbc5.ts index 9e78f275..421976f3 100644 --- a/src/scenes/jbc5.ts +++ b/src/scenes/jbc5.ts @@ -1,16 +1,13 @@ -import Scene from "../state/State/Scene"; -import LocalizedString from "../util/LocalizedString"; -import Script from "../state/State/Scene/Script"; -import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; -import { Color } from "../state/State/Scene/Color"; -import { Distance } from "../util"; -import { ReferenceFrame, Rotation, Vector3 } from "../unit-math"; +import Scene from '../state/State/Scene'; +import LocalizedString from '../util/LocalizedString'; +import Script from '../state/State/Scene/Script'; +import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import { Distance } from '../util'; +import { ReferenceFrame, Rotation, Vector3 } from '../unit-math'; const baseScene = createBaseSceneSurfaceA(); - - - const leftStartBox = ` scene.addOnIntersectionListener('robot', (type, otherNodeId) => { @@ -22,33 +19,53 @@ scene.addOnIntersectionListener('robot', (type, otherNodeId) => { }, 'startBox'); `; - - - const goingBackwards = ` - +let degrees = []; scene.addOnRenderListener(() => { + const EULER_IDENTITY = Rotation.Euler.identity(); const xAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.X, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.X)); - - console.log("Robot orientation: " + xAngle('robot')); + let angle = xAngle('robot'); + console.log(angle); + if(angle >= 179 && angle <= 180){ + degrees[0] = 0; + degrees[1] = 180; + + } + if(angle <= 1 && (degrees[1] == 180)&& ((scene.nodes['robot'].state.motors[0].pwm > scene.nodes['robot'].state.motors[3].pwm) || scene.nodes['robot'].state.motors[3].direction === 2)){ + scene.setChallengeEventValue('counterClockwise360', true); + degrees.pop(); + degrees.pop(); + } + else if (angle <=1 && (degrees[1] == 180) && (scene.nodes['robot'].state.motors[3].pwm > scene.nodes['robot'].state.motors[0].pwm) && scene.nodes['robot'].state.motors[3].direction != 2 ) + { + scene.setChallengeEventValue('clockwise360', true); + degrees.pop(); + degrees.pop(); + } + console.log("0 PDM: " + scene.nodes['robot'].state.motors[0].pwm); + console.log("3 PDM: " + scene.nodes['robot'].state.motors[3].pwm); + console.log("0 direction: " + scene.nodes['robot'].state.motors[0].direction); + console.log("3 direction: " + scene.nodes['robot'].state.motors[3].direction); + console.log(degrees) ; }); `; - export const JBC_5: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 5' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 5: Dance Party' }, + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 5: Dance Party', + }, scripts: { - goingBackwards: Script.ecmaScript("Going Backwards", goingBackwards), - leftStartBox: Script.ecmaScript("Robot Reentered Start", leftStartBox), + goingBackwards: Script.ecmaScript('Going Backwards', goingBackwards), + leftStartBox: Script.ecmaScript('Robot Reentered Start', leftStartBox), }, geometry: { ...baseScene.geometry, mainSurface_geom: { - type: "box", + type: 'box', size: { x: Distance.meters(3.54), y: Distance.centimeters(0.1), @@ -56,7 +73,7 @@ export const JBC_5: Scene = { }, }, startBox_geom: { - type: "box", + type: 'box', size: { x: Distance.meters(3.54), y: Distance.centimeters(0.1), @@ -67,9 +84,9 @@ export const JBC_5: Scene = { nodes: { ...baseScene.nodes, mainSurface: { - type: "object", - geometryId: "mainSurface_geom", - name: { [LocalizedString.EN_US]: "Mat Surface" }, + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, visible: false, origin: { position: { @@ -79,17 +96,17 @@ export const JBC_5: Scene = { }, }, material: { - type: "basic", + type: 'basic', color: { - type: "color3", + type: 'color3', color: Color.rgb(0, 0, 0), }, }, }, startBox: { - type: "object", - geometryId: "startBox_geom", - name: { [LocalizedString.EN_US]: "Start Box" }, + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, visible: false, origin: { position: { @@ -99,13 +116,12 @@ export const JBC_5: Scene = { }, }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, - }, -}; \ No newline at end of file +}; From 4764b48e9ecfec49f76d6be940fda4957ed3307d Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 17 Feb 2023 13:26:39 -0600 Subject: [PATCH 18/37] Finished JBC12 logic with testing --- src/challenges/jbc12.ts | 97 ++++++++++++++ src/scenes/jbc12.ts | 231 ++++++++++++++++++++++++++++++-- src/state/reducer/challenges.ts | 5 + 3 files changed, 323 insertions(+), 10 deletions(-) create mode 100644 src/challenges/jbc12.ts diff --git a/src/challenges/jbc12.ts b/src/challenges/jbc12.ts new file mode 100644 index 00000000..2218417b --- /dev/null +++ b/src/challenges/jbc12.ts @@ -0,0 +1,97 @@ +import Author from "../db/Author"; +import Challenge from "../state/State/Challenge"; +import Expr from "../state/State/Challenge/Expr"; +import LocalizedString from "../util/LocalizedString"; + +export default { + name: { [LocalizedString.EN_US]: "JBC Challenge 12" }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 12: Unload 'Em`, + }, + author: { + type: Author.Type.Organization, + id: "kipr", + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: "c", + events: { + can2Upright: { + name: { [LocalizedString.EN_US]: "Can 2 Upright" }, + description: { [LocalizedString.EN_US]: "Can 2 upright" }, + }, + can9Upright: { + name: { [LocalizedString.EN_US]: "Can 9 Upright" }, + description: { [LocalizedString.EN_US]: "Can 9 upright" }, + }, + can10Upright: { + name: { [LocalizedString.EN_US]: "Can 10 Upright" }, + description: { [LocalizedString.EN_US]: "Can 10 upright" }, + }, + + can2Intersects: { + name: { [LocalizedString.EN_US]: "Can 2 Intersects" }, + description: { [LocalizedString.EN_US]: "Can from green garage intersects circle 2" }, + }, + can9Intersects: { + name: { [LocalizedString.EN_US]: "Can 9 Intersects" }, + description: { [LocalizedString.EN_US]: "Can from blue garage intersects circle 9" }, + }, + can10Intersects: { + name: { [LocalizedString.EN_US]: "Can 10 Intersects" }, + description: { [LocalizedString.EN_US]: "Can from yellow garage intersects circle 10" }, + }, + }, + success: { + exprs: { + //Upright Events + can2Upright: { + type: Expr.Type.Event, + eventId: "can2Upright", + }, + can9Upright: { + type: Expr.Type.Event, + eventId: "can9Upright", + }, + can10Upright: { + type: Expr.Type.Event, + eventId: "can10Upright", + }, + cansUpright: { + type: Expr.Type.And, + argIds: ["can2Upright", "can9Upright", "can10Upright"], + }, + + + //Intersects Events + can2Intersects: { + type: Expr.Type.Event, + eventId: "can2Intersects", + }, + can9Intersects: { + type: Expr.Type.Event, + eventId: "can9Intersects", + }, + can10Intersects: { + type: Expr.Type.Event, + eventId: "can10Intersects", + }, + cansIntersects: { + type: Expr.Type.And, + argIds: ["can2Intersects", "can9Intersects", "can10Intersects"], + }, + + + // Success logic + completion: { + type: Expr.Type.And, + argIds: ["cansUpright", "cansIntersects"], + }, + }, + rootId: "completion", + }, + sceneId: "jbc12", +} as Challenge; diff --git a/src/scenes/jbc12.ts b/src/scenes/jbc12.ts index 3b95c267..d3ad6ce5 100644 --- a/src/scenes/jbc12.ts +++ b/src/scenes/jbc12.ts @@ -1,19 +1,230 @@ -import Scene from "../state/State/Scene"; -import { Distance } from "../util"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import Script from '../state/State/Scene/Script'; +import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import { Distance } from '../util'; const baseScene = createBaseSceneSurfaceA(); +const uprightCans = ` +// When a can is standing upright, the upright condition is met. + +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + // const currTime = Date.now(); + // const timeDiff = currTime - startTime; + const upright2 = yAngle('can2') < 5; + const upright9 = yAngle('can9') < 5; + const upright10 = yAngle('can10') < 5; + + scene.setChallengeEventValue('can2Upright', upright2); + scene.setChallengeEventValue('can9Upright', upright9); + scene.setChallengeEventValue('can10Upright', upright10); +}); +`; + + +const circleIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When the can (can2 in green garage) is intersecting circle4, the circle glows + +scene.addOnIntersectionListener('can2', (type, otherNodeId) => { + console.log('Can 2 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can2Intersects', visible); + setNodeVisible('circle2', visible); +}, 'circle2'); +// When the can (can9 in blue garage) is intersecting circle9, the circle glows + +scene.addOnIntersectionListener('can9', (type, otherNodeId) => { + console.log('Can 9 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can9Intersects', visible); + setNodeVisible('circle9', visible); +}, 'circle9'); + +// When the can (can10 in yellow garage) is intersecting circle10, the circle glows + +scene.addOnIntersectionListener('can10', (type, otherNodeId) => { + console.log('Can 10 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can10Intersects', visible); + setNodeVisible('circle10', visible); +}, 'circle10'); + +`; export const JBC_12: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 12' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 12: Unload 'Em` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 12: Unload 'Em`, + }, + + scripts: { + uprightCans: Script.ecmaScript('Upright Cans', uprightCans), + circleIntersects: Script.ecmaScript('Circle Intersects', circleIntersects), + }, + geometry: { + ...baseScene.geometry, + circle_geom: { + type: "cylinder", + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + + }, nodes: { ...baseScene.nodes, - 'can1': createCanNode(1, { x: Distance.centimeters(0), y: Distance.centimeters(0), z: Distance.centimeters(53.3) }), - 'can2': createCanNode(2, { x: Distance.centimeters(18.5), y: Distance.centimeters(0), z: Distance.centimeters(78) }), - 'can3': createCanNode(3, { x: Distance.centimeters(-12.3), y: Distance.centimeters(0), z: Distance.centimeters(93.9) }), - } -}; \ No newline at end of file + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + circle2: { + type: "object", + geometryId: "circle_geom", + name: { [LocalizedString.EN_US]: "Circle 2" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28.8), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + circle9: { + type: "object", + geometryId: "circle_geom", + name: { [LocalizedString.EN_US]: "Circle 9" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 9 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(85.4), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + circle10: { + type: "object", + geometryId: "circle_geom", + name: { [LocalizedString.EN_US]: "Circle 10" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(19.3),//can 10 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96.9), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can2: { + ...createCanNode(2, { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(53.3), + }), + scriptIds: ["uprightCans", "circleIntersects"], + }, + can10: { + ...createCanNode(9, { + x: Distance.centimeters(18.5), + y: Distance.centimeters(0), + z: Distance.centimeters(78), + }), + scriptIds: ["uprightCans", "circleIntersects"], + }, + can9: { + ...createCanNode(10, { + x: Distance.centimeters(-12.3), + y: Distance.centimeters(0), + z: Distance.centimeters(93.9), + }), + scriptIds: ["uprightCans", "circleIntersects"], + }, + + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index ec1283af..e5a2effd 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -27,6 +27,7 @@ import jbc7b from "../../challenges/jbc7b"; import jbc8 from "../../challenges/jbc8"; import jbc8b from "../../challenges/jbc8b"; import jbc10 from "../../challenges/jbc10"; +import jbc12 from "../../challenges/jbc12"; export namespace ChallengesAction { export interface LoadChallenge { @@ -195,6 +196,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc10, brief: ChallengeBrief.fromChallenge(jbc10), }), + 'jbc12': Async.loaded({ + value: jbc12, + brief: ChallengeBrief.fromChallenge(jbc12), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 9ac02fc3d0301c6cc86a7e13555269098b676d49 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Mon, 20 Feb 2023 12:49:52 -0600 Subject: [PATCH 19/37] Finished logic for JBC13, only thing left is to fix blue garage's orientation so not to detect non-intersecting cans --- src/challenges/jbc13.ts | 139 ++++++++++++++++++++ src/scenes/jbc13.ts | 219 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 6 + 3 files changed, 357 insertions(+), 7 deletions(-) create mode 100644 src/challenges/jbc13.ts diff --git a/src/challenges/jbc13.ts b/src/challenges/jbc13.ts new file mode 100644 index 00000000..d9e2b43a --- /dev/null +++ b/src/challenges/jbc13.ts @@ -0,0 +1,139 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 13' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 13: Clean the Mat`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + can2Intersects: { + name: { [LocalizedString.EN_US]: 'Can 2 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 2 intersects a garage' }, + }, + can5Intersects: { + name: { [LocalizedString.EN_US]: 'Can 5 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 5 intersects a garage' }, + }, + can8Intersects: { + name: { [LocalizedString.EN_US]: 'Can 8 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 8 intersects a garage' }, + }, + can10Intersects: { + name: { [LocalizedString.EN_US]: 'Can 10 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 10 intersects a garage' }, + }, + can11Intersects: { + name: { [LocalizedString.EN_US]: 'Can 11 Intersects' }, + description: { [LocalizedString.EN_US]: 'Can 11 intersects a garage' }, + }, + + can2Upright: { + name: { [LocalizedString.EN_US]: 'Can 2 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 2 upright in a garage' }, + }, + can5Upright: { + name: { [LocalizedString.EN_US]: 'Can 5 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 5 upright in a garage' }, + }, + can8Upright: { + name: { [LocalizedString.EN_US]: 'Can 8 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 8 upright in a garage' }, + }, + can10Upright: { + name: { [LocalizedString.EN_US]: 'Can 10 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 10 upright in a garage' }, + }, + can11Upright: { + name: { [LocalizedString.EN_US]: 'Can 11 Upright' }, + description: { [LocalizedString.EN_US]: 'Can 11 upright in a garage' }, + }, + + + }, + success: { + exprs: { + + // Intersects Events + can2Intersects: { + type: Expr.Type.Event, + eventId: 'can2Intersects', + }, + can5Intersects: { + type: Expr.Type.Event, + eventId: 'can5Intersects', + }, + can8Intersects: { + type: Expr.Type.Event, + eventId: 'can8Intersects', + }, + can10Intersects: { + type: Expr.Type.Event, + eventId: 'can10Intersects', + }, + can11Intersects: { + type: Expr.Type.Event, + eventId: 'can11Intersects', + }, + + cansIntersects: { + type: Expr.Type.And, + argIds: ['can2Intersects', 'can5Intersects', 'can8Intersects','can10Intersects', 'can11Intersects'], + }, + + //Upright Events + can2Upright: { + type: Expr.Type.Event, + eventId: 'can2Upright', + }, + can5Upright: { + type: Expr.Type.Event, + eventId: 'can5Upright', + }, + can8Upright: { + type: Expr.Type.Event, + eventId: 'can8Upright', + }, + can10Upright: { + type: Expr.Type.Event, + eventId: 'can10Upright', + }, + can11Upright: { + type: Expr.Type.Event, + eventId: 'can11Upright', + }, + + cansUpright: { + type: Expr.Type.And, + argIds: ['can2Upright', 'can5Upright','can8Upright','can10Upright', 'can11Upright'], + }, + + + //Success Logic = Can A upright, intersects and touched + completion: { + type: Expr.Type.And, + argIds: [ + + 'cansIntersects', + 'cansUpright' + + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc13', +} as Challenge; diff --git a/src/scenes/jbc13.ts b/src/scenes/jbc13.ts index ffa75f25..611d4dc9 100644 --- a/src/scenes/jbc13.ts +++ b/src/scenes/jbc13.ts @@ -1,20 +1,225 @@ import Scene from "../state/State/Scene"; -import LocalizedString from '../util/LocalizedString'; +import LocalizedString from "../util/LocalizedString"; +import Script from "../state/State/Scene/Script"; +import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; +import { Color } from "../state/State/Scene/Color"; +import { Distance , Angle} from "../util"; -import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; const baseScene = createBaseSceneSurfaceA(); +const garageIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +// When a can (can2, can5, can8, can10, can11) is intersecting a garage, the garage glows +let chosenGarage = []; +let garageCans = [] +let begin = 0; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + const visible = type === 'start'; + + //No chosen garage yet and enters + if(chosenGarage.length == 0){ + chosenGarage[0] = otherNodeId; + + setNodeVisible(chosenGarage[0], true); + } + + //If the garage the can moved into is the desired garage + if(otherNodeId == chosenGarage[0] && type === 'start'){ + console.log(nodeId +' placed!', type, otherNodeId); + garageCans.push(nodeId); + scene.setChallengeEventValue(nodeId + 'Intersects', true); + if(chosenGarage.length > 0){ + setNodeVisible(chosenGarage[0], true); + } + } + + //If a previously entered can leaves desired garage + if(otherNodeId == chosenGarage[0] && type === 'end' && (garageCans.includes(nodeId) == true)){ + const removeIndex = garageCans.indexOf(nodeId); + const x = garageCans.splice(removeIndex,1); + scene.setChallengeEventValue(nodeId + 'Intersects', false); + + } + + //If a previously enterted can in desired garage enters a different garage + else if(otherNodeId != chosenGarage[0] && (garageCans.includes(nodeId) == true)){ + const removeIndex = garageCans.indexOf(otherNodeId); + const x = garageCans.splice(removeIndex,1); + + + } + + + //If there aren't any cans in a garage, reset chosen garage + if(garageCans.length == 0){ + setNodeVisible(chosenGarage[0], false); + chosenGarage.pop(); + + } + + + console.log("Chosen Garage: " + chosenGarage); + console.log("Cans In Chosen Garage: " + garageCans); + }, ['yellowGarage','blueGarage','greenGarage']); + +} + +`; +const uprightCans = ` +// When a can is standing upright, the upright condition is met. +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + +scene.addOnRenderListener(() => { + const upright2 = yAngle('can2') < 5; + const upright5 = yAngle('can5') < 5; + const upright8 = yAngle('can8') < 5; + const upright10 = yAngle('can10') < 5; + const upright11 = yAngle('can11') < 5; + + scene.setChallengeEventValue('can2Upright', upright2); + scene.setChallengeEventValue('can5Upright', upright5); + scene.setChallengeEventValue('can8Upright', upright8); + scene.setChallengeEventValue('can10Upright', upright10); + scene.setChallengeEventValue('can11Upright', upright11); +}); +`; export const JBC_13: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 13' }, description: { [LocalizedString.EN_US]: `Junior Botball Challenge 13: Clean the Mat` }, + scripts: { + uprightCans: Script.ecmaScript("Upright Cans", uprightCans), + garageIntersects: Script.ecmaScript("Garage Intersects", garageIntersects), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + greenGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(20), + y: Distance.centimeters(0.1), + z: Distance.centimeters(20), + }, + }, + + blueGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(16), + y: Distance.centimeters(0.1), + z: Distance.centimeters(16), + }, + }, + yellowGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(16), + y: Distance.centimeters(0.1), + z: Distance.centimeters(18), + }, + }, + }, nodes: { ...baseScene.nodes, - 'can2': createCanNode(2), - 'can5': createCanNode(5), - 'can8': createCanNode(8), - 'can10': createCanNode(10), - 'can11': createCanNode(11), + greenGarage: { + type: "object", + geometryId: "greenGarage_geom", + name: { [LocalizedString.EN_US]: "Green Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + blueGarage: { + type: "object", + geometryId: "blueGarage_geom", + name: { [LocalizedString.EN_US]: "Blue Garage" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-13.4), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(96), + }, + // orientation: { + + // type: 'euler', + // x: Angle.degrees(0), + // y: Angle.degrees(-45), + // z: Angle.degrees(0), + // }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + + + }, + yellowGarage: { + type: "object", + geometryId: "yellowGarage_geom", + name: { [LocalizedString.EN_US]: "Yellow Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.8), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(78), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + can2: {...createCanNode(2), scriptIds: ["garageIntersects","uprightCans"]}, + can5: {...createCanNode(5), scriptIds: ["garageIntersects","uprightCans"]}, + can8: {...createCanNode(8), scriptIds: ["garageIntersects","uprightCans"]}, + can10: {...createCanNode(10), scriptIds: ["garageIntersects","uprightCans"]}, + can11: {...createCanNode(11), scriptIds: ["garageIntersects","uprightCans"]}, } }; \ No newline at end of file diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index e5a2effd..d19a57b8 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -28,6 +28,8 @@ import jbc8 from "../../challenges/jbc8"; import jbc8b from "../../challenges/jbc8b"; import jbc10 from "../../challenges/jbc10"; import jbc12 from "../../challenges/jbc12"; +import jbc13 from "../../challenges/jbc13"; + export namespace ChallengesAction { export interface LoadChallenge { @@ -200,6 +202,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc12, brief: ChallengeBrief.fromChallenge(jbc12), }), + 'jbc13': Async.loaded({ + value: jbc13, + brief: ChallengeBrief.fromChallenge(jbc13), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From fcbdb0df1887dc8f84437029c8e82ce6edf63cd4 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 21 Feb 2023 12:32:34 -0600 Subject: [PATCH 20/37] Finished JBC15b logic with testing --- src/challenges/jbc15b.ts | 85 ++++++++++++++++++++ src/scenes/jbc15b.ts | 136 +++++++++++++++++++++++++++++--- src/state/reducer/challenges.ts | 6 +- 3 files changed, 214 insertions(+), 13 deletions(-) create mode 100644 src/challenges/jbc15b.ts diff --git a/src/challenges/jbc15b.ts b/src/challenges/jbc15b.ts new file mode 100644 index 00000000..a910cb98 --- /dev/null +++ b/src/challenges/jbc15b.ts @@ -0,0 +1,85 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 15B' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 15B: Bump Bump`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + driveForwardTouch: { + name: { [LocalizedString.EN_US]: 'Robot Forward Touch' }, + description: { + [LocalizedString.EN_US]: + 'Robot drove forward and touched ream of paper', + }, + }, + + driveBackwardTouch: { + name: { [LocalizedString.EN_US]: 'Robot Backward Touch' }, + description: { + [LocalizedString.EN_US]: + 'Robot drove backward and touched ream of paper', + }, + }, + driveForward2: { + name: { [LocalizedString.EN_US]: 'Robot Forward Circle 2' }, + description: { + [LocalizedString.EN_US]: 'Robot drove forward to circle 2', + }, + }, + }, + success: { + exprs: { + //Ream Touching Events + driveForwardTouch: { + type: Expr.Type.Event, + eventId: 'driveForwardTouch', + }, + driveForwardTouchOnce: { + type: Expr.Type.Once, + argId: 'driveForwardTouch', + }, + driveBackwardTouch: { + type: Expr.Type.Event, + eventId: 'driveBackwardTouch', + }, + driveBackwardTouchOnce: { + type: Expr.Type.Once, + argId: 'driveBackwardTouch', + }, + driveForward2: { + type: Expr.Type.Event, + eventId: 'driveForward2', + }, + driveForward2Once: { + type: Expr.Type.Once, + argId: 'driveForward2', + }, + + completion: { + type: Expr.Type.And, + argIds: [ + 'driveForwardTouchOnce', + 'driveBackwardTouchOnce', + 'driveForward2Once', + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc15b', +} as Challenge; diff --git a/src/scenes/jbc15b.ts b/src/scenes/jbc15b.ts index 86ad6d17..f8e1a7cb 100644 --- a/src/scenes/jbc15b.ts +++ b/src/scenes/jbc15b.ts @@ -1,17 +1,67 @@ -import Scene from "../state/State/Scene"; -import { ReferenceFrame, Rotation } from "../unit-math"; -import { Distance, Mass } from "../util"; +import Scene from '../state/State/Scene'; +import { ReferenceFrame, Rotation } from '../unit-math'; +import { Distance, Mass } from '../util'; import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceA } from './jbcBase'; +import Script from '../state/State/Scene/Script'; +import { createCanNode, createBaseSceneSurfaceA } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; const baseScene = createBaseSceneSurfaceA(); +const bumpReam = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); +let count = 0; +let position = 0; + +scene.onBind = nodeId => { + + if(count == 3){ + count = 0; + } + scene.addOnCollisionListener('robot', (otherNodeId, point) => { + + //If front bumper is pressed + if(scene.nodes['robot'].state.digitalValues[0] === true) { + count = 1; + scene.setChallengeEventValue('driveForwardTouch', true); + console.log("Touched 1st ream"); + } + + //If either left or right back bumpers are pressed and front touch sensor was pressed first + if((scene.nodes['robot'].state.digitalValues[1] === true || scene.nodes['robot'].state.digitalValues[2] === true) && count == 1) + { + count = 2; + scene.setChallengeEventValue('driveBackwardTouch', true); + console.log("Touched 2nd ream"); + } + + + }, ['ream1','ream2',]); + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + //If touching first (front) and second (back) paper reams then going to circle 2 + if(count == 2){ + const visible = type === 'start'; + console.log('Robot intersecting circle 2!', type, otherNodeId); + scene.setChallengeEventValue('driveForward2', visible); + setNodeVisible('circle2', visible); + count = 3; + } + }, 'circle2'); + +}; + +`; + const ROBOT_ORIGIN: ReferenceFrame = { ...baseScene.nodes['robot'].origin, position: { ...baseScene.nodes['robot'].origin.position, - z: Distance.centimeters(7) + z: Distance.centimeters(7), }, }; @@ -31,7 +81,7 @@ const REAM2_ORIGIN: ReferenceFrame = { position: { x: Distance.centimeters(0), y: Distance.centimeters(5), - z: Distance.centimeters(-6.3), + z: Distance.centimeters(-12), }, orientation: Rotation.AxisAngle.fromRaw({ axis: { x: 1, y: 0, z: 0 }, @@ -42,17 +92,66 @@ const REAM2_ORIGIN: ReferenceFrame = { export const JBC_15B: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 15B' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 15B: Bump Bump` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 15B: Bump Bump`, + }, + scripts: { + bumpReam: Script.ecmaScript('Bump Ream', bumpReam), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + circle2_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + }, nodes: { ...baseScene.nodes, // The normal starting position of the robot doesn't leave room for the paper ream in the starting box // Start the robot forward a bit so that a ream fits behind it - 'robot': { + robot: { ...baseScene.nodes['robot'], startingOrigin: ROBOT_ORIGIN, origin: ROBOT_ORIGIN, }, - 'ream1': { + circle2: { + type: 'object', + geometryId: 'circle2_geom', + name: { [LocalizedString.EN_US]: 'Circle 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), //can 2 + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28.8), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + ream1: { type: 'from-template', templateId: 'ream', name: { [LocalizedString.EN_US]: 'Paper Ream 1' }, @@ -60,7 +159,7 @@ export const JBC_15B: Scene = { origin: REAM1_ORIGIN, visible: true, }, - 'ream2': { + ream2: { type: 'from-template', templateId: 'ream', name: { [LocalizedString.EN_US]: 'Paper Ream 2' }, @@ -68,5 +167,18 @@ export const JBC_15B: Scene = { origin: REAM2_ORIGIN, visible: true, }, + can12: { //Created an invisible can to attach script + ...createCanNode( + 12, + { + x: Distance.centimeters(11), + y: Distance.centimeters(0), + z: Distance.centimeters(91), + }, + false, + false + ), + scriptIds: ['bumpReam'], + }, }, -}; \ No newline at end of file +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index d19a57b8..5af9356c 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -29,7 +29,7 @@ import jbc8b from "../../challenges/jbc8b"; import jbc10 from "../../challenges/jbc10"; import jbc12 from "../../challenges/jbc12"; import jbc13 from "../../challenges/jbc13"; - +import jbc15b from "../../challenges/jbc15b"; export namespace ChallengesAction { export interface LoadChallenge { @@ -206,6 +206,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc13, brief: ChallengeBrief.fromChallenge(jbc13), }), + 'jbc15b': Async.loaded({ + value: jbc15b, + brief: ChallengeBrief.fromChallenge(jbc15b), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From ec2a41121c18da03ea2e9291b3b7ba67f1924f18 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 21 Feb 2023 14:25:54 -0600 Subject: [PATCH 21/37] Finished JBC17 logic with testing --- src/challenges/jbc17.ts | 50 ++++++++ src/scenes/jbc17.ts | 212 +++++++++++++++++++++++++++++++- src/state/reducer/challenges.ts | 5 + 3 files changed, 261 insertions(+), 6 deletions(-) create mode 100644 src/challenges/jbc17.ts diff --git a/src/challenges/jbc17.ts b/src/challenges/jbc17.ts new file mode 100644 index 00000000..7a4ec117 --- /dev/null +++ b/src/challenges/jbc17.ts @@ -0,0 +1,50 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 17' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 17: Walk the Line`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + lineFollow: { + name: { [LocalizedString.EN_US]: 'Robot Walks the Line' }, + description: { + [LocalizedString.EN_US]: + 'Robot uses reflectance sensor to follow the black line until Finish Line ', + }, + }, + }, + success: { + exprs: { + //Line Following Event + lineFollow: { + type: Expr.Type.Event, + eventId: 'lineFollow', + }, + + + completion: { + type: Expr.Type.And, + argIds: [ + 'lineFollow', + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc17', +} as Challenge; diff --git a/src/scenes/jbc17.ts b/src/scenes/jbc17.ts index 429c540c..cd4298ac 100644 --- a/src/scenes/jbc17.ts +++ b/src/scenes/jbc17.ts @@ -1,13 +1,213 @@ -import Scene from "../state/State/Scene"; -import { Distance } from "../util"; +import Scene from '../state/State/Scene'; +import { Distance } from '../util'; import LocalizedString from '../util/LocalizedString'; - -import { createBaseSceneSurfaceB } from './jbcBase'; +import { ReferenceFrame, Rotation } from '../unit-math'; +import { createCanNode, createBaseSceneSurfaceB } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import Script from '../state/State/Scene/Script'; const baseScene = createBaseSceneSurfaceB(); +const lineFollow = ` + +scene.onBind = nodeId => { + let count = 0; + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + //Reset counter if robot in start box + if(otherNodeId == 'startBox' && type === 'start'){ + count = 0; + } + //1st checkpoint + if(otherNodeId == 'n1' && type === 'start' && count == 0){ + count = 1; + console.log("Robot passed checkpoint 1"); + } + //2nd checkpoint + else if (otherNodeId == 'n2' && type === 'start' && count == 1){ + count = 2; + console.log("Robot passed checkpoint 2 after checkpoint 1"); + } + //3rd checkpoint + else if(otherNodeId == 'n3' && type === 'start'&& count == 2){ + count = 3; + console.log("Robot passed checkpoint 3 after checkpoint 2"); + } + //Finish line after all other checkpoints + else if(otherNodeId == 'finishLine' && type === 'start' && count == 3){ + console.log("Robot completed the course!"); + scene.setChallengeEventValue('lineFollow', true); + } + + console.log("Count: " + count); + }, ['finishLine', 'n1', 'n2', 'n3', 'startBox']); + +}; + +`; +const ROBOT_ORIGIN: ReferenceFrame = { + ...baseScene.nodes['robot'].origin, + position: { + ...baseScene.nodes['robot'].origin.position, + x: Distance.centimeters(-15), + }, +}; export const JBC_17: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 17' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 17: Walk the Line' }, -}; \ No newline at end of file + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 17: Walk the Line', + }, + scripts: { + lineFollow: Script.ecmaScript('Line Follow', lineFollow), + }, + geometry: { + ...baseScene.geometry, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(1.22), + y: Distance.centimeters(0.1), + z: Distance.centimeters(10), + }, + }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(1), + height: Distance.centimeters(0.1), + }, + finish_geom: { + type: 'box', + size: { + x: Distance.centimeters(25), + y: Distance.centimeters(0.1), + z: Distance.centimeters(3.54), + }, + }, + }, + nodes: { + ...baseScene.nodes, + robot: { + ...baseScene.nodes['robot'], + startingOrigin: ROBOT_ORIGIN, + origin: ROBOT_ORIGIN, + }, + finishLine: { + type: 'object', + geometryId: 'finish_geom', + name: { [LocalizedString.EN_US]: 'Finish Line' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(18), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-5), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Finish Line' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-70), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 1' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-18), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 3' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(18), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(61), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 2' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(105), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can12: { + //Created an invisible can to attach script + ...createCanNode( + 12, + { + x: Distance.centimeters(11), + y: Distance.centimeters(0), + z: Distance.centimeters(91), + }, + false, + false + ), + scriptIds: ['lineFollow'], + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 5af9356c..c91153cc 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -30,6 +30,7 @@ import jbc10 from "../../challenges/jbc10"; import jbc12 from "../../challenges/jbc12"; import jbc13 from "../../challenges/jbc13"; import jbc15b from "../../challenges/jbc15b"; +import jbc17 from "../../challenges/jbc17"; export namespace ChallengesAction { export interface LoadChallenge { @@ -210,6 +211,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc15b, brief: ChallengeBrief.fromChallenge(jbc15b), }), + 'jbc17': Async.loaded({ + value: jbc17, + brief: ChallengeBrief.fromChallenge(jbc17), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 69f611f7f7494ba0fc55c21a1575716a6721ea53 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Tue, 21 Feb 2023 14:28:19 -0600 Subject: [PATCH 22/37] Turned of JBC17 geometry visibility --- src/scenes/jbc17.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scenes/jbc17.ts b/src/scenes/jbc17.ts index cd4298ac..2a90520a 100644 --- a/src/scenes/jbc17.ts +++ b/src/scenes/jbc17.ts @@ -96,7 +96,7 @@ export const JBC_17: Scene = { type: 'object', geometryId: 'finish_geom', name: { [LocalizedString.EN_US]: 'Finish Line' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(18), @@ -116,7 +116,7 @@ export const JBC_17: Scene = { type: 'object', geometryId: 'startBox_geom', name: { [LocalizedString.EN_US]: 'Finish Line' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-70), @@ -137,7 +137,7 @@ export const JBC_17: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Checkpoint 1' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-18), @@ -158,7 +158,7 @@ export const JBC_17: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Checkpoint 3' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(18), @@ -179,7 +179,7 @@ export const JBC_17: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Checkpoint 2' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), From 167128f51df1942f5c869c33e5f230b9e2e492a4 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 22 Feb 2023 09:31:16 -0600 Subject: [PATCH 23/37] Finished JBC19 logic with testing --- src/challenges/jbc19.ts | 137 ++++++++++++++++++++++++++++ src/scenes/jbc19.ts | 154 +++++++++++++++++++++++++++++--- src/state/reducer/challenges.ts | 5 ++ 3 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 src/challenges/jbc19.ts diff --git a/src/challenges/jbc19.ts b/src/challenges/jbc19.ts new file mode 100644 index 00000000..997c44e5 --- /dev/null +++ b/src/challenges/jbc19.ts @@ -0,0 +1,137 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 19' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 19: Mountain Rescue`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + can1Upright: { + name: { [LocalizedString.EN_US]: 'Can 1 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 1 is upright', + }, + }, + can2Upright: { + name: { [LocalizedString.EN_US]: 'Can 2 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 2 is upright', + }, + }, + can3Upright: { + name: { [LocalizedString.EN_US]: 'Can 3 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 3 is upright', + }, + }, + can1Intersects: { + name: { [LocalizedString.EN_US]: 'Can 1 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 1 rescued intersecting starting box', + }, + }, + can2Intersects: { + name: { [LocalizedString.EN_US]: 'Can 2 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 2 rescued intersecting starting box', + }, + }, + can3Intersects: { + name: { [LocalizedString.EN_US]: 'Can 3 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 3 rescued intersecting starting box', + }, + }, + }, + success: { + exprs: { + //Rescued upright can events + can1Upright: { + type: Expr.Type.Event, + eventId: 'can1Upright', + }, + can1UprightOnce: { + type: Expr.Type.Once, + argId: 'can1Upright', + }, + can2Upright: { + type: Expr.Type.Event, + eventId: 'can2Upright', + }, + can2UprightOnce: { + type: Expr.Type.Once, + argId: 'can2Upright', + }, + can3Upright: { + type: Expr.Type.Event, + eventId: 'can3Upright', + }, + can3UprightOnce: { + type: Expr.Type.Once, + argId: 'can3Upright', + }, + + //Rescued intersecting can events + can1Intersects: { + type: Expr.Type.Event, + eventId: 'can1Intersects', + }, + can1IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can1Intersects', + }, + can2Intersects: { + type: Expr.Type.Event, + eventId: 'can2Intersects', + }, + can2IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can2Intersects', + }, + can3Intersects: { + type: Expr.Type.Event, + eventId: 'can3Intersects', + }, + can3IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can3Intersects', + }, + + //Intersecting and Upright + IntersectingUpright1: { + type: Expr.Type.And, + argIds: ['can1UprightOnce','can1IntersectsOnce'], + }, + IntersectingUpright2: { + type: Expr.Type.And, + argIds: ['can2UprightOnce','can2IntersectsOnce'], + }, + IntersectingUpright3: { + type: Expr.Type.And, + argIds: ['can3UprightOnce','can3IntersectsOnce'], + }, + + + completion: { + type: Expr.Type.And, + argIds: ['IntersectingUpright1','IntersectingUpright2','IntersectingUpright3'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc19', +} as Challenge; diff --git a/src/scenes/jbc19.ts b/src/scenes/jbc19.ts index b342c5f0..60e6e7de 100644 --- a/src/scenes/jbc19.ts +++ b/src/scenes/jbc19.ts @@ -1,12 +1,49 @@ -import Scene from "../state/State/Scene"; -import { Rotation, ReferenceFrame } from "../unit-math"; -import { Distance, Mass } from "../util"; +import Scene from '../state/State/Scene'; +import { Rotation, ReferenceFrame } from '../unit-math'; +import { Distance, Mass } from '../util'; import LocalizedString from '../util/LocalizedString'; - +import { Color } from '../state/State/Scene/Color'; import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import Script from "../state/State/Scene/Script"; const baseScene = createBaseSceneSurfaceA(); +const startBoxIntersects = ` + +scene.onBind = nodeId => { + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + console.log(nodeId + "entered start box!"); + const visible = type === 'start'; + scene.setChallengeEventValue(nodeId+'Intersects', visible); + }, 'startBox'); + +}; + + +`; + + + +const uprightCans = ` +// When a can is standing upright on the ream, the upright condition is met. + + +const EULER_IDENTITY = Rotation.Euler.identity(); +const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); +scene.addOnRenderListener(() => { + + const upright1 = yAngle('can1') < 5; + const upright2 = yAngle('can2') < 5; + const upright3 = yAngle('can3') < 5; + + scene.setChallengeEventValue('can1Upright', upright1); + scene.setChallengeEventValue('can2Upright', upright2); + scene.setChallengeEventValue('can3Upright', upright3); + + +}); + +`; const REAM_ORIGIN: ReferenceFrame = { position: { x: Distance.centimeters(-10), @@ -22,13 +59,108 @@ const REAM_ORIGIN: ReferenceFrame = { export const JBC_19: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 19' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 19: Mountain Rescue` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 19: Mountain Rescue`, + }, + scripts: { + uprightCans: Script.ecmaScript('Upright Cans', uprightCans), + startBoxIntersects: Script.ecmaScript('Start Box Intersects', startBoxIntersects), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(25), + }, + }, + circle2_geom: { + type: 'cylinder', + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + }, nodes: { ...baseScene.nodes, - 'can1': createCanNode(1, { x: Distance.centimeters(-3), y: Distance.centimeters(6), z: Distance.centimeters(98.6) }), - 'can2': createCanNode(2, { x: Distance.centimeters(-10), y: Distance.centimeters(6), z: Distance.centimeters(91.6) }), - 'can3': createCanNode(3, { x: Distance.centimeters(-17), y: Distance.centimeters(6), z: Distance.centimeters(84.6) }), - 'ream': { + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(3), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can1: { + ...createCanNode(1, { + x: Distance.centimeters(-3), + y: Distance.centimeters(6), + z: Distance.centimeters(98.6), + }), + scriptIds: ['uprightCans', 'startBoxIntersects'], + }, + + can2: { + ...createCanNode(1, { + x: Distance.centimeters(-10), + y: Distance.centimeters(6), + z: Distance.centimeters(91.6), + }), + scriptIds: ['uprightCans', 'startBoxIntersects'], + }, + + can3: { + ...createCanNode(1, { + x: Distance.centimeters(-17), + y: Distance.centimeters(6), + z: Distance.centimeters(84.6), + }), + scriptIds: ['uprightCans', 'startBoxIntersects'], + }, + + ream: { type: 'from-template', templateId: 'ream', name: { [LocalizedString.EN_US]: 'Paper Ream' }, @@ -36,5 +168,5 @@ export const JBC_19: Scene = { origin: REAM_ORIGIN, visible: true, }, - } -}; \ No newline at end of file + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index c91153cc..b889e66f 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -31,6 +31,7 @@ import jbc12 from "../../challenges/jbc12"; import jbc13 from "../../challenges/jbc13"; import jbc15b from "../../challenges/jbc15b"; import jbc17 from "../../challenges/jbc17"; +import jbc19 from "../../challenges/jbc19"; export namespace ChallengesAction { export interface LoadChallenge { @@ -215,6 +216,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc17, brief: ChallengeBrief.fromChallenge(jbc17), }), + 'jbc19': Async.loaded({ + value: jbc19, + brief: ChallengeBrief.fromChallenge(jbc19), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 84ff654a29fc6b542bd604602ef98113eae22158 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 22 Feb 2023 13:12:51 -0600 Subject: [PATCH 24/37] Finished JBC20 logic with testing --- src/challenges/jbc20.ts | 178 ++++++++++++++++++++++++++++++++ src/scenes/jbc20.ts | 73 ++++++++++--- src/state/reducer/challenges.ts | 5 + 3 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 src/challenges/jbc20.ts diff --git a/src/challenges/jbc20.ts b/src/challenges/jbc20.ts new file mode 100644 index 00000000..cd095600 --- /dev/null +++ b/src/challenges/jbc20.ts @@ -0,0 +1,178 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 20' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 20: Rescue the Cans`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + + can2Upright: { + name: { [LocalizedString.EN_US]: 'Can 2 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 2 is upright', + }, + }, + can9Upright: { + name: { [LocalizedString.EN_US]: 'Can 9 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 9 is upright', + }, + }, + can10Upright: { + name: { [LocalizedString.EN_US]: 'Can 10 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 10 is upright', + }, + }, + can12Upright: { + name: { [LocalizedString.EN_US]: 'Can 12 Upright' }, + description: { + [LocalizedString.EN_US]: 'Can 12 is upright', + }, + }, + + can9Intersects: { + name: { [LocalizedString.EN_US]: 'Can 9 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 9 rescued intersecting paper ream', + }, + }, + can2Intersects: { + name: { [LocalizedString.EN_US]: 'Can 2 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 2 rescued intersecting paper ream', + }, + }, + can10Intersects: { + name: { [LocalizedString.EN_US]: 'Can 10 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 10 rescued intersecting paper ream', + }, + }, + can12Intersects: { + name: { [LocalizedString.EN_US]: 'Can 12 Intersects' }, + description: { + [LocalizedString.EN_US]: 'Can 12 rescued intersecting paper ream', + }, + }, + }, + success: { + exprs: { + //Rescued upright can events + can9Upright: { + type: Expr.Type.Event, + eventId: 'can9Upright', + }, + can9UprightOnce: { + type: Expr.Type.Once, + argId: 'can9Upright', + }, + can2Upright: { + type: Expr.Type.Event, + eventId: 'can2Upright', + }, + can2UprightOnce: { + type: Expr.Type.Once, + argId: 'can2Upright', + }, + can10Upright: { + type: Expr.Type.Event, + eventId: 'can10Upright', + }, + can10UprightOnce: { + type: Expr.Type.Once, + argId: 'can10Upright', + }, + can12Upright: { + type: Expr.Type.Event, + eventId: 'can12Upright', + }, + can12UprightOnce: { + type: Expr.Type.Once, + argId: 'can12Upright', + }, + + + //Rescued intersecting can events + can9Intersects: { + type: Expr.Type.Event, + eventId: 'can9Intersects', + }, + can9IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can9Intersects', + }, + can2Intersects: { + type: Expr.Type.Event, + eventId: 'can2Intersects', + }, + can2IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can2Intersects', + }, + can10Intersects: { + type: Expr.Type.Event, + eventId: 'can10Intersects', + }, + can10IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can10Intersects', + }, + can12Intersects: { + type: Expr.Type.Event, + eventId: 'can12Intersects', + }, + can12IntersectsOnce: { + type: Expr.Type.Once, + argId: 'can12Intersects', + }, + + + //Intersecting and Upright + IntersectingUpright9: { + type: Expr.Type.And, + argIds: ['can9Upright', 'can9Intersects'], + }, + IntersectingUpright2: { + type: Expr.Type.And, + argIds: ['can2Upright', 'can2Intersects'], + }, + IntersectingUpright10: { + type: Expr.Type.And, + argIds: ['can10Upright', 'can10Intersects'], + }, + IntersectingUpright12: { + type: Expr.Type.And, + argIds: ['can12Upright', 'can12Intersects'], + }, + + + completion: { + type: Expr.Type.And, + argIds: [ + 'IntersectingUpright9', + 'IntersectingUpright2', + 'IntersectingUpright10', + 'IntersectingUpright12' + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc20', +} as Challenge; diff --git a/src/scenes/jbc20.ts b/src/scenes/jbc20.ts index 61e4e7c7..d080dfdb 100644 --- a/src/scenes/jbc20.ts +++ b/src/scenes/jbc20.ts @@ -1,17 +1,47 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import { ReferenceFrame } from '../unit-math'; -import { Distance, Mass } from "../util"; +import { Distance, Mass } from '../util'; import LocalizedString from '../util/LocalizedString'; - +import Script from '../state/State/Scene/Script'; import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +const uprightCans = ` +// When a can is standing upright on the ream, the upright condition is met. + + +scene.onBind = nodeId => { + const EULER_IDENTITY = Rotation.Euler.identity(); + const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); + + scene.addOnRenderListener(() => { + + const canUpright2 = yAngle('can2') < 5; + const canUpright9 = yAngle('can9') < 5; + const canUpright10 = yAngle('can10') < 5; + const canUpright12 = yAngle('can12') < 5; + scene.setChallengeEventValue('can2Upright', canUpright2); + scene.setChallengeEventValue('can9Upright', canUpright9); + scene.setChallengeEventValue('can10Upright', canUpright10); + scene.setChallengeEventValue('can12Upright', canUpright12); + + }); + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + const visible = type === 'start'; + scene.setChallengeEventValue(nodeId +'Intersects', visible); + + }, 'ream'); + +}; + +`; + const baseScene = createBaseSceneSurfaceA(); const ROBOT_ORIGIN: ReferenceFrame = { ...baseScene.nodes['robot'].origin, position: { ...baseScene.nodes['robot'].origin.position, - x: Distance.centimeters(18) + x: Distance.centimeters(18), }, }; @@ -26,21 +56,38 @@ const REAM_ORIGIN: ReferenceFrame = { export const JBC_20: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 20' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 20: Rescue the Cans` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 20: Rescue the Cans`, + }, + scripts: { + uprightCans: Script.ecmaScript('Upright Cans', uprightCans), + }, nodes: { ...baseScene.nodes, // The normal starting position of the robot doesn't leave room for the paper ream in the starting box // Start the robot on the left side so that a ream fits on the right side - 'robot': { + robot: { ...baseScene.nodes['robot'], startingOrigin: ROBOT_ORIGIN, - origin: ROBOT_ORIGIN + origin: ROBOT_ORIGIN, + }, + can2: { + ...createCanNode(2), + scriptIds: ['uprightCans'], + }, + can9: { + ...createCanNode(9), + scriptIds: ['uprightCans'], }, - 'can2': createCanNode(2), - 'can9': createCanNode(9), - 'can10': createCanNode(10), - 'can12': createCanNode(12), - 'ream': { + can10: { + ...createCanNode(10), + scriptIds: ['uprightCans'], + }, + can12: { + ...createCanNode(12), + scriptIds: ['uprightCans'], + }, + ream: { type: 'from-template', templateId: 'ream', name: { [LocalizedString.EN_US]: 'Paper Ream' }, @@ -49,4 +96,4 @@ export const JBC_20: Scene = { visible: true, }, }, -}; \ No newline at end of file +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index b889e66f..ac932abb 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -32,6 +32,7 @@ import jbc13 from "../../challenges/jbc13"; import jbc15b from "../../challenges/jbc15b"; import jbc17 from "../../challenges/jbc17"; import jbc19 from "../../challenges/jbc19"; +import jbc20 from "../../challenges/jbc20"; export namespace ChallengesAction { export interface LoadChallenge { @@ -220,6 +221,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc19, brief: ChallengeBrief.fromChallenge(jbc19), }), + 'jbc20': Async.loaded({ + value: jbc20, + brief: ChallengeBrief.fromChallenge(jbc20), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 5459973bfb9ca9436b645505bf7ddcf270a71cf9 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 22 Feb 2023 16:01:33 -0600 Subject: [PATCH 25/37] Started JBC21 --- src/challenges/jbc21.ts | 45 +++++++++++++++++++++++ src/scenes/jbc21.ts | 65 ++++++++++++++++++++++++++++++--- src/state/reducer/challenges.ts | 5 +++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/challenges/jbc21.ts diff --git a/src/challenges/jbc21.ts b/src/challenges/jbc21.ts new file mode 100644 index 00000000..0505bcb8 --- /dev/null +++ b/src/challenges/jbc21.ts @@ -0,0 +1,45 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 21' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 21: Foot Tall`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + footTallMark: { + name: { [LocalizedString.EN_US]: 'Can 9 Lifted' }, + description: { + [LocalizedString.EN_US]: 'Can 9 Lifted a Foot Tall', + }, + }, + }, + success: { + exprs: { + footTallMark: { + type: Expr.Type.Event, + eventId: 'footTallMark', + }, + + completion: { + type: Expr.Type.And, + argIds: ['footTallMark'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc21', +} as Challenge; diff --git a/src/scenes/jbc21.ts b/src/scenes/jbc21.ts index f3e5291b..fe0df04e 100644 --- a/src/scenes/jbc21.ts +++ b/src/scenes/jbc21.ts @@ -1,16 +1,69 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; - +import { Distance } from '../util'; import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import Script from '../state/State/Scene/Script'; const baseScene = createBaseSceneSurfaceA(); +const footTallBox = ` + +scene.addOnIntersectionListener('can9', (type, otherNodeId) => { + console.log('Bottom of can 9 is at the foot tall mark!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('footTallMark', type === 'end'); + } + +}, 'footTall'); +`; + export const JBC_21: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 21' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 21: Foot Tall` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 21: Foot Tall`, + }, + scripts: { + footTallBox: Script.ecmaScript('Foot Tall Cutoff', footTallBox), + }, + geometry: { + ...baseScene.geometry, + footTall_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + }, nodes: { ...baseScene.nodes, - 'can9': createCanNode(9), - } -}; \ No newline at end of file + footTall: { + type: 'object', + geometryId: 'footTall_geom', + name: { [LocalizedString.EN_US]: 'Foot Tall Cutoff' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), //circle 6 + y: Distance.inches(11), + z: Distance.centimeters(57.2), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can9: { + ...createCanNode(9), + scriptIds: ["footTallBox"], + + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index ac932abb..35fa5d1e 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -33,6 +33,7 @@ import jbc15b from "../../challenges/jbc15b"; import jbc17 from "../../challenges/jbc17"; import jbc19 from "../../challenges/jbc19"; import jbc20 from "../../challenges/jbc20"; +import jbc21 from "../../challenges/jbc21"; export namespace ChallengesAction { export interface LoadChallenge { @@ -225,6 +226,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc20, brief: ChallengeBrief.fromChallenge(jbc20), }), + 'jbc21': Async.loaded({ + value: jbc21, + brief: ChallengeBrief.fromChallenge(jbc21), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From 5af0301fa52f01107010b1cb7f03296207cef384 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 24 Feb 2023 12:15:55 -0600 Subject: [PATCH 26/37] Working on JBC22 node parentId --- src/SceneBinding.ts | 6 +- src/challenges/jbc22.ts | 54 ++++++++++++++ src/scenes/jbc22.ts | 124 ++++++++++++++++++++++++++++++-- src/state/reducer/challenges.ts | 5 ++ 4 files changed, 180 insertions(+), 9 deletions(-) create mode 100644 src/challenges/jbc22.ts diff --git a/src/SceneBinding.ts b/src/SceneBinding.ts index 75d15cc2..e65072cd 100644 --- a/src/SceneBinding.ts +++ b/src/SceneBinding.ts @@ -951,6 +951,7 @@ class SceneBinding { }; private updateNode_ = async (id: string, node: Patch, geometryPatches: Dict>, nextScene: Scene): Promise => { + switch (node.type) { // The node hasn't changed type, but some fields have been changed case Patch.Type.InnerChange: { @@ -1211,7 +1212,7 @@ class SceneBinding { for (const nodeId of nodeIds) { const node = patch.nodes[nodeId]; if (node.type !== Patch.Type.Remove) continue; - + console.log("Node from setScene(forloop): " + node); await this.updateNode_(nodeId, node, patch.geometry, scene); delete this.nodes_[nodeId]; @@ -1226,7 +1227,8 @@ class SceneBinding { for (const nodeId of sortedNodeIds) { if (removedKeys.has(nodeId)) continue; const node = patch.nodes[nodeId]; - + console.log("Node from setScene: " + node + " with nodeId: " + nodeId); + const updatedNode = await this.updateNode_(nodeId, node, patch.geometry, scene); if (updatedNode) { this.nodes_[nodeId] = updatedNode; diff --git a/src/challenges/jbc22.ts b/src/challenges/jbc22.ts new file mode 100644 index 00000000..32b2f500 --- /dev/null +++ b/src/challenges/jbc22.ts @@ -0,0 +1,54 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 22' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 22: Stackerz`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + + + leaveStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Left Start' }, + description: { [LocalizedString.EN_US]: 'Robot left starting box' }, + }, + + + }, + success: { + exprs: { + + + //Upright Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: 'leaveStartBox', + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: 'leaveStartBox', + }, + + completion: { + type: Expr.Type.And, + argIds: ['leaveStartBoxOnce'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc22', +} as Challenge; diff --git a/src/scenes/jbc22.ts b/src/scenes/jbc22.ts index 44f86f02..4a45c08e 100644 --- a/src/scenes/jbc22.ts +++ b/src/scenes/jbc22.ts @@ -1,17 +1,127 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; - +import { Distance } from '../util'; import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import Script from '../state/State/Scene/Script'; const baseScene = createBaseSceneSurfaceA(); +const leftStartBox = ` + +scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot left start box!', type, otherNodeId); + if(scene.programStatus === 'running'){ + scene.setChallengeEventValue('leaveStartBox', type === 'end'); + } + +}, 'startBox'); +`; export const JBC_22: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 22' }, - description: { [LocalizedString.EN_US]: `Junior Botball Challenge 22: Stackerz` }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 22: Stackerz`, + }, + scripts: { + leftStartBox: Script.ecmaScript('Robot Left Start', leftStartBox), + }, + geometry: { + ...baseScene.geometry, + + mainSurface_geom: { + type: 'box', + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(1.77), + y: Distance.centimeters(0.1), + z: Distance.centimeters(30), + }, + }, + canEnd_geom: { + type: 'cylinder', + + radius: Distance.centimeters(3), + height: Distance.centimeters(0.1), + }, + }, + nodes: { ...baseScene.nodes, - 'can5': createCanNode(5), - 'can7': createCanNode(7), - } -}; \ No newline at end of file + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + can5: createCanNode(5), + can7: createCanNode(7), + canEnd: { + parentId: 'ground', + type: 'object', + geometryId: 'canEnd_geom', + name: { [LocalizedString.EN_US]: 'Bottom or Top of a can' }, + + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(0), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + + }, + + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 35fa5d1e..8a71e209 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -34,6 +34,7 @@ import jbc17 from "../../challenges/jbc17"; import jbc19 from "../../challenges/jbc19"; import jbc20 from "../../challenges/jbc20"; import jbc21 from "../../challenges/jbc21"; +import jbc22 from "../../challenges/jbc22"; export namespace ChallengesAction { export interface LoadChallenge { @@ -230,6 +231,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc21, brief: ChallengeBrief.fromChallenge(jbc21), }), + 'jbc22': Async.loaded({ + value: jbc22, + brief: ChallengeBrief.fromChallenge(jbc22), + }), }; const create = async (challengeId: string, next: Async.Creating) => { From a4e84986230d12374e86a05beadab988e8939885 Mon Sep 17 00:00:00 2001 From: Braden McDorman Date: Tue, 28 Feb 2023 21:21:26 +0000 Subject: [PATCH 27/37] Fix undefined nodeId --- src/state/State/Scene/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/state/State/Scene/index.ts b/src/state/State/Scene/index.ts index 1511933f..d664801c 100644 --- a/src/state/State/Scene/index.ts +++ b/src/state/State/Scene/index.ts @@ -105,8 +105,9 @@ namespace Scene { const queue = [...rootNodes]; const visited = new Set(); const ret: string[] = []; + - while (visited.size < Object.keys(scene.nodes).length) { + while (queue.length > 0) { const next = queue.shift(); if (visited.has(next)) continue; visited.add(next); From af745db32c4c385a41428a47759a9f910dabd772 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 1 Mar 2023 13:38:16 -0600 Subject: [PATCH 28/37] Working on JBC3 --- dependencies/libwallaby | 2 +- i18n/i18n.json | 1069 +++++++++++++++++++++++++++++++ src/SceneBinding.ts | 2 - src/challenges/jbc3.ts | 94 +++ src/scenes/jbc3.ts | 356 +++++++++- src/state/reducer/challenges.ts | 7 +- 6 files changed, 1523 insertions(+), 7 deletions(-) create mode 100644 i18n/i18n.json create mode 100644 src/challenges/jbc3.ts diff --git a/dependencies/libwallaby b/dependencies/libwallaby index 3327a44c..e63f9bd5 160000 --- a/dependencies/libwallaby +++ b/dependencies/libwallaby @@ -1 +1 @@ -Subproject commit 3327a44c2b7539311444ccfbe05e89648356caac +Subproject commit e63f9bd5d171a6d8d095d32b3fdb3ee966bb0844 diff --git a/i18n/i18n.json b/i18n/i18n.json new file mode 100644 index 00000000..c8d19cbf --- /dev/null +++ b/i18n/i18n.json @@ -0,0 +1,1069 @@ +{ + "": { + "Robot": { + "en-US": "Robot" + }, + "Base Scene - Surface A": { + "en-US": "Base Scene - Surface A" + }, + "A base scene using Surface A. Intended to be augmented to create full JBC scenes": { + "en-US": "A base scene using Surface A. Intended to be augmented to create full JBC scenes" + }, + "JBC Surface A": { + "en-US": "JBC Surface A" + }, + "Ground": { + "en-US": "Ground" + }, + "Light": { + "en-US": "Light" + }, + "Base Scene - Surface B": { + "en-US": "Base Scene - Surface B" + }, + "A base scene using Surface B. Intended to be augmented to create full JBC scenes": { + "en-US": "A base scene using Surface B. Intended to be augmented to create full JBC scenes" + }, + "JBC Surface B": { + "en-US": "JBC Surface B" + }, + "Can %s": { + "en-US": "Can %s" + }, + "JBC Sandbox A": { + "en-US": "JBC Sandbox A" + }, + "Junior Botball Challenge Sandbox on Mat A. All cans 1-12 are available by default.": { + "en-US": "Junior Botball Challenge Sandbox on Mat A. All cans 1-12 are available by default." + }, + "Paper Ream 1": { + "en-US": "Paper Ream 1" + }, + "Paper Ream 2": { + "en-US": "Paper Ream 2" + }, + "JBC Sandbox B": { + "en-US": "JBC Sandbox B" + }, + "Junior Botball Challenge Sandbox on Mat B.": { + "en-US": "Junior Botball Challenge Sandbox on Mat B." + }, + "JBC 1": { + "en-US": "JBC 1" + }, + "Junior Botball Challenge 1: Tag, You're It!": { + "en-US": "Junior Botball Challenge 1: Tag, You're It!" + }, + "JBC 2": { + "en-US": "JBC 2" + }, + "Junior Botball Challenge 2: Ring Around the Can": { + "en-US": "Junior Botball Challenge 2: Ring Around the Can" + }, + "JBC 2B": { + "en-US": "JBC 2B" + }, + "Junior Botball Challenge 2B: Ring Around the Can, Sr.": { + "en-US": "Junior Botball Challenge 2B: Ring Around the Can, Sr." + }, + "JBC 2C": { + "en-US": "JBC 2C" + }, + "Junior Botball Challenge 2C: Back It Up": { + "en-US": "Junior Botball Challenge 2C: Back It Up" + }, + "JBC 2D": { + "en-US": "JBC 2D" + }, + "Junior Botball Challenge 2D: Ring Around the Can and Back It Up": { + "en-US": "Junior Botball Challenge 2D: Ring Around the Can and Back It Up" + }, + "JBC 3": { + "en-US": "JBC 3" + }, + "Junior Botball Challenge 3: Precision Parking": { + "en-US": "Junior Botball Challenge 3: Precision Parking" + }, + "JBC 3B": { + "en-US": "JBC 3B" + }, + "Junior Botball Challenge 3B: Parallel Parking": { + "en-US": "Junior Botball Challenge 3B: Parallel Parking" + }, + "JBC 3C": { + "en-US": "JBC 3C" + }, + "Junior Botball Challenge 3C: Quick Get Away!": { + "en-US": "Junior Botball Challenge 3C: Quick Get Away!" + }, + "JBC 4": { + "en-US": "JBC 4" + }, + "Junior Botball Challenge 4: Figure Eight": { + "en-US": "Junior Botball Challenge 4: Figure Eight" + }, + "JBC 4B": { + "en-US": "JBC 4B" + }, + "Junior Botball Challenge 4B: Barrel Racing": { + "en-US": "Junior Botball Challenge 4B: Barrel Racing" + }, + "JBC 5": { + "en-US": "JBC 5" + }, + "Junior Botball Challenge 5: Dance Party": { + "en-US": "Junior Botball Challenge 5: Dance Party" + }, + "JBC 5B": { + "en-US": "JBC 5B" + }, + "Junior Botball Challenge 5B: Line Dance": { + "en-US": "Junior Botball Challenge 5B: Line Dance" + }, + "JBC 5C": { + "en-US": "JBC 5C" + }, + "Junior Botball Challenge 5C: Synchronized Dancing": { + "en-US": "Junior Botball Challenge 5C: Synchronized Dancing" + }, + "JBC 6": { + "en-US": "JBC 6" + }, + "Junior Botball Challenge 6: Load 'Em Up": { + "en-US": "Junior Botball Challenge 6: Load 'Em Up" + }, + "JBC 6B": { + "en-US": "JBC 6B" + }, + "Junior Botball Challenge 6B: Pick 'Em Up": { + "en-US": "Junior Botball Challenge 6B: Pick 'Em Up" + }, + "JBC 6C": { + "en-US": "JBC 6C" + }, + "Junior Botball Challenge 6C: Empty the Garage": { + "en-US": "Junior Botball Challenge 6C: Empty the Garage" + }, + "Circle 2": { + "en-US": "Circle 2" + }, + "Circle 9": { + "en-US": "Circle 9" + }, + "Circle 10": { + "en-US": "Circle 10" + }, + "Mat Surface": { + "en-US": "Mat Surface" + }, + "JBC 7": { + "en-US": "JBC 7" + }, + "Junior Botball Challenge 7: Bulldozer Mania": { + "en-US": "Junior Botball Challenge 7: Bulldozer Mania" + }, + "JBC 7B": { + "en-US": "JBC 7B" + }, + "Junior Botball Challenge 7B: Cover Your Bases": { + "en-US": "Junior Botball Challenge 7B: Cover Your Bases" + }, + "JBC 8": { + "en-US": "JBC 8" + }, + "Junior Botball Challenge 8: Serpentine": { + "en-US": "Junior Botball Challenge 8: Serpentine" + }, + "JBC 8B": { + "en-US": "JBC 8B" + }, + "Junior Botball Challenge 8B: Serpentine Jr.": { + "en-US": "Junior Botball Challenge 8B: Serpentine Jr." + }, + "JBC 9": { + "en-US": "JBC 9" + }, + "Junior Botball Challenge 9: Add It Up": { + "en-US": "Junior Botball Challenge 9: Add It Up" + }, + "JBC 9B": { + "en-US": "JBC 9B" + }, + "Junior Botball Challenge 9B: Balancing Act": { + "en-US": "Junior Botball Challenge 9B: Balancing Act" + }, + "JBC 10": { + "en-US": "JBC 10" + }, + "Junior Botball Challenge 10: Solo Joust": { + "en-US": "Junior Botball Challenge 10: Solo Joust" + }, + "JBC 10B": { + "en-US": "JBC 10B" + }, + "Junior Botball Challenge 10: Solo Joust Jr.": { + "en-US": "Junior Botball Challenge 10: Solo Joust Jr." + }, + "JBC 12": { + "en-US": "JBC 12" + }, + "Junior Botball Challenge 12: Unload 'Em": { + "en-US": "Junior Botball Challenge 12: Unload 'Em" + }, + "JBC 13": { + "en-US": "JBC 13" + }, + "Junior Botball Challenge 13: Clean the Mat": { + "en-US": "Junior Botball Challenge 13: Clean the Mat" + }, + "JBC 15B": { + "en-US": "JBC 15B" + }, + "Junior Botball Challenge 15B: Bump Bump": { + "en-US": "Junior Botball Challenge 15B: Bump Bump" + }, + "JBC 17": { + "en-US": "JBC 17" + }, + "Junior Botball Challenge 17: Walk the Line": { + "en-US": "Junior Botball Challenge 17: Walk the Line" + }, + "JBC 17B": { + "en-US": "JBC 17B" + }, + "Junior Botball Challenge 17: Walk the Line II": { + "en-US": "Junior Botball Challenge 17: Walk the Line II" + }, + "JBC 19": { + "en-US": "JBC 19" + }, + "Junior Botball Challenge 19: Mountain Rescue": { + "en-US": "Junior Botball Challenge 19: Mountain Rescue" + }, + "Paper Ream": { + "en-US": "Paper Ream" + }, + "JBC 20": { + "en-US": "JBC 20" + }, + "Junior Botball Challenge 20: Rescue the Cans": { + "en-US": "Junior Botball Challenge 20: Rescue the Cans" + }, + "JBC 21": { + "en-US": "JBC 21" + }, + "Junior Botball Challenge 21: Foot Tall": { + "en-US": "Junior Botball Challenge 21: Foot Tall" + }, + "JBC 22": { + "en-US": "JBC 22" + }, + "Junior Botball Challenge 22: Stackerz": { + "en-US": "Junior Botball Challenge 22: Stackerz" + }, + "Script Playground": { + "en-US": "Script Playground" + }, + "Script tests": { + "en-US": "Script tests" + }, + "Demobot": { + "en-US": "Demobot" + }, + "JBC Challenge 6C": { + "en-US": "JBC Challenge 6C" + }, + "Can A Lifted": { + "en-US": "Can A Lifted" + }, + "Can A picked up": { + "en-US": "Can A picked up" + }, + "Can B Lifted": { + "en-US": "Can B Lifted" + }, + "Can B picked up": { + "en-US": "Can B picked up" + }, + "Can C Lifted": { + "en-US": "Can C Lifted" + }, + "Can C picked up": { + "en-US": "Can C picked up" + }, + "Can A Placed": { + "en-US": "Can A Placed" + }, + "Can A placed on circle 2": { + "en-US": "Can A placed on circle 2" + }, + "Can B Placed": { + "en-US": "Can B Placed" + }, + "Can A placed on circle 9": { + "en-US": "Can A placed on circle 9" + }, + "Can C Placed": { + "en-US": "Can C Placed" + }, + "Can A placed on circle 10": { + "en-US": "Can A placed on circle 10" + }, + "Can A Upright": { + "en-US": "Can A Upright" + }, + "Can A upright on circle 2": { + "en-US": "Can A upright on circle 2" + }, + "Can B Upright": { + "en-US": "Can B Upright" + }, + "Can B upright on circle 9": { + "en-US": "Can B upright on circle 9" + }, + "Can C Upright": { + "en-US": "Can C Upright" + }, + "Can C upright on circle 10": { + "en-US": "Can C upright on circle 10" + }, + "Loading...": { + "en-US": "Loading..." + }, + "Logout": { + "en-US": "Logout" + }, + "Tutorials": { + "en-US": "Tutorials" + }, + "Learn how to get started with the simulator": { + "en-US": "Learn how to get started with the simulator" + }, + "3D Simulator": { + "en-US": "3D Simulator" + }, + "A simulator for the Botball demobot.": { + "en-US": "A simulator for the Botball demobot." + }, + "About": { + "en-US": "About" + }, + "KIPR is a 501(c) 3 organization started to make the long-term educational benefits of robotics accessible to students.": { + "en-US": "KIPR is a 501(c) 3 organization started to make the long-term educational benefits of robotics accessible to students." + }, + "Quick Start": { + "en-US": "Quick Start" + }, + "Navigating in 3D": { + "en-US": "Navigating in 3D" + }, + "Learn the controls for navigating in 3D in the simulator": { + "en-US": "Learn the controls for navigating in 3D in the simulator" + }, + "Robot Section": { + "en-US": "Robot Section" + }, + "How to use the robot section": { + "en-US": "How to use the robot section" + }, + "World Section": { + "en-US": "World Section" + }, + "Learn how to create and manipulate items and scene in the simulator": { + "en-US": "Learn how to create and manipulate items and scene in the simulator" + }, + "Indent": { + "en-US": "Indent" + }, + "Download": { + "en-US": "Download" + }, + "Reset": { + "en-US": "Reset" + }, + "Error(s)": { + "en-US": "Error(s)" + }, + "Warning(s)": { + "en-US": "Warning(s)" + }, + "grams": { + "en-US": "grams" + }, + "kilograms": { + "en-US": "kilograms" + }, + "pounds": { + "en-US": "pounds" + }, + "ounces": { + "en-US": "ounces" + }, + "meters": { + "en-US": "meters" + }, + "centimeters": { + "en-US": "centimeters" + }, + "feet": { + "en-US": "feet" + }, + "inches": { + "en-US": "inches" + }, + "radians": { + "en-US": "radians" + }, + "degrees": { + "en-US": "degrees" + }, + "Can": { + "en-US": "Can" + }, + "Box": { + "en-US": "Box" + }, + "Sphere": { + "en-US": "Sphere" + }, + "Cylinder": { + "en-US": "Cylinder" + }, + "Cone": { + "en-US": "Cone" + }, + "Plane": { + "en-US": "Plane" + }, + "File": { + "en-US": "File" + }, + "Euler": { + "en-US": "Euler" + }, + "Axis Angle": { + "en-US": "Axis Angle" + }, + "Empty": { + "en-US": "Empty" + }, + "Standard Object": { + "en-US": "Standard Object" + }, + "Custom Object": { + "en-US": "Custom Object" + }, + "Point Light": { + "en-US": "Point Light" + }, + "Unset": { + "en-US": "Unset" + }, + "Basic": { + "en-US": "Basic" + }, + "Texture": { + "en-US": "Texture" + }, + "Value": { + "en-US": "Value" + }, + "General": { + "en-US": "General" + }, + "Name": { + "en-US": "Name" + }, + "Type": { + "en-US": "Type" + }, + "Geometry": { + "en-US": "Geometry" + }, + "Item": { + "en-US": "Item" + }, + "Box Options": { + "en-US": "Box Options" + }, + "Size X": { + "en-US": "Size X" + }, + "Size Y": { + "en-US": "Size Y" + }, + "Size Z": { + "en-US": "Size Z" + }, + "Sphere Options": { + "en-US": "Sphere Options" + }, + "Radius": { + "en-US": "Radius" + }, + "Cylinder Options": { + "en-US": "Cylinder Options" + }, + "Height": { + "en-US": "Height" + }, + "Plane Options": { + "en-US": "Plane Options" + }, + "File Options": { + "en-US": "File Options" + }, + "URI": { + "en-US": "URI" + }, + "Material": { + "en-US": "Material" + }, + "Color Type": { + "en-US": "Color Type" + }, + "Color Red": { + "en-US": "Color Red" + }, + "Color Green": { + "en-US": "Color Green" + }, + "Color Blue": { + "en-US": "Color Blue" + }, + "Color Texture URI": { + "en-US": "Color Texture URI" + }, + "Albedo Type": { + "en-US": "Albedo Type" + }, + "Albedo Red": { + "en-US": "Albedo Red" + }, + "Albedo Green": { + "en-US": "Albedo Green" + }, + "Albedo Blue": { + "en-US": "Albedo Blue" + }, + "Albedo Texture URI": { + "en-US": "Albedo Texture URI" + }, + "Reflection Type": { + "en-US": "Reflection Type" + }, + "Reflection Red": { + "en-US": "Reflection Red" + }, + "Reflection Green": { + "en-US": "Reflection Green" + }, + "Reflection Blue": { + "en-US": "Reflection Blue" + }, + "Reflection Texture URI": { + "en-US": "Reflection Texture URI" + }, + "Emissive Type": { + "en-US": "Emissive Type" + }, + "Emissive Red": { + "en-US": "Emissive Red" + }, + "Emissive Green": { + "en-US": "Emissive Green" + }, + "Emissive Blue": { + "en-US": "Emissive Blue" + }, + "Emissive Texture URI": { + "en-US": "Emissive Texture URI" + }, + "Ambient Type": { + "en-US": "Ambient Type" + }, + "Ambient Red": { + "en-US": "Ambient Red" + }, + "Ambient Green": { + "en-US": "Ambient Green" + }, + "Ambient Blue": { + "en-US": "Ambient Blue" + }, + "Ambient Texture URI": { + "en-US": "Ambient Texture URI" + }, + "Metalness Type": { + "en-US": "Metalness Type" + }, + "Metalness": { + "en-US": "Metalness" + }, + "Metalness Texture URI": { + "en-US": "Metalness Texture URI" + }, + "Position": { + "en-US": "Position" + }, + "X": { + "en-US": "X" + }, + "Y": { + "en-US": "Y" + }, + "Z": { + "en-US": "Z" + }, + "Orientation": { + "en-US": "Orientation" + }, + "Order": { + "en-US": "Order" + }, + "Angle": { + "en-US": "Angle" + }, + "Scale": { + "en-US": "Scale" + }, + "Physics": { + "en-US": "Physics" + }, + "Mass": { + "en-US": "Mass" + }, + "Friction": { + "en-US": "Friction" + }, + "Unnamed Object": { + "en-US": "Unnamed Object" + }, + "Add Item": { + "en-US": "Add Item" + }, + "Accept": { + "en-US": "Accept" + }, + "Settings": { + "en-US": "Settings" + }, + "Add Script": { + "en-US": "Add Script" + }, + "Select Scene": { + "en-US": "Select Scene" + }, + "Save Scene": { + "en-US": "Save Scene" + }, + "Copy Scene": { + "en-US": "Copy Scene" + }, + "Item(s) (%d)": { + "en-US": "Item(s) (%d)" + }, + "Script(s) (%d)": { + "en-US": "Script(s) (%d)" + }, + "Layouts": { + "en-US": "Layouts" + }, + "Overlay": { + "en-US": "Overlay" + }, + "Side": { + "en-US": "Side" + }, + "Options": { + "en-US": "Options" + }, + "Show All": { + "en-US": "Show All" + }, + "Hide All": { + "en-US": "Hide All" + }, + "Clear": { + "en-US": "Clear" + }, + "Rotation": { + "en-US": "Rotation" + }, + "Start Location": { + "en-US": "Start Location" + }, + "Motor Velocity Plot": { + "en-US": "Motor Velocity Plot" + }, + "Motor Position Plot": { + "en-US": "Motor Position Plot" + }, + "Analog Sensor Plot": { + "en-US": "Analog Sensor Plot" + }, + "Digital Sensor Plot": { + "en-US": "Digital Sensor Plot" + }, + "Analog Sensors": { + "en-US": "Analog Sensors" + }, + "Digital Sensors": { + "en-US": "Digital Sensors" + }, + "Servos": { + "en-US": "Servos" + }, + "Motor Velocities": { + "en-US": "Motor Velocities" + }, + "Motor Positions": { + "en-US": "Motor Positions" + }, + "This process is taking longer than expected...\nIf you have a poor internet connection, this can take some time": { + "en-US": "This process is taking longer than expected...\nIf you have a poor internet connection, this can take some time" + }, + "The simulator may have failed to load.\nPlease submit a feedback form to let us know!": { + "en-US": "The simulator may have failed to load.\nPlease submit a feedback form to let us know!" + }, + "Initializing Simulator...": { + "en-US": "Initializing Simulator..." + }, + "all of": { + "en-US": "all of" + }, + "one or more of": { + "en-US": "one or more of" + }, + "exactly one of": { + "en-US": "exactly one of" + }, + "once": { + "en-US": "once" + }, + "not": { + "en-US": "not" + }, + "Success": { + "en-US": "Success" + }, + "Failure": { + "en-US": "Failure" + }, + "Editor": { + "en-US": "Editor" + }, + "World": { + "en-US": "World" + }, + "Script Editor": { + "en-US": "Script Editor" + }, + "Console": { + "en-US": "Console" + }, + "Open": { + "en-US": "Open" + }, + "Save": { + "en-US": "Save" + }, + "Save As": { + "en-US": "Save As" + }, + "Delete": { + "en-US": "Delete" + }, + "Documentation": { + "en-US": "Documentation" + }, + "Feedback": { + "en-US": "Feedback" + }, + "Reset World": { + "en-US": "Reset World" + }, + "Layout": { + "en-US": "Layout" + }, + "User Interface": { + "en-US": "User Interface" + }, + "Simulation": { + "en-US": "Simulation" + }, + "Locale": { + "en-US": "Locale" + }, + "Switch languages": { + "en-US": "Switch languages" + }, + "Sensor noise": { + "en-US": "Sensor noise" + }, + "Controls whether sensor outputs are affected by random noise": { + "en-US": "Controls whether sensor outputs are affected by random noise" + }, + "Realistic sensors": { + "en-US": "Realistic sensors" + }, + "Controls whether sensors behave like real-world sensors instead of like ideal sensors. For example, real-world ET sensors are nonlinear": { + "en-US": "Controls whether sensors behave like real-world sensors instead of like ideal sensors. For example, real-world ET sensors are nonlinear" + }, + "Autocomplete": { + "en-US": "Autocomplete" + }, + "Controls autocompletion of code, brackets, and quotes": { + "en-US": "Controls autocompletion of code, brackets, and quotes" + }, + "Version %s (%s)": { + "en-US": "Version %s (%s)" + }, + "Copyright": { + "en-US": "Copyright" + }, + "This software is licensed under the terms of the": { + "en-US": "This software is licensed under the terms of the" + }, + "Thank you to the following contributors and testers:": { + "en-US": "Thank you to the following contributors and testers:" + }, + "Want to help improve the simulator and get your name listed here?": { + "en-US": "Want to help improve the simulator and get your name listed here?" + }, + "GitHub repository": { + "en-US": "GitHub repository" + }, + "We're happy to help you get started!": { + "en-US": "We're happy to help you get started!" + }, + "Give a helpful description of a problem you're facing, or a feature you'd like to request": { + "en-US": "Give a helpful description of a problem you're facing, or a feature you'd like to request" + }, + "Thanks for using the KIPR Simulator! Find a bug? Have a feature request? Let us know!": { + "en-US": "Thanks for using the KIPR Simulator! Find a bug? Have a feature request? Let us know!" + }, + "How has your experience using the KIPR Simulator been?": { + "en-US": "How has your experience using the KIPR Simulator been?" + }, + "Email (optional): ": { + "en-US": "Email (optional): " + }, + "Include anonymous usage data to help KIPR developers": { + "en-US": "Include anonymous usage data to help KIPR developers" + }, + "Please try again,": { + "en-US": "Please try again," + }, + "open an issue on our github page": { + "en-US": "open an issue on our github page" + }, + ", or": { + "en-US": ", or" + }, + "email KIPR.": { + "en-US": "email KIPR." + }, + "Submit": { + "en-US": "Submit" + }, + "Feedback Success": { + "en-US": "Feedback Success" + }, + "Feedback successfully submitted!": { + "en-US": "Feedback successfully submitted!" + }, + "Thank you for helping improve the KIPR Simulator!": { + "en-US": "Thank you for helping improve the KIPR Simulator!" + }, + "Open World": { + "en-US": "Open World" + }, + "Unknown": { + "en-US": "Unknown" + }, + "Description: ": { + "en-US": "Description: " + }, + "Author: ": { + "en-US": "Author: " + }, + "Me": { + "en-US": "Me" + }, + "Select a scene to see more details": { + "en-US": "Select a scene to see more details" + }, + "Description": { + "en-US": "Description" + }, + "New World": { + "en-US": "New World" + }, + "Create": { + "en-US": "Create" + }, + "Delete %s?": { + "en-US": "Delete %s?" + }, + "Are you sure you want to delete %s?": { + "en-US": "Are you sure you want to delete %s?" + }, + "Copy World": { + "en-US": "Copy World" + }, + "Error %d": { + "en-US": "Error %d" + }, + "Closing this dialog will take you back to the last well-known state.": { + "en-US": "Closing this dialog will take you back to the last well-known state." + }, + "If this error persists, please submit feedback.": { + "en-US": "If this error persists, please submit feedback." + }, + "World Settings": { + "en-US": "World Settings" + }, + "CHALLENGE": { + "en-US": "CHALLENGE" + }, + "Start": { + "en-US": "Start" + }, + "Welcome to the KIPR Simulator!\n": { + "en-US": "Welcome to the KIPR Simulator!\n" + }, + "Compiling...\n": { + "en-US": "Compiling...\n" + }, + "Compilation succeeded with warnings.\n": { + "en-US": "Compilation succeeded with warnings.\n" + }, + "Compilation succeeded.\n": { + "en-US": "Compilation succeeded.\n" + }, + "Compilation failed.\n": { + "en-US": "Compilation failed.\n" + }, + "Something went wrong during compilation.\n": { + "en-US": "Something went wrong during compilation.\n" + }, + "Compilation succeeded with warnings\n": { + "en-US": "Compilation succeeded with warnings\n" + }, + "Compilation succeeded\n": { + "en-US": "Compilation succeeded\n" + }, + "Modules": { + "en-US": "Modules" + }, + "Functions": { + "en-US": "Functions" + }, + "Structures": { + "en-US": "Structures" + }, + "Enumerations": { + "en-US": "Enumerations" + }, + "Files": { + "en-US": "Files" + }, + "Search...": { + "en-US": "Search..." + }, + "Detailed Description": { + "en-US": "Detailed Description" + }, + "Parameters": { + "en-US": "Parameters" + }, + "Return Value": { + "en-US": "Return Value" + }, + "Fields": { + "en-US": "Fields" + }, + "Volume": { + "en-US": "Volume" + }, + "RGB": { + "en-US": "RGB" + }, + "Challenge": { + "en-US": "Challenge" + }, + "Stop": { + "en-US": "Stop" + }, + "Run": { + "en-US": "Run" + }, + "and External Contributors": { + "en-US": "and External Contributors" + }, + "Visit our": { + "en-US": "Visit our" + } + }, + "Volume (box) in the 3D scene": { + "Volume": { + "en-US": "Volume" + } + }, + "Red, Green, Blue": { + "RGB": { + "en-US": "RGB" + } + }, + "Computer text command line (e.g., DOS)": { + "Console": { + "en-US": "Console" + } + }, + "A predefined task for the user to complete": { + "Challenge": { + "en-US": "Challenge" + } + }, + "Terminate program execution": { + "Stop": { + "en-US": "Stop" + } + }, + "Begin program execution": { + "Run": { + "en-US": "Run" + } + }, + "Part of copyright notice, after KIPR is listed": { + "and External Contributors": { + "en-US": "and External Contributors" + } + }, + "URL link to github repository follows": { + "Visit our": { + "en-US": "Visit our" + } + }, + "Rotation order": { + "XYZ": { + "en-US": "XYZ" + }, + "YZX": { + "en-US": "YZX" + }, + "ZXY": { + "en-US": "ZXY" + }, + "XZY": { + "en-US": "XZY" + }, + "YXZ": { + "en-US": "YXZ" + }, + "ZYX": { + "en-US": "ZYX" + } + } +} \ No newline at end of file diff --git a/src/SceneBinding.ts b/src/SceneBinding.ts index e65072cd..eb3d662b 100644 --- a/src/SceneBinding.ts +++ b/src/SceneBinding.ts @@ -1212,7 +1212,6 @@ class SceneBinding { for (const nodeId of nodeIds) { const node = patch.nodes[nodeId]; if (node.type !== Patch.Type.Remove) continue; - console.log("Node from setScene(forloop): " + node); await this.updateNode_(nodeId, node, patch.geometry, scene); delete this.nodes_[nodeId]; @@ -1227,7 +1226,6 @@ class SceneBinding { for (const nodeId of sortedNodeIds) { if (removedKeys.has(nodeId)) continue; const node = patch.nodes[nodeId]; - console.log("Node from setScene: " + node + " with nodeId: " + nodeId); const updatedNode = await this.updateNode_(nodeId, node, patch.geometry, scene); if (updatedNode) { diff --git a/src/challenges/jbc3.ts b/src/challenges/jbc3.ts new file mode 100644 index 00000000..56c160db --- /dev/null +++ b/src/challenges/jbc3.ts @@ -0,0 +1,94 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 3' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 3: Precision Parking`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + touchGarageLines: { + name: { [LocalizedString.EN_US]: 'Robot Touched Garage Lines' }, + description: { + [LocalizedString.EN_US]: 'Robot touched garage boundaries', + }, + }, + singleGarageRun1: { + name: { [LocalizedString.EN_US]: 'Robot Parked in One Garage' }, + description: { + [LocalizedString.EN_US]: 'Robot parked in only one garage', + }, + }, + singleGarageRun2: { + name: { [LocalizedString.EN_US]: 'Robot Parked in Different Garage' }, + description: { + [LocalizedString.EN_US]: 'Robot parked in a different garage', + }, + }, + + returnStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Returned Start' }, + description: { [LocalizedString.EN_US]: 'Robot returned to starting box' }, + }, + }, + success: { + exprs: { + //Garage Events + touchGarageLines: { + type: Expr.Type.Event, + eventId: 'touchGarageLines', + }, + touchGarageLinesNot: { + type: Expr.Type.Not, + argId: 'touchGarageLines', + }, + singleGarageRun1: { + type: Expr.Type.Event, + eventId: 'singleGarageRun1', + }, + singleGarageRun1Once: { + type: Expr.Type.Once, + argId: 'singleGarageRun1', + }, + singleGarageRun2: { + type: Expr.Type.Event, + eventId: 'singleGarageRun2', + }, + singleGarageRun2Once: { + type: Expr.Type.Once, + argId: 'singleGarageRun2', + }, + + + //Start Box Events + returnStartBox: { + type: Expr.Type.Event, + eventId: 'returnStartBox', + }, + returnStartBoxOnce: { + type: Expr.Type.Once, + argId: 'returnStartBox', + }, + + completion: { + type: Expr.Type.And, + argIds: ['singleGarageRun1Once', 'returnStartBoxOnce','singleGarageRun2Once', 'touchGarageLinesNot'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc3', +} as Challenge; diff --git a/src/scenes/jbc3.ts b/src/scenes/jbc3.ts index 17488818..f4cbbe6c 100644 --- a/src/scenes/jbc3.ts +++ b/src/scenes/jbc3.ts @@ -1,12 +1,362 @@ import Scene from "../state/State/Scene"; import LocalizedString from '../util/LocalizedString'; +import Script from '../state/State/Scene/Script'; +import { Distance , Angle} from "../util"; +import { createBaseSceneSurfaceA, createCanNode} from './jbcBase'; +import {Rotation } from "../unit-math"; +import { Color } from '../state/State/Scene/Color'; +const baseScene = createBaseSceneSurfaceA(); + +const garageIntersects = ` +const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { + ...scene.nodes[nodeId], + visible +}); + +let chosenGarage = []; +scene.onBind = nodeId => { + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + console.log('Robot touched: ', otherNodeId); + const visible = type === 'start'; + chosenGarage.pop(); + }, ['startBox']); + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + // if(chosenGarage.length == 0){ + // chosenGarage[0] == otherNodeId; + + // } + if(chosenGarage.length < 1 && otherNodeId == 'n1') { + chosenGarage.push('greenGarage'); + console.log('Robot: ', type, otherNodeId); + const visible = type === 'start'; + setNodeVisible('greenGarage', true); + } + console.log("Chosen Garages: " + chosenGarage); + }, ['n1', ]); + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + if(otherNodeId == 'n2'){ + console.log('Robot touched: greenGarage right boundary'); + const visible = type === 'start'; + //setNodeVisible('n2', visible); + scene.setChallengeEventValue('touchGarageLines', true); + } + }, ['n2']); + + +} +`; + -import { createBaseSceneSurfaceA } from './jbcBase'; -const baseScene = createBaseSceneSurfaceA(); export const JBC_3: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 3' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 3: Precision Parking' }, -}; \ No newline at end of file + scripts: { + + garageIntersects: Script.ecmaScript("Garage Intersects", garageIntersects), + }, + geometry: { + ...baseScene.geometry, + mainSurface_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.meters(3.54), + }, + }, + startBox_geom: { + type: "box", + size: { + x: Distance.meters(3.54), + y: Distance.centimeters(0.1), + z: Distance.centimeters(0), + }, + }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(0.01), + height: Distance.centimeters(0.1), + }, + greenGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(18), + y: Distance.centimeters(0.1), + z: Distance.centimeters(18), + }, + }, + greenGarageL_geom: { + type: "box", + size: { + x: Distance.centimeters(0.01), + y: Distance.centimeters(0.1), + z: Distance.centimeters(22), + }, + }, + greenGarageR_geom: { + type: "box", + size: { + x: Distance.centimeters(0.1), + y: Distance.centimeters(0.01), + z: Distance.centimeters(18), + }, + }, + greenGarageT_geom: { + type: "box", + size: { + x: Distance.centimeters(24), + y: Distance.centimeters(0.1), + z: Distance.centimeters(1), + }, + }, + + + blueGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(18), + y: Distance.centimeters(0.1), + z: Distance.centimeters(18), + }, + }, + yellowGarage_geom: { + type: "box", + size: { + x: Distance.centimeters(16), + y: Distance.centimeters(0.1), + z: Distance.centimeters(18), + }, + }, + }, + nodes: { + ...baseScene.nodes, + mainSurface: { + type: "object", + geometryId: "mainSurface_geom", + name: { [LocalizedString.EN_US]: "Mat Surface" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: "object", + geometryId: "startBox_geom", + name: { [LocalizedString.EN_US]: "Start Box" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + + greenGarage: { + type: "object", + geometryId: "greenGarage_geom", + name: { [LocalizedString.EN_US]: "Green Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + n1: { + type: "object", + geometryId: "n_geom", + name: { [LocalizedString.EN_US]: "Green Garage node" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + greenGarageL: { + type: "object", + geometryId: "greenGarageL_geom", + name: { [LocalizedString.EN_US]: "Green Garage Left Boundary" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(12), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53.5), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(44,104,27), + }, + }, + }, + greenGarageR: { + type: "object", + geometryId: "greenGarageR_geom", + name: { [LocalizedString.EN_US]: "Green Garage Right Boundary" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-11.5), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53.5), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(44,104,27), + }, + }, + }, + n2: { + type: "object", + geometryId: "n_geom", + name: { [LocalizedString.EN_US]: "Green Garage Right Boundary node" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-11.5), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53.5), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + greenGarageT: { + type: "object", + geometryId: "greenGarageT_geom", + name: { [LocalizedString.EN_US]: "Green Garage Top Boundary" }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(65), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(44,104,27), + }, + }, + }, + + blueGarage: { + type: "object", + geometryId: "blueGarage_geom", + name: { [LocalizedString.EN_US]: "Blue Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-12.5), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(94.5), + }, + orientation: Rotation.AxisAngle.fromRaw({ + axis: { x: 0, y: 1, z: 0 }, + angle: 115.5, + }), + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + + + }, + yellowGarage: { + type: "object", + geometryId: "yellowGarage_geom", + name: { [LocalizedString.EN_US]: "Yellow Garage" }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.8), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(78), + }, + }, + material: { + type: "pbr", + emissive: { + type: "color3", + color: Color.rgb(255, 255, 255), + }, + }, + }, + can12: { //Created an invisible can to attach script + ...createCanNode( + 12, + { + x: Distance.centimeters(11), + y: Distance.centimeters(0), + z: Distance.centimeters(91), + }, + false, + false + ), + scriptIds: ['garageIntersects'], + }, + + }, +}; \ No newline at end of file diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 8a71e209..a8fbd605 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -18,9 +18,10 @@ import jbc2 from "../../challenges/jbc2"; import jbc2b from "../../challenges/jbc2b"; import jbc2c from "../../challenges/jbc2c"; import jbc2d from "../../challenges/jbc2d"; -import jbc5 from "../../challenges/jbc5"; +import jbc3 from "../../challenges/jbc3"; import jbc4 from "../../challenges/jbc4"; import jbc4b from "../../challenges/jbc4b"; +import jbc5 from "../../challenges/jbc5"; import jbc6 from "../../challenges/jbc6"; import jbc7 from "../../challenges/jbc7"; import jbc7b from "../../challenges/jbc7b"; @@ -167,6 +168,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc2d, brief: ChallengeBrief.fromChallenge(jbc2d), }), + 'jbc3': Async.loaded({ + value: jbc3, + brief: ChallengeBrief.fromChallenge(jbc3), + }), 'jbc5': Async.loaded({ value: jbc5, brief: ChallengeBrief.fromChallenge(jbc5), From f673e21a0157a7a7d3a01f03b722022d7a1ac507 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 2 Mar 2023 09:29:04 -0600 Subject: [PATCH 29/37] Working on JBC22 --- src/challenges/jbc22.ts | 28 ++++++++- src/scenes/jbc22.ts | 136 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 150 insertions(+), 14 deletions(-) diff --git a/src/challenges/jbc22.ts b/src/challenges/jbc22.ts index 32b2f500..2b3e8ec8 100644 --- a/src/challenges/jbc22.ts +++ b/src/challenges/jbc22.ts @@ -26,14 +26,23 @@ export default { name: { [LocalizedString.EN_US]: 'Robot Left Start' }, description: { [LocalizedString.EN_US]: 'Robot left starting box' }, }, + + canStacked: { + name: { [LocalizedString.EN_US]: 'One Can Stacked' }, + description: { [LocalizedString.EN_US]: 'One can is stacked on another' }, + }, + robotTouchCan: { + name: { [LocalizedString.EN_US]: 'Robot Touching Can' }, + description: { [LocalizedString.EN_US]: 'Robot is touching a can' }, + }, }, success: { exprs: { - //Upright Events + //Startbox Events leaveStartBox: { type: Expr.Type.Event, eventId: 'leaveStartBox', @@ -42,10 +51,25 @@ export default { type: Expr.Type.Once, argId: 'leaveStartBox', }, + + //Can Events + canStacked: { + type: Expr.Type.Event, + eventId: 'canStacked', + }, + robotTouchCan: { + type: Expr.Type.Event, + eventId: 'robotTouchCan', + }, + robotTouchCanNot: { + type: Expr.Type.Not, + argId: 'robotTouchCan', + }, + completion: { type: Expr.Type.And, - argIds: ['leaveStartBoxOnce'], + argIds: ['leaveStartBoxOnce', 'canStacked', 'robotTouchCanNot'], }, }, rootId: 'completion', diff --git a/src/scenes/jbc22.ts b/src/scenes/jbc22.ts index 4a45c08e..8b7eb2c0 100644 --- a/src/scenes/jbc22.ts +++ b/src/scenes/jbc22.ts @@ -17,6 +17,52 @@ scene.addOnIntersectionListener('robot', (type, otherNodeId) => { }, 'startBox'); `; + +const canStacked = ` + +scene.addOnIntersectionListener('can5Bottom', (type, otherNodeId) => { + if(otherNodeId == 'can7Top'){ + console.log("Can5 stacked ontop of Can7!"); + scene.setChallengeEventValue('canStacked', true); + } + else if (otherNodeId == 'mainSurface'){ + scene.setChallengeEventValue('canStacked', false); + } + +}, ['can7Top', 'mainSurface']); + +scene.addOnIntersectionListener('can7Bottom', (type, otherNodeId) => { + + if(otherNodeId == 'can5Top'){ + console.log("Can7 stacked ontop of Can5!"); + scene.setChallengeEventValue('canStacked', true); + } + else if (otherNodeId == 'mainSurface'){ + scene.setChallengeEventValue('canStacked', false); + } + +}, ['can5Top', 'mainSurface']); + + +`; + +const robotTouchesCan = ` + +scene.onBind = nodeId => { + + scene.addOnCollisionListener(nodeId, (otherNodeId, point)=> { + if(nodeId == 'can5' || nodeId == 'can7'){ + scene.setChallengeEventValue('robotTouchCan', true); + } + + }, ['robot']); + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + scene.setChallengeEventValue('robotTouchCan', false); + }, ['mainSurface']); +}; +`; + export const JBC_22: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 22' }, @@ -25,6 +71,8 @@ export const JBC_22: Scene = { }, scripts: { leftStartBox: Script.ecmaScript('Robot Left Start', leftStartBox), + canStacked: Script.ecmaScript('Cans Stacked', canStacked), + robotTouchesCan: Script.ecmaScript('Robot Touches Can', robotTouchesCan), }, geometry: { ...baseScene.geometry, @@ -47,7 +95,7 @@ export const JBC_22: Scene = { }, canEnd_geom: { type: 'cylinder', - + radius: Distance.centimeters(3), height: Distance.centimeters(0.1), }, @@ -79,7 +127,7 @@ export const JBC_22: Scene = { type: 'object', geometryId: 'startBox_geom', name: { [LocalizedString.EN_US]: 'Start Box' }, - + visible: true, origin: { position: { @@ -96,20 +144,86 @@ export const JBC_22: Scene = { }, }, }, - - can5: createCanNode(5), - can7: createCanNode(7), - canEnd: { - parentId: 'ground', + + can5: { ...createCanNode(5), scriptIds: ['canStacked', 'robotTouchesCan'] }, + can7: { ...createCanNode(7), scriptIds: ['canStacked', 'robotTouchesCan'] }, + can5Bottom: { + parentId: 'can5', type: 'object', geometryId: 'canEnd_geom', - name: { [LocalizedString.EN_US]: 'Bottom or Top of a can' }, - + name: { [LocalizedString.EN_US]: 'Bottom of can5' }, + visible: true, origin: { position: { x: Distance.centimeters(0), - y: Distance.centimeters(0), + y: Distance.centimeters(-5.8), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can7Top: { + parentId: 'can7', + type: 'object', + geometryId: 'canEnd_geom', + name: { [LocalizedString.EN_US]: 'Top of can7' }, + + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(5.75), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can7Bottom: { + parentId: 'can7', + type: 'object', + geometryId: 'canEnd_geom', + name: { [LocalizedString.EN_US]: 'Bottom of can7' }, + + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-5.8), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can5Top: { + parentId: 'can5', + type: 'object', + geometryId: 'canEnd_geom', + name: { [LocalizedString.EN_US]: 'Top of can5' }, + + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(5.75), z: Distance.centimeters(0), }, }, @@ -120,8 +234,6 @@ export const JBC_22: Scene = { color: Color.rgb(255, 255, 255), }, }, - }, - }, }; From 386b3eb241ed25486aedbee728d4742386da5d92 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Thu, 2 Mar 2023 14:12:47 -0600 Subject: [PATCH 30/37] Added onClick listeners --- src/ScriptManager/ScriptSceneBinding.ts | 2 +- src/ScriptManager/index.ts | 42 +++++++++++++++++++++++-- src/Sim.tsx | 5 +++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/ScriptManager/ScriptSceneBinding.ts b/src/ScriptManager/ScriptSceneBinding.ts index 2a7b766b..ee073f03 100644 --- a/src/ScriptManager/ScriptSceneBinding.ts +++ b/src/ScriptManager/ScriptSceneBinding.ts @@ -35,7 +35,7 @@ export interface ScriptSceneBinding { addOnRenderListener(cb: () => void): string; addOnCollisionListener(nodeId: string, cb: (otherNodeId: string, point: Vector3) => void, filterIds: Ids): string; addOnIntersectionListener(nodeId: string, cb: (type: 'start' | 'end', otherNodeId: string) => void, filterIds: Ids): string; - + addOnClickListener(filterIds: Ids, cb: (nodeId: string) => void): string; removeListener(handle: string): void; onBind?: (nodeId: string) => void; diff --git a/src/ScriptManager/index.ts b/src/ScriptManager/index.ts index 022c4e12..e1c31ebe 100644 --- a/src/ScriptManager/index.ts +++ b/src/ScriptManager/index.ts @@ -145,6 +145,7 @@ namespace ScriptManager { Collision, IntersectionStart, IntersectionEnd, + Click } export interface Render { @@ -177,13 +178,21 @@ namespace ScriptManager { } export const intersectionEnd = construct(Type.IntersectionEnd); + + export interface Click { + type: Type.Click; + nodeId: string; + } + + export const click = construct(Type.Click); } export type Event = ( Event.Render | Event.Collision | Event.IntersectionStart | - Event.IntersectionEnd + Event.IntersectionEnd | + Event.Click ); export namespace Listener { @@ -191,6 +200,7 @@ namespace ScriptManager { Render, Collision, Intersection, + Click } export interface Render { @@ -217,12 +227,22 @@ namespace ScriptManager { } export const intersection = construct(Type.Intersection); + + + export interface Click { + type: Type.Click; + filterIds: Set; + cb: (nodeId: string) => void; + } + + export const click = construct(Type.Click); } export type Listener = ( Listener.Render | Listener.Collision | - Listener.Intersection + Listener.Intersection | + Listener.Click ); export type CachedListener = Omit; @@ -283,6 +303,10 @@ namespace ScriptManager { this.triggerIntersection_(event); break; } + case Event.Type.Click: { + this.triggerClick_(event); + break; + } } } @@ -311,6 +335,14 @@ namespace ScriptManager { } } + private triggerClick_(event: Event.Click) { + for (const listener of Dict.values(this.listeners_)) { + if (listener.type !== Listener.Type.Click) continue; + if (listener.filterIds && !listener.filterIds.has(event.nodeId)) continue; + listener.cb(event.nodeId); + } + } + bind(nodeId: string) { if (this.boundNodeIds_.has(nodeId)) return; if (this.onBind) this.onBind(nodeId); @@ -456,6 +488,12 @@ namespace ScriptManager { return handle; } + addOnClickListener(filterIds: Ids, cb: (nodeId: string) => void): string { + const handle = uuid(); + this.listeners_[handle] = Listener.click({ filterIds: Ids.toSet(filterIds), cb }); + return handle; + } + removeListener(handle: string): void { if (!(handle in this.listeners_)) return; diff --git a/src/Sim.tsx b/src/Sim.tsx index a0d56704..07778230 100644 --- a/src/Sim.tsx +++ b/src/Sim.tsx @@ -201,6 +201,11 @@ export class Space { const mesh = eventData.pickInfo.pickedMesh; const id = (mesh.metadata as SceneMeshMetadata).id; + + this.sceneBinding_.scriptManager.trigger(ScriptManager.Event.click({ + nodeId: id, + })); + const prevId = this.scene_.selectedNodeId; if (id !== prevId && this.scene_.nodes[id]?.editable) { this.onSelectNodeId?.(id); From 3ae92f939f2e67931c76299dc1f97fc81bfd790b Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 3 Mar 2023 09:36:11 -0600 Subject: [PATCH 31/37] Added JBC10B --- src/challenges/jbc10b.ts | 89 +++++++++++++++++++++++++++++++++ src/scenes/jbc10b.ts | 61 ++++++++++++++++++++++ src/scenes/jbc3.ts | 3 ++ src/state/reducer/challenges.ts | 5 ++ 4 files changed, 158 insertions(+) create mode 100644 src/challenges/jbc10b.ts diff --git a/src/challenges/jbc10b.ts b/src/challenges/jbc10b.ts new file mode 100644 index 00000000..d77ccbdc --- /dev/null +++ b/src/challenges/jbc10b.ts @@ -0,0 +1,89 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 10B' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 10B: Solo Joust Jr.`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + + can1Upright: { + name: { [LocalizedString.EN_US]: 'Can A Upright' }, + description: { + [LocalizedString.EN_US]: 'Can A upright in a circle', + }, + }, + leaveStartBox: { + name: { [LocalizedString.EN_US]: 'Robot Left Start' }, + description: { [LocalizedString.EN_US]: 'Robot left starting box' }, + }, + robotTouchingLine: { + name: { [LocalizedString.EN_US]: 'Robot Touching Line B' }, + description: { [LocalizedString.EN_US]: 'Robot is touching line B' }, + }, + + }, + success: { + exprs: { + + + //Upright Events + can1Upright: { + type: Expr.Type.Event, + eventId: 'can1Upright', + }, + can1NotUpright: { + type: Expr.Type.Not, + argId: 'can1Upright', + }, + + //Line B Event + robotTouchingLine: { + type: Expr.Type.Event, + eventId: 'robotTouchingLine', + }, + robotNotTouchingLine: { + type: Expr.Type.Not, + argId: 'robotTouchingLine', + }, + + //Can 1 Not Upright and Robot Not Touching Line B + NotUprightNotTouching: { + type: Expr.Type.And, + argIds: ['can1NotUpright', 'robotNotTouchingLine'], + }, + + //Start Box Events + leaveStartBox: { + type: Expr.Type.Event, + eventId: 'leaveStartBox', + }, + leaveStartBoxOnce: { + type: Expr.Type.Once, + argId: 'leaveStartBox', + }, + + + completion: { + type: Expr.Type.And, + argIds: ['leaveStartBoxOnce', 'NotUprightNotTouching'], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc10b', +} as Challenge; diff --git a/src/scenes/jbc10b.ts b/src/scenes/jbc10b.ts index 9d9e19a4..862eacf0 100644 --- a/src/scenes/jbc10b.ts +++ b/src/scenes/jbc10b.ts @@ -1,6 +1,7 @@ import Scene from "../state/State/Scene"; import { Distance } from "../util"; import LocalizedString from '../util/LocalizedString'; +import { Color } from '../state/State/Scene/Color'; import { createBaseSceneSurfaceB, createCanNode } from './jbcBase'; @@ -12,6 +13,66 @@ export const JBC_10B: Scene = { description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 10: Solo Joust Jr.' }, nodes: { ...baseScene.nodes, + mainSurface: { + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'basic', + color: { + type: 'color3', + color: Color.rgb(0, 0, 0), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-90), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-3), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + lineB: { + type: 'object', + geometryId: 'lineB_geom', + name: { [LocalizedString.EN_US]: 'Line B' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, 'can1': createCanNode(1, { x: Distance.centimeters(-13), y: Distance.centimeters(0), z: Distance.centimeters(17) }), // green line 'can2': createCanNode(2, { x: Distance.centimeters(-17), y: Distance.centimeters(0), z: Distance.centimeters(41) }), // red line 'can3': createCanNode(3, { x: Distance.centimeters(11.5), y: Distance.centimeters(0), z: Distance.centimeters(51) }), // yellow line diff --git a/src/scenes/jbc3.ts b/src/scenes/jbc3.ts index f4cbbe6c..3a47e379 100644 --- a/src/scenes/jbc3.ts +++ b/src/scenes/jbc3.ts @@ -16,6 +16,9 @@ const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { let chosenGarage = []; scene.onBind = nodeId => { + scene.addOnClickListener('greenGarage', (nodeId) => { + console.log('User clicked: '); + }); scene.addOnIntersectionListener('robot', (type, otherNodeId) => { console.log('Robot touched: ', otherNodeId); const visible = type === 'start'; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index a8fbd605..948e8500 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -28,6 +28,7 @@ import jbc7b from "../../challenges/jbc7b"; import jbc8 from "../../challenges/jbc8"; import jbc8b from "../../challenges/jbc8b"; import jbc10 from "../../challenges/jbc10"; +import jbc10b from "../../challenges/jbc10b"; import jbc12 from "../../challenges/jbc12"; import jbc13 from "../../challenges/jbc13"; import jbc15b from "../../challenges/jbc15b"; @@ -208,6 +209,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc10, brief: ChallengeBrief.fromChallenge(jbc10), }), + 'jbc10b': Async.loaded({ + value: jbc10b, + brief: ChallengeBrief.fromChallenge(jbc10b), + }), 'jbc12': Async.loaded({ value: jbc12, brief: ChallengeBrief.fromChallenge(jbc12), From 3c342c573ee17dc176a8f33c1219c120a61e6960 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 3 Mar 2023 10:08:30 -0600 Subject: [PATCH 32/37] Finished JBC17B implementation with testing --- src/challenges/jbc17b.ts | 50 +++++++++ src/scenes/jbc17b.ts | 193 ++++++++++++++++++++++++++++++-- src/state/reducer/challenges.ts | 5 + 3 files changed, 241 insertions(+), 7 deletions(-) create mode 100644 src/challenges/jbc17b.ts diff --git a/src/challenges/jbc17b.ts b/src/challenges/jbc17b.ts new file mode 100644 index 00000000..f3856486 --- /dev/null +++ b/src/challenges/jbc17b.ts @@ -0,0 +1,50 @@ +import Author from '../db/Author'; +import Challenge from '../state/State/Challenge'; +import Expr from '../state/State/Challenge/Expr'; +import LocalizedString from '../util/LocalizedString'; + +export default { + name: { [LocalizedString.EN_US]: 'JBC Challenge 17B' }, + description: { + [LocalizedString.EN_US]: `Junior Botball Challenge 17B: Walk the Line II`, + }, + author: { + type: Author.Type.Organization, + id: 'kipr', + //COMME + }, + code: { + c: `#include `, + cpp: `#include `, + python: `from kipr import botball`, + }, + defaultLanguage: 'c', + events: { + lineFollow: { + name: { [LocalizedString.EN_US]: 'Robot Walks the Line' }, + description: { + [LocalizedString.EN_US]: + 'Robot uses reflectance sensor to follow the black line until the Blue line', + }, + }, + }, + success: { + exprs: { + //Line Following Event + lineFollow: { + type: Expr.Type.Event, + eventId: 'lineFollow', + }, + + + completion: { + type: Expr.Type.And, + argIds: [ + 'lineFollow', + ], + }, + }, + rootId: 'completion', + }, + sceneId: 'jbc17b', +} as Challenge; diff --git a/src/scenes/jbc17b.ts b/src/scenes/jbc17b.ts index 38d0874f..c110f261 100644 --- a/src/scenes/jbc17b.ts +++ b/src/scenes/jbc17b.ts @@ -1,17 +1,52 @@ -import Scene from "../state/State/Scene"; -import { ReferenceFrame } from '../unit-math'; -import { Distance } from "../util"; +import Scene from '../state/State/Scene'; +import { Distance } from '../util'; import LocalizedString from '../util/LocalizedString'; +import { ReferenceFrame, Rotation } from '../unit-math'; +import { createCanNode, createBaseSceneSurfaceB } from './jbcBase'; +import { Color } from '../state/State/Scene/Color'; +import Script from '../state/State/Scene/Script'; -import { createBaseSceneSurfaceB } from './jbcBase'; const baseScene = createBaseSceneSurfaceB(); +const lineFollow = ` + +scene.onBind = nodeId => { + let count = 0; + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + + //Reset counter if robot in start box + if(otherNodeId == 'startBox' && type === 'start'){ + count = 0; + } + //1st checkpoint + if(otherNodeId == 'n1' && type === 'start' && count == 0){ + count = 1; + console.log("Robot passed checkpoint 1"); + } + //2nd checkpoint + else if (otherNodeId == 'n2' && type === 'start' && count == 1){ + count = 2; + console.log("Robot passed checkpoint 2 after checkpoint 1"); + } + + //Finish line after all other checkpoints + else if(otherNodeId == 'lineB' && type === 'start' && count == 2){ + console.log("Robot completed the course!"); + scene.setChallengeEventValue('lineFollow', true); + } + + console.log("Count: " + count); + }, ['lineB', 'n1', 'n2', 'n3', 'startBox']); + +}; + +`; const ROBOT_ORIGIN: ReferenceFrame = { ...baseScene.nodes['robot'].origin, position: { ...baseScene.nodes['robot'].origin.position, - x: Distance.centimeters(16.5), + x: Distance.centimeters(-16.5), }, }; @@ -20,6 +55,33 @@ export const JBC_17B: Scene = { name: { [LocalizedString.EN_US]: 'JBC 17B' }, description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 17: Walk the Line II' }, // Start the robot on the black tape + scripts: { + lineFollow: Script.ecmaScript('Line Follow', lineFollow), + }, + geometry: { + ...baseScene.geometry, + startBox_geom: { + type: 'box', + size: { + x: Distance.meters(1.22), + y: Distance.centimeters(0.1), + z: Distance.centimeters(10), + }, + }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(1), + height: Distance.centimeters(0.1), + }, + lineB_geom: { + type: 'box', + size: { + x: Distance.centimeters(0.5), + y: Distance.centimeters(0.1), + z: Distance.meters(1.77), + }, + }, + }, nodes: { ...baseScene.nodes, 'robot': { @@ -27,5 +89,122 @@ export const JBC_17B: Scene = { startingOrigin: ROBOT_ORIGIN, origin: ROBOT_ORIGIN }, - } -}; \ No newline at end of file + lineB: { + type: 'object', + geometryId: 'lineB_geom', + name: { [LocalizedString.EN_US]: 'Line B' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.inches(19.75), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-70), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(0), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 1' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-18), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(28), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 2' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-16), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(61), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Checkpoint 3' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(105), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can12: { + //Created an invisible can to attach script + ...createCanNode( + 12, + { + x: Distance.centimeters(11), + y: Distance.centimeters(0), + z: Distance.centimeters(91), + }, + false, + false + ), + scriptIds: ['lineFollow'], + }, + }, +}; diff --git a/src/state/reducer/challenges.ts b/src/state/reducer/challenges.ts index 948e8500..958a8916 100644 --- a/src/state/reducer/challenges.ts +++ b/src/state/reducer/challenges.ts @@ -33,6 +33,7 @@ import jbc12 from "../../challenges/jbc12"; import jbc13 from "../../challenges/jbc13"; import jbc15b from "../../challenges/jbc15b"; import jbc17 from "../../challenges/jbc17"; +import jbc17b from "../../challenges/jbc17b"; import jbc19 from "../../challenges/jbc19"; import jbc20 from "../../challenges/jbc20"; import jbc21 from "../../challenges/jbc21"; @@ -229,6 +230,10 @@ const DEFAULT_CHALLENGES: Challenges = { value: jbc17, brief: ChallengeBrief.fromChallenge(jbc17), }), + 'jbc17b': Async.loaded({ + value: jbc17b, + brief: ChallengeBrief.fromChallenge(jbc17b), + }), 'jbc19': Async.loaded({ value: jbc19, brief: ChallengeBrief.fromChallenge(jbc19), From cda26120e4532077564fffaada36dd39909b2673 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 8 Mar 2023 09:35:31 -0600 Subject: [PATCH 33/37] Finsihed JBC3 implementation with testing --- src/scenes/jbc3.ts | 605 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 470 insertions(+), 135 deletions(-) diff --git a/src/scenes/jbc3.ts b/src/scenes/jbc3.ts index 3a47e379..59883c9b 100644 --- a/src/scenes/jbc3.ts +++ b/src/scenes/jbc3.ts @@ -1,12 +1,14 @@ -import Scene from "../state/State/Scene"; +import Scene from '../state/State/Scene'; import LocalizedString from '../util/LocalizedString'; import Script from '../state/State/Scene/Script'; -import { Distance , Angle} from "../util"; -import { createBaseSceneSurfaceA, createCanNode} from './jbcBase'; -import {Rotation } from "../unit-math"; +import { Distance, Angle } from '../util'; +import { createBaseSceneSurfaceA, createCanNode } from './jbcBase'; +import { Rotation, ReferenceFrame } from '../unit-math'; import { Color } from '../state/State/Scene/Color'; +import { Vector2 } from '../math'; const baseScene = createBaseSceneSurfaceA(); + const garageIntersects = ` const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { ...scene.nodes[nodeId], @@ -14,59 +16,164 @@ const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { }); let chosenGarage = []; +let declaredGarage = []; +let clicked = true; + +//state == 0 (reset), state == 1 (1 garage parked), state == 2 (finished) +let state = 0; + +let selected = 0; + scene.onBind = nodeId => { - scene.addOnClickListener('greenGarage', (nodeId) => { - console.log('User clicked: '); - }); - scene.addOnIntersectionListener('robot', (type, otherNodeId) => { - console.log('Robot touched: ', otherNodeId); - const visible = type === 'start'; - chosenGarage.pop(); - }, ['startBox']); scene.addOnIntersectionListener('robot', (type, otherNodeId) => { - // if(chosenGarage.length == 0){ - // chosenGarage[0] == otherNodeId; - - // } - if(chosenGarage.length < 1 && otherNodeId == 'n1') { + + //Value resets + if (state >= 2){ + state = 0; + } + if(selected >= 2){ + selected = 0; + } + + //Entering StartBox Events + if(otherNodeId == 'startBox' && type == 'start'){ + + //Reset Challenge Sequence + if(state == 0 && chosenGarage.length > 0){ + for (let i = 0; i < chosenGarage.length; i++){ + chosenGarage.pop(); + } + for (let i = 0; i < declaredGarage.length; i++){ + declaredGarage.pop(); + } + + clicked = true; + + } + + //Return to startbox after first garage park + else if(state == 1 && chosenGarage.length > 0){ + scene.setChallengeEventValue('returnStartBox', true); + setNodeVisible(chosenGarage[0], false); + clicked = true; + + + if(declaredGarage.includes('greenBox')){ + setNodeVisible('yellowBox', true); + setNodeVisible('blueBox', true); + + } + else if (declaredGarage.includes('yellowBox')){ + setNodeVisible('greenBox', true); + setNodeVisible('blueBox', true); + + } + else if (declaredGarage.includes('blueBox')){ + setNodeVisible('greenBox', true); + setNodeVisible('yellowBox', true); + + } + chosenGarage.pop(); + declaredGarage.pop(); + } + } + //Entering Garage Events + if(type == 'start'){ + + if(otherNodeId == 'n1' && declaredGarage.includes('greenBox')){ + setNodeVisible('greenGarage', true); + state++; + selected++; + } + else if(otherNodeId == 'n2' && declaredGarage.includes('yellowBox')) { + setNodeVisible('yellowGarage', true); + state++; + selected++; + } + else if(otherNodeId == 'n3' && declaredGarage.includes('blueBox')) { + setNodeVisible('blueGarage', true); + state++; + selected++; + } + } + + + if(selected == 1){ + scene.setChallengeEventValue('singleGarageRun1', true); + } + else if (selected == 2){ + scene.setChallengeEventValue('singleGarageRun2', true); + } + + }, ['startBox', 'greenBox', 'yellowBox', 'blueBox','n1','n2','n3']); + + + //User declares garage + scene.addOnClickListener(['greenBox','yellowBox','blueBox'], id => { + + clicked = !clicked; + setNodeVisible('greenBox', clicked); + setNodeVisible('yellowBox', clicked); + setNodeVisible('blueBox', clicked); + if(id == 'greenBox'){ chosenGarage.push('greenGarage'); - console.log('Robot: ', type, otherNodeId); - const visible = type === 'start'; - setNodeVisible('greenGarage', true); + declaredGarage.push('greenBox'); + } + else if(id == 'yellowBox'){ + chosenGarage.push('yellowGarage'); + declaredGarage.push('yellowBox'); } - console.log("Chosen Garages: " + chosenGarage); - }, ['n1', ]); + else if(id == 'blueBox'){ + chosenGarage.push('blueGarage'); + declaredGarage.push('blueBox'); + } + }); + + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { - if(otherNodeId == 'n2'){ - console.log('Robot touched: greenGarage right boundary'); - const visible = type === 'start'; - //setNodeVisible('n2', visible); + if(declaredGarage.includes('greenBox') && + (otherNodeId == 'g1' || otherNodeId == 'g2' || otherNodeId == 'g3')){ + state = 0; + selected = 0; scene.setChallengeEventValue('touchGarageLines', true); } - }, ['n2']); + else if(declaredGarage.includes('blueBox') && + (otherNodeId == 'b1' || otherNodeId == 'b2' || otherNodeId == 'b3')){ + state = 0; + selected = 0; + scene.setChallengeEventValue('touchGarageLines', true); + else if(declaredGarage.includes('yellowBox') && + (otherNodeId == 'y1' || otherNodeId == 'y2' || otherNodeId == 'y3')){ + state = 0; + selected = 0; + scene.setChallengeEventValue('touchGarageLines', true); + } + }, ['g1', 'g2','g3', 'b1','b2','b3', 'y1', 'y2', 'y3']); - -} -`; +} +`; export const JBC_3: Scene = { ...baseScene, name: { [LocalizedString.EN_US]: 'JBC 3' }, - description: { [LocalizedString.EN_US]: 'Junior Botball Challenge 3: Precision Parking' }, + description: { + [LocalizedString.EN_US]: 'Junior Botball Challenge 3: Precision Parking', + }, scripts: { - - garageIntersects: Script.ecmaScript("Garage Intersects", garageIntersects), + garageIntersects: Script.ecmaScript('Garage Intersects', garageIntersects), + //clicked: Script.ecmaScript('Garage Intersects', clicked), }, geometry: { ...baseScene.geometry, mainSurface_geom: { - type: "box", + type: 'box', size: { x: Distance.meters(3.54), y: Distance.centimeters(0.1), @@ -74,7 +181,7 @@ export const JBC_3: Scene = { }, }, startBox_geom: { - type: "box", + type: 'box', size: { x: Distance.meters(3.54), y: Distance.centimeters(0.1), @@ -86,42 +193,24 @@ export const JBC_3: Scene = { radius: Distance.centimeters(0.01), height: Distance.centimeters(0.1), }, - greenGarage_geom: { - type: "box", + designatorBox_geom: { + type: 'box', size: { - x: Distance.centimeters(18), - y: Distance.centimeters(0.1), - z: Distance.centimeters(18), + x: Distance.centimeters(10), + y: Distance.centimeters(1), + z: Distance.centimeters(10), }, }, - greenGarageL_geom: { - type: "box", + greenGarage_geom: { + type: 'box', size: { - x: Distance.centimeters(0.01), + x: Distance.centimeters(18), y: Distance.centimeters(0.1), - z: Distance.centimeters(22), - }, - }, - greenGarageR_geom: { - type: "box", - size: { - x: Distance.centimeters(0.1), - y: Distance.centimeters(0.01), z: Distance.centimeters(18), }, }, - greenGarageT_geom: { - type: "box", - size: { - x: Distance.centimeters(24), - y: Distance.centimeters(0.1), - z: Distance.centimeters(1), - }, - }, - - blueGarage_geom: { - type: "box", + type: 'box', size: { x: Distance.centimeters(18), y: Distance.centimeters(0.1), @@ -129,7 +218,7 @@ export const JBC_3: Scene = { }, }, yellowGarage_geom: { - type: "box", + type: 'box', size: { x: Distance.centimeters(16), y: Distance.centimeters(0.1), @@ -140,9 +229,9 @@ export const JBC_3: Scene = { nodes: { ...baseScene.nodes, mainSurface: { - type: "object", - geometryId: "mainSurface_geom", - name: { [LocalizedString.EN_US]: "Mat Surface" }, + type: 'object', + geometryId: 'mainSurface_geom', + name: { [LocalizedString.EN_US]: 'Mat Surface' }, visible: false, origin: { position: { @@ -152,17 +241,17 @@ export const JBC_3: Scene = { }, }, material: { - type: "basic", + type: 'basic', color: { - type: "color3", + type: 'color3', color: Color.rgb(0, 0, 0), }, }, }, startBox: { - type: "object", - geometryId: "startBox_geom", - name: { [LocalizedString.EN_US]: "Start Box" }, + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, visible: false, origin: { position: { @@ -172,18 +261,125 @@ export const JBC_3: Scene = { }, }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, + greenBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Green Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6), + z: Distance.centimeters(53), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-90), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, + + yellowBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(18.5), + y: Distance.centimeters(-6), + z: Distance.centimeters(78.9), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-90), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, + + blueBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-12), + y: Distance.centimeters(-6), + z: Distance.centimeters(94), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-135), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, greenGarage: { - type: "object", - geometryId: "greenGarage_geom", - name: { [LocalizedString.EN_US]: "Green Garage" }, + type: 'object', + geometryId: 'greenGarage_geom', + name: { [LocalizedString.EN_US]: 'Green Garage' }, visible: false, origin: { position: { @@ -193,57 +389,78 @@ export const JBC_3: Scene = { }, }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, n1: { - type: "object", - geometryId: "n_geom", - name: { [LocalizedString.EN_US]: "Green Garage node" }, - visible: false, + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage node' }, + visible: true, origin: { position: { x: Distance.centimeters(0), y: Distance.centimeters(-6.9), - z: Distance.centimeters(53), + z: Distance.centimeters(58), }, }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, - greenGarageL: { - type: "object", - geometryId: "greenGarageL_geom", - name: { [LocalizedString.EN_US]: "Green Garage Left Boundary" }, + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage node' }, visible: true, origin: { position: { - x: Distance.centimeters(12), - y: Distance.centimeters(-6.9), - z: Distance.centimeters(53.5), + x: Distance.centimeters(18.5), + y: Distance.centimeters(-6), + z: Distance.centimeters(73.9), }, }, material: { - type: "basic", - color: { - type: "color3", - color: Color.rgb(44,104,27), + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage node' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-14), + y: Distance.centimeters(-6), + z: Distance.centimeters(96), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), }, }, }, - greenGarageR: { - type: "object", - geometryId: "greenGarageR_geom", - name: { [LocalizedString.EN_US]: "Green Garage Right Boundary" }, + + g1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage Right Boundary node' }, visible: true, origin: { position: { @@ -253,37 +470,37 @@ export const JBC_3: Scene = { }, }, material: { - type: "basic", - color: { - type: "color3", - color: Color.rgb(44,104,27), + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), }, }, }, - n2: { - type: "object", - geometryId: "n_geom", - name: { [LocalizedString.EN_US]: "Green Garage Right Boundary node" }, - visible: false, + g2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage Left Boundary node' }, + visible: true, origin: { position: { - x: Distance.centimeters(-11.5), + x: Distance.centimeters(12), y: Distance.centimeters(-6.9), z: Distance.centimeters(53.5), }, }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, - greenGarageT: { - type: "object", - geometryId: "greenGarageT_geom", - name: { [LocalizedString.EN_US]: "Green Garage Top Boundary" }, + g3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage Top Boundary node' }, visible: true, origin: { position: { @@ -293,18 +510,18 @@ export const JBC_3: Scene = { }, }, material: { - type: "basic", - color: { - type: "color3", - color: Color.rgb(44,104,27), + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), }, }, }, blueGarage: { - type: "object", - geometryId: "blueGarage_geom", - name: { [LocalizedString.EN_US]: "Blue Garage" }, + type: 'object', + geometryId: 'blueGarage_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage' }, visible: false, origin: { position: { @@ -318,19 +535,77 @@ export const JBC_3: Scene = { }), }, material: { - type: "pbr", + type: 'pbr', emissive: { - type: "color3", + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + b1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage Right Boundary node' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-19.2), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(86.4), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + b2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage Left Boundary node' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-5), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(102.6), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + b3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage Top Boundary node' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-19.2), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(102), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', color: Color.rgb(255, 255, 255), }, }, - - }, yellowGarage: { - type: "object", - geometryId: "yellowGarage_geom", - name: { [LocalizedString.EN_US]: "Yellow Garage" }, + type: 'object', + geometryId: 'yellowGarage_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage' }, visible: false, origin: { position: { @@ -340,14 +615,75 @@ export const JBC_3: Scene = { }, }, material: { - type: "pbr", + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + y1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage Right Boundary node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(29.3), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(77.9), + }, + }, + material: { + type: 'pbr', emissive: { - type: "color3", + type: 'color3', color: Color.rgb(255, 255, 255), }, }, }, - can12: { //Created an invisible can to attach script + y2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage Left Boundary node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(9.3), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(77.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + y3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage Top Boundary node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.3), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(68.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + can12: { + //Created an invisible can to attach script ...createCanNode( 12, { @@ -360,6 +696,5 @@ export const JBC_3: Scene = { ), scriptIds: ['garageIntersects'], }, - }, -}; \ No newline at end of file +}; From 98f276536fc1aa8da063f3a19120bd3698a59ee6 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 8 Mar 2023 09:39:08 -0600 Subject: [PATCH 34/37] Turned off geometry visibility and adding "Click Here.png" for garage declaration --- src/scenes/jbc10.ts | 4 ++-- src/scenes/jbc4.ts | 4 ++-- static/Click Here.png | Bin 0 -> 9390 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 static/Click Here.png diff --git a/src/scenes/jbc10.ts b/src/scenes/jbc10.ts index 0c17a517..0f6cf6b9 100644 --- a/src/scenes/jbc10.ts +++ b/src/scenes/jbc10.ts @@ -124,7 +124,7 @@ export const JBC_10: Scene = { type: 'object', geometryId: 'startBox_geom', name: { [LocalizedString.EN_US]: 'Start Box' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-90), @@ -144,7 +144,7 @@ export const JBC_10: Scene = { type: 'object', geometryId: 'lineB_geom', name: { [LocalizedString.EN_US]: 'Line B' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), diff --git a/src/scenes/jbc4.ts b/src/scenes/jbc4.ts index 40abb590..634e5add 100644 --- a/src/scenes/jbc4.ts +++ b/src/scenes/jbc4.ts @@ -289,7 +289,7 @@ export const JBC_4: Scene = { type: "object", geometryId: "middle_geom", name: { [LocalizedString.EN_US]: "Between cans 4 and 9" }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), @@ -310,7 +310,7 @@ export const JBC_4: Scene = { type: "object", geometryId: "topCan9_geom", name: { [LocalizedString.EN_US]: "Top side of can 9" }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), diff --git a/static/Click Here.png b/static/Click Here.png new file mode 100644 index 0000000000000000000000000000000000000000..1affa21e3fe674c5650a546a7eb18734112d606e GIT binary patch literal 9390 zcmdUTXHZjJ)Gk(RAZq9WB8Z_&ZvrYLp~ImUDS~wAC3IAz9l+28>5xe8B?JgfASg%? z>4c(@BHhq2l#h4r%>DoUxik07>^Za7S^L@LtiAU0>}VY=1kE*;YgANJG^#4fx>Qsb zKq{(p16MAbS(YzRr=7jddFdjaotx|t2tBJ@byqR*qM{Pw`mdbx%UAS0b7<4i(1)F# zp02O2x3#r(c6M%UZDFz4Gj}>Vy88P1^z`)5&`?`jTQxN`EiEkv2Zyk*u3}-!@|PClarI?=4KWa7G7T7;o;%=`FU<`ZZR=2ZEfwjxw-cC z_W1bt*RNk&Sy?@K@}#b=Zfa`k-o1P7?(UnLo58`s7z_pmgDEO11_T5Q4h}wg^au`z zzk2nGnwlB_01XWd8X6i}T3QJSiR;&|3keBHNlBTRndRi<*x1-aM@LsyR-#a-wY4=? zR@Q(2{`L0uUc7km=g*&UadC}}jbFZev9`8`Kp-9-9upH2+uPf6%&u&JrZ&CTuR&6~o)!j_hn92^|Exw%zURXRF4LqkJLOH03g{gRcH-Pze0A0NMb z`EplRS72b^{{DVnU*Gxj=g*xx$Hm1ZFE39flfAsWEG#TmR#tA^x`jj{5eUTh@81^} z7hk@7DJdz*$Hx~E5;8V6_V(@DCnu--_wV=j_lt^(GB7Z7cXux@FSD_+6%`dlzVY&=qPicYs{B;nFLQn7Fo$Ac z@P%xO4TAx6PcNp{4;$KpDeoIFpNo5q0FO&VNBizej2EYom-d7AZ`KDU1rD_APm3Sd z4g1T79w;cxIgVvCCuPhp78w2)OaEUzm7S?0=9U3njnQeNZEI0p7cAn1-5M$~IcN9i z`*EQQMlHWf+ZMB^2iMH4?cyrs{m|{OC}r}D<$m_D@aFNqeKtuk^p%5mm;;(k;gh{L zZjT-8lyCjL3MXe&Omnmy<~qy$_ZfXq;g&Gu$R;X=jxs8pY25I|x18uAi-&n>=|B>$ zcV3)j&bR#s9jqCi<$4PLru(}fG;oIbRm3$IIc#cTE~NcF8$UQF;vM|x(N1L7cS{q( zvrLOx%SW=iTUL1?frSO`m95O85W?mN{OIqw7@sm|Nb1KmBz43IyU5PIVKrT$)QFUb zR>92ZU_=jaq~OxEsc6*`MFRXKMYKN6qL#ih5jeiXkG`J!28W;=l_7&YUm29mAfY;} zqDdh!+3OIFyjp%&l-9`o!!(ST^bqzeqnb1Ss!#GzUqgdCBT zQWBu-01+2WwtK)c#6XzRZcq$4$_?iR5&HWs*3Ce%syMuQFG=x3Aeua!bCA}Vk_cr_ z2po@qW-EK%E(gj+L-v+JTKBKF9rXMnD(ZB3wDU9(0w4X9MnjU!k zhBD86n-CL&M&9||&-^aup;lz)BHURz=pM+(4D zLwom_l*w^PUpnLbYuVV+pcX0+du8%YS9vXVc|z2a0Nj=L#m}tcOIuu#r|-9Z#Kc-J z6;qnc^0bbA^2qxb>G^G}{9^L1K*Gj?*NQs3dIJB{L+j9mUIu(GVyv&i`dfDGqJ8D1=^Z3iuWHm!;8%3goXwq)K zpHREY3$_|5y0K&Pvfhj>eF8WgHsH+911+{T(mMT~KvqeQYJGgn7Uxe_Xhu3RO%Rpb zAjaY^yQ>;R@d0&OsBHahM6|X1cgBu5-9xX-CWMO8BbQ26DAwKvR_zVh>@=63xOsWP z(~@cQ`fTZ2C~d&l%sqC3^Umw-) zh%qtFyxYmYXkNi`$8mSKxCL?(Wql;58VH%&y(RN5&$4s{BMnxJWSMmjY#OPReh-3F z+K4&qkoYYm!4)#m2a)RGSQp$KkY_CS7_6>EypW25lX3G@+k;(3=q;$JMMtYwiTlPT z*W_hBoOuA5`D2YSADEIR)%Vb@%rWEsuTOps5Y6@P{lL-sAULPUSeb3e0W(wT$gmc{ zE6(*uZ(=6I`aj1LM1i{gAl?{Zs`@%DVVR?abK$l~_azS%dmuR|e-kRA`j zEateCG*7|~V?$nYzB7lwMn}0~DgvURd$AY+0D&DAqSs3|xyt}kTCaP7B1J9?=1A#l zV{5I`NhTgvf8f65?ws+Dni~&K48*T31NwmiTS8P)y8Y9w;VHV^icqknYv$fvm~G|1 z=`R}mfD2@o8e4Mo-iayb4nbx6xS14flyH~e`^@rX%B6P0q7gybXzMLkx>(X?E8^r| zVEu<8aj@4^GcswdbuxfXah_w2WwACIz2&>CRO+825$Q!%DvL;JrYU1va7|0seiquE z<9@nR1vSOfR>8>o3#gn>oXZ2gIP|npB#|OkOeFmHDE=*11?@a2_XD2MTz~TXe>! z2lE7lBmEm3ygQ&Jm8x2`-}{b$pyaloJ?%bz;01(mu7C;R@y#~$$Cg&`?3A~?Xy1sZ z7yAYL3n@wegzeG23k!RWDW}1?FNcntKCc#Jr6=;}D1cL%`}8Q^rrfAL?-q&Y~f8oZO8@xe!nhPHld#70dOjl zOLb%~RnaU<_~iM?U&gEdXFT1F&YZ3$n~4RQ4G(bP8evHWxbuPb{1;@rY!!9bF%5`o z`Io5Vy^J%3K-2Nk>H_9olc6QSz}>oDXtxmkf>6$3h{GQvlbZevvDXuy>P6$djP@=} z-utvbi+;@hdk9TfMi+^1M;qqfMjxc|@&o3O-{wqB^bIp6dRm4py-7&ktaDxWC#K%? zPV!UUG#7pCdgR$zQ0ExZQinKFt*lRekM=BPa;bDckvj3ZhUg|}ua{w^*}Ou>U_c=i!SR(BMS9M=wP7QvT6SEO7pI{nSFj@zl)~Xnd)EVT;gYgm0RCkHJ&|XIGy9w zqXc^0(w_j@1ZbU6_MVqUpuL6KqsfIfSy%REjMVm*h^6a4 z)sf>{!y92*`-gV8!*9rMCdjd3shKW(>|G#^!=5+uo*D3;bZ@+nz+74F(S--3WCVzSow$W37AoeiBh{^ z|E}7a7PyU%oaIr&nay;DXYUIUKry$4fxCsi)E8Hq8=7T|}f<#zDxrHVGX4QlLZoq`~)5?j$(lvAMcPg=)AN+uWSzHM*uif#9_(`?J=8&b=8 z6h35>f;=WvFL;>X|L{?#rOSh}4D!dek>|8CR@8BACswZyO~4Z!XM6mo>@?x+m1S$$ zTA_0(w-rL_fTs}RZ0ihLx3KClMzrMD>KxVyQ?#StU|ehZ43eZ^_F^;fX^StTdis&w zm4^i79+R?r;NneR7R*6wsBX7}0ljowg-(szL`lZsIOU26EWyr zG%vXij@^mc)hj$by0Eo>SV+TfxlY}F2dsGx3D$lqapu3tw3Z^iT$VE-cRi(!eN3q& z3Vl?SIKToc$Dee|-Qc%$f!s;d6#{u5&c0LVd|OC3PE1$yZx&xja$TM;JbcR+jrORN zKveGu_fBlaRt91LjfRi>%!GHV(eI#_g)exir@P<#_~Uy)G9|eLApz8_WA~sZs}C3G zHc>_Z|9k6bVZ_)Ew8Nmans$0#G;LfbeSBAqu2w8PtU85x%ME3{{=4@NM_h&9C?IZs z#-aK%_=@$2?J%`Gmj-gVMxq}TCAzu*AIAXXTv=V#^@j=D{NF<}g1 zJJAi&ue3VesGvwBmAmFYXihCev*@~3Vr!x+KP{D$Lmn1G!5HTEW-G1|IqPkBXOP5r zsz?px{_NK>BWQqc>s=gJO+`0Wz+KMgAP`D zEx_0-$%mcc3-875)~EMVY(k#->bOacdztmSjosz&a&_y?%`U&@(P~m|ATw6ljGw4L zWt0=V3s;W>H5g#X_B6+8PKG-s4?G*|OsvEN3@fnN+fFfTqDKEal`DPo)Es#{Sj>3U zFYW~Q>tCCm@a?}Ww_ra7=>Bhc-T)MO&CIL_)M>XUHyJS!fF+M=m@7qn@LSyW1anqE zn)^izjEZv1UmaRGy;~tyXz^s6AGD^B$8ff;|6-JBwOU>mb>|KTw+>0wWqk3HecGA` zt*^|H=bd)W4&Vf$3pm5&j=$8(oNtSO(z0&~n1w?vB0fPSS&Ul58lN;CLC139i0{s9 zT~MLv>70PHR3UkAx79z4j_@s>odExRc%!5^m5q=fe)dgxEiKi8E@h-#N66D5eSW)D=dLMw=}=!y9V%dwy%#OOUz@L@m67G7;(Cw4XpcNGY0?XciJ z4DJyh@FfCjLH7W>S-$8u>@(aT6L@9)QeogHj|3oA!YAWqWPkZD_k$-8;pp3hCNY&3 znf-Ov!G|V``RcJG>Ew>di5a2mm;f(HZZP#T9U+{OXMYoj2o@811fHxcH~aI%{q<0; zhYEE_8z2)y+)0?i4X@Dham}@xR&_y+!E$?ExIptD*ccOGZ);|MUEgrnpATn*YMPn# zyf&k88Z45t{>ruTTTA~c{#8z(9kbY<$1V&3E{CMh;;Y!o@fPZ7-NF zrm@wiy>bX;f)ZDh`*jeMINO;a);rk@#BoyZ(&AWs{*<=)E_Syx#7#;=91J5UKNkG@ z52u|iBe&XM-Z->=vaphO*V$Xp)NRfu38^-xTCH(hTRWk;TRgKHw3#WnJ6T`pmEXWt ze>|}sI4iZuDz#NJ5s*z&w~~2J)Ri6%Y z<&W*#v-x)jyBpF_f%qsA#@>Ju{Q-IWNm_HRZNtXJIA=8OXJ2S-HX&tswT%!E+^|B> zezopew;B~P&iJJSJZk1v_Q;*p7>y{S24#+#Y$%dJilI_g++eFSF|)NMNe)x)`-Q@P zh-;yIFX17mWPMkP4jhSC(wn+9#O88{8_GH|D`&_F;kpgqb{8RNJ}GS^e;t(<8o zPo>Pb(p14_587;r#tUQYn2?k930h*-*g&c`OrA1hD^TF}RWiB*!^ORon~J;fRROFo zAa=7UmFJ{5_q}xa_UF|_WF7wlu~p8vVWZ9C*+T5P7Y}d-lTin)|3E*ub)n0-(0R-M z<)HYi>t7K4NB>}vQ}mEA@Dlg~dIlf&u_4l@GO)a)A( zJevLlt1b|K^DT9({W-;5SR}B1$hXsooe#tYF+Mp0hOH7i<>PU(={dD!+rO%?LeJ-% zy~BO}8fr(XuLw6LUT0|ZGs}DRD@(^3f;G3>Cu%@ELNst838jM+ZE$|dXP4mgKMnrrpz1%`_s`&$Z>)T7YJqNb&@ArUSCpfNd)y1*ojvcpAO4CG=F1iO zLe?wgrT&~-nhK;g@VLYLt{_YJ%n%DKEt3?oyzya3-*NYC4Nztuu&xpFtp0S8oe*u& zu!5IsoWsIzly{(eudYe?IVH3;cNftsdzf)s>uJYeno?u%Tm=CXZ^5k12f9$1qDPl?8F?$9}OvaEJJ&<6mSSAFk+h1 zaS&$dyg%{wZem;~Ar6a7w9Ifdii98m@t_!|;1HJU{ zpgBG^n19z5IB=%BsZkRlx9~Wj)DRPj-pZ^gs1kC89-Yl()Ug*I$&4$`udoO!SKub3#I@> zj+k9v=W`Q2l=9cNuy%u2Etu$ygeLhInao{*v^|%_rEIY6=1VtYH9HmaqxuUB(M*=E z&JelT*4SyncShJu?o}86`N!V9(z9a45+LRa(Lt=BUH|v>7U=W@aTf3RRrFie&Ur$P z#eB9!>VVPN7Vv$YkyD58y|sF4VU8x!Mh}t`kdiMQ1LZ>&v}~%Rp+9cs3+1loIQivK zqY5sQ-#~kh%YHyx8_bHL0sRdXHzS#rs%AjExrh-(%C!$FTogbTY5X8sb=RTe3qi>Qr4I}9`@ zFNa;md^{)!3V;kN#6CBGpn!RM9$wHiW_CvY_jY5LtO~wL8U=OAdHOe#Aq>#?GyIZQ z28_^E!)Jkf%Jvk%gQ=kn=8zzy1{p0GY}HiCJ$~`An#LEn2dWtv_fN-pk!|Q{=0u4l5k+hvMaM_(EL?+Vl~N-_4nPw@{e~2U z)C&Y*WFq7K^rLPDnAuZhJi|eln3UP6Jv+CY_!>mX-sEAr9NV+s zlU;YshMf~6BqfEitRQK?!XrfE4#oO|T+j8j5y7u?gg2*h?cqiP$t)@5rT)8K-N;{N zQYX-EClqPvHjr$ju>v!{e`?-=|6;ZDnIb`FGpoE9&qQd)fBtv0Km47xA?{>&Z>b}) z`$I8D;n%@4W^G}=*~EG@<;CeV<*_+db0a&ldjMHNo#h&On%v0&^Y`Q(^Cb*EKo@1T zpP$rf8Z+_=x>u#Ac&c=%H!pNsUeG0ZMOv=~LHm zyL{pK67#h`94(uVeZ0okrtDeAHyARO0}kz+D%&cW*Sb|@_!$Paqut1XeA!NsCAi)a zT3M92*8*0V|EfLByjytMw>yKM0fEendDu<}%Y%QH2ZdXjlI~i}+t0^Co7jX7(v@d+ z8DE&P4dG2obQ!Fr)N~=0zH-w~{9j-+Ai?TE`^_e!h0`VJbGMid0v@5RjGf;ve2-Wd z`H#s=d*krspIT%-WWb~CJ{^+wCAjz)4!x`sauP0}p^A`AdAy_NZ<;0AH3hX6A?GQ{19~iYQkPUO z7U%1*rrIo@x7&Omi;ml9pMlP83`jJ(&y zuDA?Qlb=752R}#V*z809XxaRf*U&~6Ly6W_a^Ac)-N^Qt++Wbk zzNrO8ogYxvR$sRI+J)5pgn-O9p=k_82d9djYyiaF}i zMN8*QrX$CvQb<4Gcg4Au(q`hTLv(^yKa48VufB#(8Di%{M3~H0-wxaeLe$yH!S)}S z6l}vRSqyP>q~RidjJDCjt7sAsbM&bU$fPCgD=1BoXTFLp2LF|HlrpYUx5j2SS3H-) z|9%S8l{pqQ>yhPl^1DibSX=-8=1Y= z=7v2gC%cyRj&2W}7QsSvF#+;syZvI!73F~|jlxNvn+f`RfD8$8ZiPy58Bk8%}e84s04VYJPrTP%McjETKT)mmOVAT=eP zw|Jf1ydpMRO|8SW?&zIHxj=QlhWK!Eoo$y`{G9Lnm#U!Wp4-#GiTl#FgC_iw8J6&$ z^b?AW&1OE^^&7fXfvc1o<_Ey#*NM88@_x}X_2-12tdvqu*PVNRUj%&IL-n3Z5G+5q zcrG~sLZB`wY)|;4oWOk^kwiz3*)*a;*r3prZrW7zkM@~7963ZT4aA6mceJA00h6=P z(f`3oMb+jzcK34NPR3w^*@b4_U9$4kdH0FtLhEap9Yq$EbM`T(-^C#RyUVKor``|u ZPwRE7J6ykWMg7;WDojhc;+fUk{{cC|LpuNf literal 0 HcmV?d00001 From 664e8bab55b4a2c048c30c2312d04f48cb8c2646 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 8 Mar 2023 11:51:45 -0600 Subject: [PATCH 35/37] Turned off node geometries and fixed syntax error --- src/scenes/jbc3.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/scenes/jbc3.ts b/src/scenes/jbc3.ts index 59883c9b..59657a10 100644 --- a/src/scenes/jbc3.ts +++ b/src/scenes/jbc3.ts @@ -146,6 +146,7 @@ scene.onBind = nodeId => { state = 0; selected = 0; scene.setChallengeEventValue('touchGarageLines', true); + } else if(declaredGarage.includes('yellowBox') && (otherNodeId == 'y1' || otherNodeId == 'y2' || otherNodeId == 'y3')){ state = 0; @@ -400,7 +401,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Green Garage node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), @@ -420,7 +421,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Yellow Garage node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(18.5), @@ -440,7 +441,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Blue Garage node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-14), @@ -461,7 +462,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Green Garage Right Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-11.5), @@ -481,7 +482,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Green Garage Left Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(12), @@ -501,7 +502,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Green Garage Top Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(0), @@ -546,7 +547,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Blue Garage Right Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-19.2), @@ -566,7 +567,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Blue Garage Left Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-5), @@ -586,7 +587,7 @@ export const JBC_3: Scene = { type: 'object', geometryId: 'n_geom', name: { [LocalizedString.EN_US]: 'Blue Garage Top Boundary node' }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-19.2), From 33a448c33ebd7271fb4d40408ceb6c6b3d5e4279 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Wed, 8 Mar 2023 12:47:25 -0600 Subject: [PATCH 36/37] Finished JBC6 implementation with testing --- src/scenes/jbc6.ts | 144 +++++++++++++++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 44 deletions(-) diff --git a/src/scenes/jbc6.ts b/src/scenes/jbc6.ts index 4324982e..1388e827 100644 --- a/src/scenes/jbc6.ts +++ b/src/scenes/jbc6.ts @@ -4,68 +4,59 @@ import { createBaseSceneSurfaceA, createCanNode } from "./jbcBase"; import { Color } from "../state/State/Scene/Color"; import { Distance , Angle} from "../util"; import Script from "../state/State/Scene/Script"; -import { Euler } from "../math"; -import { Rotation } from "../unit-math"; -import {SharedRegistersRobot} from '../SharedRegistersRobot'; const baseScene = createBaseSceneSurfaceA(); - const garageIntersects = ` const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { ...scene.nodes[nodeId], visible }); -//const sharedRegistersRobot_ = SharedRegistersRobot; -// When the can (can2) is intersecting the green garage, the garage glows - -scene.addOnIntersectionListener('can2', (type, otherNodeId) => { - console.log('Can 2 placed!', type, otherNodeId); - const visible = type === 'start'; - scene.setChallengeEventValue('can2Intersects', visible); - setNodeVisible('greenGarage', visible); -}, 'greenGarage'); - -// When the can (can9) is intersecting the blue garage, the garage glows - -scene.addOnIntersectionListener('can9', (type, otherNodeId) => { - console.log('Can 9 placed!', type, otherNodeId); - const visible = type === 'start'; - scene.setChallengeEventValue('can9Intersects', visible); - setNodeVisible('blueGarage', visible); -}, 'blueGarage'); - - -// When the can (can10) is intersecting the yellow garage, the garage glows - -scene.addOnIntersectionListener('can10', (type, otherNodeId) => { - console.log('Can 10 placed!', type, otherNodeId); - const visible = type === 'start'; - scene.setChallengeEventValue('can10Intersects', visible); - setNodeVisible('yellowGarage', visible); -}, 'yellowGarage'); + + +scene.onBind = nodeId => { + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { + + //green garage and can2 intersecting + if(nodeId == 'can2' && otherNodeId == 'n1'){ + console.log('Can 2 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can2Intersects', visible); + setNodeVisible('greenGarage', visible); + } + //yellow garage and can10 intersecting + else if(nodeId == 'can10' && otherNodeId == 'n2') + { + console.log('Can 10 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can10Intersects', visible); + setNodeVisible('yellowGarage', visible); + } + //blue garage and can9 intersecting + else if(nodeId == 'can9' && otherNodeId == 'n3'){ + console.log('Can 9 placed!', type, otherNodeId); + const visible = type === 'start'; + scene.setChallengeEventValue('can9Intersects', visible); + setNodeVisible('blueGarage', visible); + } + }, ['n1','n2','n3']); +} + `; const uprightCans = ` // When a can is standing upright, the upright condition is met. -// let startTime = Date.now(); const EULER_IDENTITY = Rotation.Euler.identity(); -// const startingOrientationInv = (nodeId) => Quaternion.inverse(Rotation.toRawQuaternion(scene.nodes[nodeId].startingOrigin.orientation || EULER_IDENTITY)); const yAngle = (nodeId) => 180 / Math.PI * Math.acos(Vector3.dot(Vector3.applyQuaternion(Vector3.Y, Rotation.toRawQuaternion(scene.nodes[nodeId].origin.orientation || EULER_IDENTITY)), Vector3.Y)); scene.addOnRenderListener(() => { - // const currTime = Date.now(); - // const timeDiff = currTime - startTime; + const upright2 = yAngle('can2') < 5; const upright9 = yAngle('can9') < 5; const upright10 = yAngle('can10') < 5; - // if(timeDiff > 1000) { - // console.log('can6 angle: ', yAngle('can6')); - // startTime = currTime; - // } scene.setChallengeEventValue('can2Upright', upright2); scene.setChallengeEventValue('can9Upright', upright9); scene.setChallengeEventValue('can10Upright', upright10); @@ -92,6 +83,11 @@ export const JBC_6: Scene = { z: Distance.meters(3.54), }, }, + n_geom: { + type: 'cylinder', + radius: Distance.centimeters(2), + height: Distance.centimeters(0.1), + }, startBox_geom: { type: "box", size: { @@ -194,7 +190,7 @@ export const JBC_6: Scene = { type: "object", geometryId: "blueGarage_geom", name: { [LocalizedString.EN_US]: "Blue Garage" }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-13.4), @@ -210,9 +206,9 @@ export const JBC_6: Scene = { }, }, material: { - type: "basic", - color: { - type: "color3", + type: 'pbr', + emissive: { + type: 'color3', color: Color.rgb(255, 255, 255), }, }, @@ -239,6 +235,66 @@ export const JBC_6: Scene = { }, }, }, + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(52), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.5), + y: Distance.centimeters(-6), + z: Distance.centimeters(78.9), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-13), + y: Distance.centimeters(-6), + z: Distance.centimeters(95), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, ...baseScene.nodes, can2: {...createCanNode(2), scriptIds: ["garageIntersects"]}, can9: {...createCanNode(9,{ From 8ce92ce4eb2e71c92e244559a86cdcca91fc31d3 Mon Sep 17 00:00:00 2001 From: Erin Harrington Date: Fri, 17 Mar 2023 09:29:34 -0500 Subject: [PATCH 37/37] Finished JBC13 implementation with testing --- src/challenges/jbc13.ts | 20 +-- src/scenes/jbc13.ts | 368 ++++++++++++++++++++++++++++++++++------ 2 files changed, 322 insertions(+), 66 deletions(-) diff --git a/src/challenges/jbc13.ts b/src/challenges/jbc13.ts index d9e2b43a..afac9dc4 100644 --- a/src/challenges/jbc13.ts +++ b/src/challenges/jbc13.ts @@ -22,44 +22,44 @@ export default { events: { can2Intersects: { name: { [LocalizedString.EN_US]: 'Can 2 Intersects' }, - description: { [LocalizedString.EN_US]: 'Can 2 intersects a garage' }, + description: { [LocalizedString.EN_US]: 'Can 2 intersects chosen garage' }, }, can5Intersects: { name: { [LocalizedString.EN_US]: 'Can 5 Intersects' }, - description: { [LocalizedString.EN_US]: 'Can 5 intersects a garage' }, + description: { [LocalizedString.EN_US]: 'Can 5 intersects chosen garage' }, }, can8Intersects: { name: { [LocalizedString.EN_US]: 'Can 8 Intersects' }, - description: { [LocalizedString.EN_US]: 'Can 8 intersects a garage' }, + description: { [LocalizedString.EN_US]: 'Can 8 intersects chosen garage' }, }, can10Intersects: { name: { [LocalizedString.EN_US]: 'Can 10 Intersects' }, - description: { [LocalizedString.EN_US]: 'Can 10 intersects a garage' }, + description: { [LocalizedString.EN_US]: 'Can 10 intersects chosen garage' }, }, can11Intersects: { name: { [LocalizedString.EN_US]: 'Can 11 Intersects' }, - description: { [LocalizedString.EN_US]: 'Can 11 intersects a garage' }, + description: { [LocalizedString.EN_US]: 'Can 11 intersects chosen garage' }, }, can2Upright: { name: { [LocalizedString.EN_US]: 'Can 2 Upright' }, - description: { [LocalizedString.EN_US]: 'Can 2 upright in a garage' }, + description: { [LocalizedString.EN_US]: 'Can 2 upright in chosen garage' }, }, can5Upright: { name: { [LocalizedString.EN_US]: 'Can 5 Upright' }, - description: { [LocalizedString.EN_US]: 'Can 5 upright in a garage' }, + description: { [LocalizedString.EN_US]: 'Can 5 upright in achosen garage' }, }, can8Upright: { name: { [LocalizedString.EN_US]: 'Can 8 Upright' }, - description: { [LocalizedString.EN_US]: 'Can 8 upright in a garage' }, + description: { [LocalizedString.EN_US]: 'Can 8 upright in chosen garage' }, }, can10Upright: { name: { [LocalizedString.EN_US]: 'Can 10 Upright' }, - description: { [LocalizedString.EN_US]: 'Can 10 upright in a garage' }, + description: { [LocalizedString.EN_US]: 'Can 10 upright in chosen garage' }, }, can11Upright: { name: { [LocalizedString.EN_US]: 'Can 11 Upright' }, - description: { [LocalizedString.EN_US]: 'Can 11 upright in a garage' }, + description: { [LocalizedString.EN_US]: 'Can 11 upright in chosen garage' }, }, diff --git a/src/scenes/jbc13.ts b/src/scenes/jbc13.ts index 611d4dc9..03b4a55c 100644 --- a/src/scenes/jbc13.ts +++ b/src/scenes/jbc13.ts @@ -4,7 +4,8 @@ import Script from "../state/State/Scene/Script"; import { createCanNode, createBaseSceneSurfaceA } from "./jbcBase"; import { Color } from "../state/State/Scene/Color"; import { Distance , Angle} from "../util"; - +import { Rotation, ReferenceFrame } from '../unit-math'; +import { Vector2 } from '../math'; const baseScene = createBaseSceneSurfaceA(); const garageIntersects = ` @@ -13,64 +14,114 @@ const setNodeVisible = (nodeId, visible) => scene.setNode(nodeId, { visible }); -// When a can (can2, can5, can8, can10, can11) is intersecting a garage, the garage glows let chosenGarage = []; -let garageCans = [] -let begin = 0; +let declaredGarage = []; +let parkedCans = []; +let clicked = true; +let count = 0; +let state = 0; scene.onBind = nodeId => { - - scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { - const visible = type === 'start'; - //No chosen garage yet and enters - if(chosenGarage.length == 0){ - chosenGarage[0] = otherNodeId; + + scene.addOnIntersectionListener('robot', (type, otherNodeId) => { + if (state >= 2){ + state = 0; + } + + //Entering StartBox Events + if(otherNodeId == 'startBox' && type == 'start'){ + + //Reset Challenge Sequence + if(parkedCans.length > 0 || chosenGarage.length > 0){ + for (let i = 0; i < chosenGarage.length; i++){ + chosenGarage.pop(); + } + for (let i = 0; i < declaredGarage.length; i++){ + declaredGarage.pop(); + } - setNodeVisible(chosenGarage[0], true); + for (let i = 0; i < parkedCans.length; i++){ + parkedCans.pop(); + } + clicked = true; + + } + } + + + + }, ['startBox']); + + + scene.addOnIntersectionListener(nodeId, (type, otherNodeId) => { - //If the garage the can moved into is the desired garage - if(otherNodeId == chosenGarage[0] && type === 'start'){ - console.log(nodeId +' placed!', type, otherNodeId); - garageCans.push(nodeId); - scene.setChallengeEventValue(nodeId + 'Intersects', true); - if(chosenGarage.length > 0){ - setNodeVisible(chosenGarage[0], true); + const visible = type === 'start'; + //Entering Garage Events + if(type == 'start'){ + + if(nodeId != 'robot' && otherNodeId == 'n1' && declaredGarage.includes('greenBox')){ + state++; + if(parkedCans.includes(nodeId) == false){ + parkedCans.push(nodeId); + } + scene.setChallengeEventValue(nodeId+"Intersects",visible ); } + else if(nodeId != 'robot' && otherNodeId == 'n2' && declaredGarage.includes('yellowBox')) { + state++; + scene.setChallengeEventValue(nodeId+"Intersects",visible ); + if(parkedCans.includes(nodeId) == false){ + parkedCans.push(nodeId); + } + scene.setChallengeEventValue(nodeId+"Intersects",visible ); + } + else if(nodeId != 'robot' && otherNodeId == 'n3' && declaredGarage.includes('blueBox')) { + state++; + scene.setChallengeEventValue(nodeId+"Intersects",visible ); + if(parkedCans.includes(nodeId) == false){ + parkedCans.push(nodeId); + } + scene.setChallengeEventValue(nodeId+"Intersects",visible ); + } + + } - - //If a previously entered can leaves desired garage - if(otherNodeId == chosenGarage[0] && type === 'end' && (garageCans.includes(nodeId) == true)){ - const removeIndex = garageCans.indexOf(nodeId); - const x = garageCans.splice(removeIndex,1); - scene.setChallengeEventValue(nodeId + 'Intersects', false); - + if(type == 'end' && parkedCans.includes(nodeId) && otherNodeId == declaredGarage[0]){ + const removeIndex = parkedCans.indexOf(nodeId); + const x = parkedCans.splice(removeIndex,1); } - //If a previously enterted can in desired garage enters a different garage - else if(otherNodeId != chosenGarage[0] && (garageCans.includes(nodeId) == true)){ - const removeIndex = garageCans.indexOf(otherNodeId); - const x = garageCans.splice(removeIndex,1); - - - } + + console.log("Parked cans: " + parkedCans + " NodeId: "+ nodeId + " Type: " + type); + }, ['n1','n2','n3']); + + + //User declares garage + scene.addOnClickListener(['greenBox','yellowBox','blueBox'], id => { - //If there aren't any cans in a garage, reset chosen garage - if(garageCans.length == 0){ - setNodeVisible(chosenGarage[0], false); - chosenGarage.pop(); - + clicked = !clicked; + setNodeVisible('greenBox', clicked); + setNodeVisible('yellowBox', clicked); + setNodeVisible('blueBox', clicked); + if(id == 'greenBox'){ + chosenGarage.push('greenGarage'); + declaredGarage.push('greenBox'); } - - - console.log("Chosen Garage: " + chosenGarage); - console.log("Cans In Chosen Garage: " + garageCans); - }, ['yellowGarage','blueGarage','greenGarage']); - -} + else if(id == 'yellowBox'){ + chosenGarage.push('yellowGarage'); + declaredGarage.push('yellowBox'); + } + else if(id == 'blueBox'){ + chosenGarage.push('blueGarage'); + declaredGarage.push('blueBox'); + } + }); + +} `; + const uprightCans = ` // When a can is standing upright, the upright condition is met. const EULER_IDENTITY = Rotation.Euler.identity(); @@ -143,9 +194,217 @@ export const JBC_13: Scene = { z: Distance.centimeters(18), }, }, + n_geom: { + type: "box", + size: { + x: Distance.centimeters(20), + y: Distance.centimeters(0.1), + z: Distance.centimeters(20), + }, + }, + designatorBox_geom: { + type: 'box', + size: { + x: Distance.centimeters(10), + y: Distance.centimeters(1), + z: Distance.centimeters(10), + }, + }, }, nodes: { ...baseScene.nodes, + startBox: { + type: 'object', + geometryId: 'startBox_geom', + name: { [LocalizedString.EN_US]: 'Start Box' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(-10), + }, + }, + material: { + type: 'pbr', + emissive: { + type: 'color3', + color: Color.rgb(255, 255, 255), + }, + }, + }, + greenBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Green Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6), + z: Distance.centimeters(53), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-90), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, + + yellowBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(18.5), + y: Distance.centimeters(-6), + z: Distance.centimeters(78.9), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-90), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, + + blueBox: { + type: 'object', + geometryId: 'designatorBox_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage Designator Box' }, + visible: true, + origin: { + position: { + x: Distance.centimeters(-12), + y: Distance.centimeters(-6), + z: Distance.centimeters(94), + }, + orientation: { + + type: 'euler', + x: Angle.degrees(0), + y: Angle.degrees(-135), + z: Angle.degrees(0), + }, + }, + material: { + type: 'basic', + color: { + type: 'texture', + uri: '/static/Click Here.png', + }, + }, + faceUvs: [ + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.ZERO, Vector2.ZERO, + Vector2.create(0, 1), Vector2.create(1, 0), //TOP + Vector2.ZERO, Vector2.ZERO, + ], + }, + + n1: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Green Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(0), + y: Distance.centimeters(-6.9), + z: Distance.centimeters(53), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + n2: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Yellow Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(18.5), + y: Distance.centimeters(-6), + z: Distance.centimeters(78), + }, + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, + n3: { + type: 'object', + geometryId: 'n_geom', + name: { [LocalizedString.EN_US]: 'Blue Garage node' }, + visible: false, + origin: { + position: { + x: Distance.centimeters(-13), + y: Distance.centimeters(-6), + z: Distance.centimeters(94), + }, + orientation: Rotation.AxisAngle.fromRaw({ + axis: { x: 0, y: 1, z: 0 }, + angle: 115.5, + }), + }, + material: { + type: "basic", + color: { + type: "color3", + color: Color.rgb(0, 0, 0), + }, + }, + }, greenGarage: { type: "object", geometryId: "greenGarage_geom", @@ -162,7 +421,7 @@ export const JBC_13: Scene = { type: "pbr", emissive: { type: "color3", - color: Color.rgb(255, 255, 255), + color: Color.rgb(200, 200, 200), }, }, }, @@ -171,25 +430,22 @@ export const JBC_13: Scene = { type: "object", geometryId: "blueGarage_geom", name: { [LocalizedString.EN_US]: "Blue Garage" }, - visible: true, + visible: false, origin: { position: { x: Distance.centimeters(-13.4), y: Distance.centimeters(-6.9), z: Distance.centimeters(96), }, - // orientation: { - - // type: 'euler', - // x: Angle.degrees(0), - // y: Angle.degrees(-45), - // z: Angle.degrees(0), - // }, + orientation: Rotation.AxisAngle.fromRaw({ + axis: { x: 0, y: 1, z: 0 }, + angle: 115.5, + }), }, material: { - type: "basic", - color: { - type: "color3", + type: 'pbr', + emissive: { + type: 'color3', color: Color.rgb(255, 255, 255), }, },