From ba405b8fed5760ca05c174aa443885f1b4f19451 Mon Sep 17 00:00:00 2001 From: Ting-Kuan Date: Thu, 13 Feb 2014 09:21:40 -0500 Subject: [PATCH 1/3] Revise zh-tw translations. --- app/locale/zh-HANT.coffee | 72 +++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index 31a9bc743..4bc71f9f5 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -3,14 +3,14 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese loading: "Loading..." saving: "儲存中..." sending: "發送中...." - cancel: "退出" -# save: "Save" + cancel: "取消" + save: "存檔" delay_1_sec: "1 秒" delay_3_sec: "3 秒" delay_5_sec: "5 秒" - manual: "手動手动" + manual: "手動發動" # fork: "Fork" - play: "玩" + play: "播放" # Play timeline in a level. modal: close: "關閉" @@ -20,17 +20,17 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese page_not_found: "找不到網頁" nav: - play: "玩" + play: "開始遊戲" editor: "編輯" - blog: "博客" - forum: "論壇" - admin: "超級管理員" + blog: "部落格" # Official blog + forum: "論壇" # Official forum + admin: "系統管理員" home: "首頁" contribute: "貢獻" - legal: "法律" + legal: "版權聲明" # Copyright about: "關於" contact: "聯繫我們" - twitter_follow: "關注" + twitter_follow: "在Twitter關注" # employers: "Employers" # versions: @@ -43,8 +43,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese login: sign_up: "註冊" - log_in: "登錄" - log_out: "退出" + log_in: "登入" + log_out: "登出" recover: "找回帳戶" recover: @@ -53,51 +53,51 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese signup: # create_account_title: "Create Account to Save Progress" - description: "這是免費的。超簡單的喲:" + description: "登入以儲存遊戲進度:" email_announcements: "通過郵件接收通知" coppa: "13歲以上或非美國公民" coppa_why: "爲什麽?" creating: "帳戶創建中..." sign_up: "註冊" - log_in: "登錄" + log_in: "登入" home: slogan: "通過玩遊戲學習Javascript 腳本語言" no_ie: "抱歉!Internet Explorer 9 等舊的瀏覽器打不開此網站" no_mobile: "CodeCombat 不是針對手機設備設計的,所以可能會出問題!" - play: "玩" + play: "開始遊戲" play: - choose_your_level: "選取難度" + choose_your_level: "選取關卡" adventurer_prefix: "你可以選擇以下任意關卡,或者討論以上的關卡 " adventurer_forum: "冒險家論壇" adventurer_suffix: "." - campaign_beginner: "新手作戰" + campaign_beginner: "新手指南" campaign_beginner_description: "...在這裡可以學到編程技巧。" campaign_dev: "隨機關卡" - campaign_dev_description: "...在這裡你可以學到做一些複雜功能的接口。" + campaign_dev_description: "...在這裡你可以學到做一些較複雜的程式技巧。" campaign_multiplayer: "多人競技場" - campaign_multiplayer_description: "...在這裡你可以和其他玩家們進行代碼近戰。" - campaign_player_created: "已創建的玩家" - campaign_player_created_description: "...在這裡你可以與你的小夥伴的創造力戰鬥 技術指導." + campaign_multiplayer_description: "...在這裡你可以和其他玩家進行對戰。" + campaign_player_created: "玩家建立的關卡" + campaign_player_created_description: "...挑戰同伴的創意 技術指導." level_difficulty: "難度" contact: contact_us: "聯繫我們" welcome: "很高興收到你的信!用這個表格給我們發電郵。 " - contribute_prefix: "如果你想貢獻代碼,請看 " - contribute_page: "貢獻代碼頁面" + contribute_prefix: "如果你想貢獻程式,請看 " + contribute_page: "程式貢獻頁面" contribute_suffix: "!" - forum_prefix: "對於任何公共部份,放手去做吧 " - forum_page: "我們的論壇" - forum_suffix: "代替。" + forum_prefix: "如果有任何問題, 請至" + forum_page: "論壇" + forum_suffix: "討論。" sending: "發送中。。。" send: "意見反饋" diplomat_suggestion: title: "幫我們翻譯CodeCombat" sub_heading: "我們需要您的語言技能" - pitch_body: "我們開發了CodeCombat的英文版,但是現在我們的玩家遍佈全球。很多人想玩中文(繁体)版的,卻不會說英文,所以如果你中英文都會,請考慮一下參加我們的翻譯工作,幫忙把 CodeCombat 網站還有所有的關卡翻譯成中文(繁体)。" + pitch_body: "我們開發了CodeCombat的英文版,但是現在我們的玩家遍佈全球。很多人想玩中文版的,卻不會說英文,所以如果你中英文都會,請考慮一下參加我們的翻譯工作,幫忙把 CodeCombat 網站還有所有的關卡翻譯成中文(繁体)。" missing_translations: "直至所有正體中文的翻譯完畢,當無法提供正體中文時還會以英文顯示。" learn_more: "關於成為外交官" subscribe_as_diplomat: "註冊成為外交官" @@ -107,21 +107,21 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # customize_avatar: "Customize Your Avatar" account_settings: - title: "帳戶設置" + title: "帳戶設定" not_logged_in: "登錄或創建一個帳戶來修改設置。" autosave: "自動保存修改" me_tab: "我" - picture_tab: "圖片" + picture_tab: "頭像" wizard_tab: "巫師" password_tab: "密碼" - emails_tab: "郵件" - gravatar_select: "選擇使用 Gravatar 照片" + emails_tab: "電子郵件" + gravatar_select: "選擇一個 Gravatar" gravatar_add_photos: "添加小圖和照片到一个 Gravatar 帳戶供你選擇。" gravatar_add_more_photos: "添加更多照片到你的 Gravatar 帳戶并查看。" wizard_color: "巫師 衣服 顏色" new_password: "新密碼" - new_password_verify: "核實" - email_subscriptions: "郵箱驗證" + new_password_verify: "確認密碼" + email_subscriptions: "訊息設定" email_announcements: "通知" email_announcements_description: "接收關於 CodeCombat 最近的新聞和發展的郵件。" contributor_emails: "貢獻者電郵" @@ -134,7 +134,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese password_mismatch: "密碼不匹配。" account_profile: - edit_settings: "編輯設置" + edit_settings: "帳號設定" profile_for_prefix: "關於TA的基本資料:" # profile_for_suffix: "" profile: "基本資料" @@ -253,8 +253,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # version_history_for: "Version History for: " # results: "Results" # description: "Description" - email: "郵箱" - message: "留言" + email: "Email" + message: "訊息" # about: # who_is_codecombat: "Who is CodeCombat?" From 803770a08042e0b7405ede13964856f19dfb1db2 Mon Sep 17 00:00:00 2001 From: Ting-Kuan Date: Thu, 13 Feb 2014 14:32:08 -0500 Subject: [PATCH 2/3] Revise the phrasing of exisitng translations. Translate "about". --- app/locale/zh-HANT.coffee | 135 +++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee index 4bc71f9f5..f12a105a0 100644 --- a/app/locale/zh-HANT.coffee +++ b/app/locale/zh-HANT.coffee @@ -9,7 +9,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese delay_3_sec: "3 秒" delay_5_sec: "5 秒" manual: "手動發動" -# fork: "Fork" + fork: "Fork" play: "播放" # Play timeline in a level. modal: @@ -22,8 +22,8 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese nav: play: "開始遊戲" editor: "編輯" - blog: "部落格" # Official blog - forum: "論壇" # Official forum + blog: "官方部落格" # Official blog + forum: "論壇" admin: "系統管理員" home: "首頁" contribute: "貢獻" @@ -31,7 +31,7 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese about: "關於" contact: "聯繫我們" twitter_follow: "在Twitter關注" -# employers: "Employers" + employers: "招募訊息" # versions: # save_version_title: "Save New Version" @@ -45,19 +45,19 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese sign_up: "註冊" log_in: "登入" log_out: "登出" - recover: "找回帳戶" + recover: "找回帳號" recover: - recover_account_title: "復原帳戶" -# send_password: "Send Recovery Password" + recover_account_title: "復原帳號" + send_password: "送出新密碼" signup: -# create_account_title: "Create Account to Save Progress" + create_account_title: "建立帳號儲存進度" description: "登入以儲存遊戲進度:" email_announcements: "通過郵件接收通知" coppa: "13歲以上或非美國公民" coppa_why: "爲什麽?" - creating: "帳戶創建中..." + creating: "帳號建立中..." sign_up: "註冊" log_in: "登入" @@ -107,91 +107,92 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # customize_avatar: "Customize Your Avatar" account_settings: - title: "帳戶設定" - not_logged_in: "登錄或創建一個帳戶來修改設置。" + title: "帳號設定" + not_logged_in: "登錄或建立一個帳號來修改設置。" autosave: "自動保存修改" me_tab: "我" picture_tab: "頭像" wizard_tab: "巫師" password_tab: "密碼" - emails_tab: "電子郵件" - gravatar_select: "選擇一個 Gravatar" - gravatar_add_photos: "添加小圖和照片到一个 Gravatar 帳戶供你選擇。" - gravatar_add_more_photos: "添加更多照片到你的 Gravatar 帳戶并查看。" + emails_tab: "郵件" + gravatar_select: "選擇一個Gravatar" + gravatar_add_photos: "上傳頭像到Gravatar" + # gravatar_add_more_photos: "Add thumbnails and photos to a Gravatar account for your email to choose an image." wizard_color: "巫師 衣服 顏色" new_password: "新密碼" new_password_verify: "確認密碼" - email_subscriptions: "訊息設定" + email_subscriptions: "訂閱" email_announcements: "通知" - email_announcements_description: "接收關於 CodeCombat 最近的新聞和發展的郵件。" + email_notifications_description: "接收帳號通知" + email_announcements_description: "接收關於 CodeCombat 的新聞和開發消息。" contributor_emails: "貢獻者電郵" contribute_prefix: "我們在尋找志同道合的人!請到 " contribute_page: "貢獻頁面" contribute_suffix: " 查看更多信息。" - email_toggle: "切換所有" - error_saving: "保存時出錯" - saved: "保存修改" - password_mismatch: "密碼不匹配。" + email_toggle: "全選" + error_saving: "保存時發生錯誤" + saved: "修改已儲存" + password_mismatch: "密碼不正確。" account_profile: edit_settings: "帳號設定" - profile_for_prefix: "關於TA的基本資料:" -# profile_for_suffix: "" + profile_for_prefix: "關於" + profile_for_suffix: "的基本資料" profile: "基本資料" user_not_found: "沒有找到用戶。檢查URL?" - gravatar_not_found_mine: "我們找不到TA的基本資料:" - gravatar_not_found_email_suffix: "." - gravatar_signup_prefix: "去註冊 " - gravatar_signup_suffix: " 去設置!" - gravatar_not_found_other: "哎呦,沒有與這個人的郵箱相關的資料。" - gravatar_contact: "聯繫" + gravatar_not_found_mine: "我們找不到有關" + gravatar_not_found_email_suffix: "的資料" + gravatar_signup_prefix: "請至" + gravatar_signup_suffix: " 註冊帳號" + gravatar_not_found_other: "哎呦,找不到這個地址的資料。" + gravatar_contact: "聯繫我們" gravatar_websites: "網站" gravatar_accounts: "顯示為" gravatar_profile_link: "完善 Gravatar 資料" play_level: - level_load_error: "關卡不能載入。" + level_load_error: "載入關卡時發生錯誤。" done: "完成" grid: "格子" customize_wizard: "自定義巫師" - home: "主頁" + home: "首頁" guide: "指南" multiplayer: "多人遊戲" restart: "重新開始" goals: "目標" action_timeline: "行動時間軸" click_to_select: "點擊選擇一個單元。" - reload_title: "重載所有代碼?" - reload_really: "確定重載這一關,返回開始處?" - reload_confirm: "重載所有" -# victory_title_prefix: "" + reload_title: "重新載入程式碼?" + reload_really: "確定重設所有的程式碼?" + reload_confirm: "重設所有程式碼" + victory_title_prefix: "" victory_title_suffix: " 完成" victory_sign_up: "保存進度" - victory_sign_up_poke: "想保存你的代碼?創建一個免費帳戶吧!" + victory_sign_up_poke: "想保存你的程式碼?建立一個免費帳號吧!" victory_rate_the_level: "評估關卡: " victory_play_next_level: "下一關" - victory_go_home: "返回主頁" - victory_review: "給我們反饋!" + victory_go_home: "返回首頁" + victory_review: "給我們回饋!" victory_hour_of_code_done: "你完成了嗎?" - victory_hour_of_code_done_yes: "是的,我完成了我的代碼!" - multiplayer_title: "多人遊戲設置" - multiplayer_link_description: "把這個鏈接告訴小夥伴們,一起玩吧。" + victory_hour_of_code_done_yes: "是的,我完成了我的程式碼!" + multiplayer_title: "多人遊戲設定" + multiplayer_link_description: "把這個連結告訴同伴們,一起玩吧。" multiplayer_hint_label: "提示:" - multiplayer_hint: " 點擊全選,然後按 Apple-C(苹果電腦)或 Ctrl-C 複製鏈接。" - multiplayer_coming_soon: "多人遊戲的更多特性!" + multiplayer_hint: " 點擊全選,然後按 ⌘-C 或 Ctrl-C 複製連結。" + multiplayer_coming_soon: "請期待更多的多人關卡!" guide_title: "指南" tome_minion_spells: "助手的咒語" - tome_read_only_spells: "只讀的咒語" - tome_other_units: "其他單元" + tome_read_only_spells: "唯讀的咒語" + tome_other_units: "其他單位" tome_cast_button_castable: "發動" tome_cast_button_casting: "發動中" tome_cast_button_cast: "咒語" tome_autocast_delay: "自動施法延遲" tome_select_spell: "選擇一個法術" - tome_select_a_thang: "選擇人物來 " + tome_select_a_thang: "選擇一個人物來施放" tome_available_spells: "可用的法術" hud_continue: "繼續 (按 shift-空格)" -# spell_saved: "Spell Saved" + spell_saved: "咒語已儲存" # admin: # av_title: "Admin Views" @@ -245,33 +246,33 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese # general: # and: "and" - or: "或" - name: "名字" +# or: "或" +# name: "名字" # body: "Body" # version: "Version" # commit_msg: "Commit Message" # version_history_for: "Version History for: " # results: "Results" # description: "Description" - email: "Email" - message: "訊息" +# email: "Email" +# message: "訊息" -# about: -# who_is_codecombat: "Who is CodeCombat?" -# why_codecombat: "Why CodeCombat?" -# who_description_prefix: "together started CodeCombat in 2013. We also created " -# who_description_suffix: "in 2008, growing it to the #1 web and iOS application for learning to write Chinese and Japanese characters." -# who_description_ending: "Now it's time to teach people to write code." -# why_paragraph_1: "When making Skritter, George didn't know how to program and was constantly frustrated by his inability to implement his ideas. Afterwards, he tried learning, but the lessons were too slow. His housemate, wanting to reskill and stop teaching, tried Codecademy, but \"got bored.\" Each week another friend started Codecademy, then dropped off. We realized it was the same problem we'd solved with Skritter: people learning a skill via slow, intensive lessons when what they need is fast, extensive practice. We know how to fix that." -# why_paragraph_2: "Need to learn to code? You don't need lessons. You need to write a lot of code and have a great time doing it." -# why_paragraph_3_prefix: "That's what programming is about. It's gotta be fun. Not fun like" -# why_paragraph_3_italic: "yay a badge" -# why_paragraph_3_center: "but fun like" -# why_paragraph_3_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!" -# why_paragraph_3_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing." -# why_paragraph_4: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age." -# why_ending: "And hey, it's free. " -# why_ending_url: "Start wizarding now!" + about: + who_is_codecombat: "什麼是CodeCombat?" + why_codecombat: "為什麼使用CodeCombat?" + who_description_prefix: "在2013年共同創立了CodeCombat. 在2008年, 我們創立了" + who_description_suffix: ",排名第一的中、日文字的學習網頁及iOS系統應用程式。" + who_description_ending: "這次,我們將教大家如何寫程式。" + why_paragraph_1: "當我們在研發Skritter時,George不會寫程式,所以常常無法展現他的想法。他嘗試去學,然而課程成果緩慢。他的室友曾想學習新技能,試過Codecademy,但厭倦了。每周也都有其他朋友投入Codecademy,卻都以失敗告終。我們發現,這與我們藉由Skritter所想解決的問題是一致的─人們需要的不是繁瑣又密集的課程, 而是快速而大量的練習。我們知道該如何改善這個情況。" + why_paragraph_2: "想學程式嗎? 你不需要課程。你需要的只是大量的時間去\"玩\"程式。" + why_paragraph_3_prefix: "寫程式應該是有趣的。當然不是" + why_paragraph_3_italic: "「耶!拿到獎章了。」" + why_paragraph_3_center: "的有趣, 而是" + why_paragraph_3_italic_caps: "「媽我不要出去玩,我要寫完這段!」" + why_paragraph_3_suffix: "般引人入勝。這是為甚麼CodeCombat被設計成多人對戰「遊戲」,而不是遊戲化「課程」。在你對這遊戲無法自拔之前,我們是不會放棄的─幫然,這個遊戲,將是有益於你的。" + why_paragraph_4: "如果你要沉迷遊戲的話,就來沉迷CodeCombat,成為科技時代的魔法師吧!" + why_ending: "啊還有,他是免費的。" + why_ending_url: "那還等什麼? 馬上開始!" # george_description: "CEO, business guy, web designer, game designer, and champion of beginning programmers everywhere." # scott_description: "Programmer extraordinaire, software architect, kitchen wizard, and master of finances. Scott is the reasonable one." # nick_description: "Programming wizard, eccentric motivation mage, and upside-down experimenter. Nick can do anything and chooses to build CodeCombat." From 7cec574e175af43b1e8da5267d8108e5fddd7a8e Mon Sep 17 00:00:00 2001 From: Michael Schmatz Date: Fri, 14 Feb 2014 10:49:16 -0800 Subject: [PATCH 3/3] Started simulator refactor --- app/lib/simulator/Simulator.coffee | 270 +++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 app/lib/simulator/Simulator.coffee diff --git a/app/lib/simulator/Simulator.coffee b/app/lib/simulator/Simulator.coffee new file mode 100644 index 000000000..bbf9c1f3b --- /dev/null +++ b/app/lib/simulator/Simulator.coffee @@ -0,0 +1,270 @@ +SuperModel = require 'models/SuperModel' +LevelLoader = require 'lib/LevelLoader' +GoalManager = require 'lib/world/GoalManager' + +module.exports = class Simulator + constructor: -> + @retryDelayInSeconds = 10 + @taskURL = "/queue/scoring" + + + fetchAndSimulateTask: => + $.ajax + url: @taskURL + type: "GET" + error: @handleFetchTaskError + success: @setupSimulationAndLoadLevel + + cleanupSimulation: -> + + + handleFetchTaskError: (errorData) => + console.log "There were no games to score. Error: #{JSON.stringify errorData}" + console.log "Retrying in #{@retryDelayInSeconds}" + _.delay @fetchAndSimulateTask, @retryDelayInSeconds * 1000 + + + setupSimulationAndLoadLevel: (taskData) => + @task = new SimulationTask(taskData) + @superModel = new SuperModel() + @god = new God() + @levelLoader = new LevelLoader @task.getLevelName(), @superModel, @task.getFirstSessionID() + + @levelLoader.once 'loaded-all', @simulateGame + + + + simulateGame: => + @assignWorldAndLevelFromLevelLoaderAndDestroyIt() + @setupGod() + try + @commenceSimulationAndSetupCallback() + catch e + console.log "There was an error in simulation. Trying again in #{retryDelayInSeconds} seconds" + console.log "Error #{e}" + _.delay @fetchAndSimulateTask, @retryDelayInSeconds * 1000 + + assignWorldAndLevelFromLevelLoaderAndDestroyIt: -> + @world = @levelLoader.world + @level = @levelLoader.level + @levelLoader.destroy() + + + setupGod: -> + @god.level = @level.serialize @supermodel + @god.worldClassMap = world.classMap + @setupGoalManager() + @setupGodSpells() + + + setupGoalManager: -> + @god.goalManager = new GoalManager @world + @god.goalManager.goals = @fetchGoalsFromWorldNoteChain() + @god.goalManager.goalStates = @manuallyGenerateGoalStates() + + commenceSimulationAndSetupCallback: -> + @god.createWorld() + Backbone.Mediator.subscribeOnce 'god:new-world-created', @processResults, @ + + + processResults: (simulationResults) -> + taskResults = @formTaskResultsObject simulationResults + sendResultsBackToServer taskResults + + sendResultsBackToServer: (results) => + $.ajax + url: @taskURL + data: results + type: "PUT" + success: @handleTaskResultsTransferSuccess + error: @handleTaskResultsTransferError + complete: @cleanupAndSimulateAnotherTask() + + handleTaskResultsTransferSuccess: (result) -> + console.log "Task registration result: #{JSON.stringify result}" + + handleTaskResultsTransferError: (error) -> + console.log "Task registration error: #{JSON.stringify error}" + + cleanupAndSimulateAnotherTask: => + @cleanupSimulation() + @fetchAndSimulateTask() + + + + formTaskResultsObject: (simulationResults) -> + taskResults = + taskID: @task.getTaskID() + receiptHandle: @task.getReceiptHandle() + calculationTime: 500 + sessions: [] + + for session in @task.sessions + sessionResult = + sessionID: session.sessionID + sessionChangedTime: session.sessionChangedTime + metrics: + rank: @calculateSessionRank session.sessionID, simulationResults.goalStates + + taskResults.sessions.push sessionResult + + return taskResults + + + calculateSessionRank: (sessionID, goalStates) -> + humansDestroyed = goalStates["destroy-humans"].status is "success" + ogresDestroyed = goalStates["destroy-ogres"].status is "success" + console.log "Humans destroyed:#{humansDestroyed}" + console.log "Ogres destroyed:#{ogresDestroyed}" + console.log "Team Session Map: #{JSON.stringify @teamSessionMap}" + if humansDestroyed is ogresDestroyed + return 0 + else if humansDestroyed and @teamSessionMap["ogres"] is sessionID + return 0 + else if humansDestroyed and @teamSessionMap["ogres"] isnt sessionID + return 1 + else if ogresDestroyed and @teamSessionMap["humans"] is sessionID + return 0 + else + return 1 + + + + fetchGoalsFromWorldNoteChain: -> return @god.goalManager.world.scripts[0].noteChain[0].goals.add + + + manuallyGenerateGoalStates: -> + goalStates = + "destroy-humans": + keyFrame: 0 + killed: + "Human Base": false + status: "incomplete" + "destroy-ogres": + keyFrame:0 + killed: + "Ogre Base": false + status: "incomplete" + + + + setupGodSpells: -> + @generateSpellsObject() + @god.spells = @spells + + + generateSpellsObject: (currentUserCodeMap) -> + @userCodeMap = currentUserCodeMap + @spells = {} + for thang in @level.attributes.thangs + continue if @thangIsATemplate thang + @generateSpellKeyToSourceMapPropertiesFromThang thang + + + thangIsATemplate: (thang) -> + for component in thang.components + continue unless @componentHasProgrammableMethods component + for methodName, method of component.config.programmableMethods + return true if methodBelongsToTemplateThang method + + return false + + + componentHasProgrammableMethods: (component) -> component.config? and _.has component.config, 'programmableMethods' + + methodBelongsToTemplateThang: (method) -> typeof method is 'string' + + generateSpellKeyToSourceMapPropertiesFromThang: (thang) => + for component in thang.components + continue unless @componentHasProgrammableMethods component + + for methodName, method of component.config.programmableMethods + spellKey = @generateSpellKeyFromThangIDAndMethodName thang.id, methodName + + @createSpellAndAssignName spellKey, methodName + @createSpellThang thang, method, spellKey + @transpileSpell thang, spellKey, methodName + + + + + generateSpellKeyFromThangIDAndMethodName: (thang, methodName) -> + spellKeyComponents = [thang.id, methodName] + pathComponents[0] = _.string.slugify pathComponents[0] + pathComponents.join '/' + + createSpellAndAssignName: (spellKey, spellName) -> + @spells[spellKey] ?= {} + @spells[spellKey].name = methodName + + createSpellThang: (thang, method, spellKey) -> + @spells[spellKey].thangs ?= {} + @spells[spellKey].thangs[thang.id] ?= {} + @spells[spellKey].thangs[thang.id].aether = @createAether @spells[spellKey].name, method + + transpileSpell: (thang, spellKey, methodName) -> + slugifiedThangID = _.string.slugify thang.id + source = @currentUserCodeMap[slugifiedThangID]?[methodName] ? "" + @spells[spellKey].thangs[thang.id].aether.transpile source + + + + + + + + createAether: (methodName, method) -> + aetherOptions = + functionName: methodName + protectAPI: false + includeFlow: false + return new Aether aetherOptions + + + + + + + + + +class SimulationTask + constructor: (@rawData) -> + + + getLevelName: -> + levelName = @rawData.sessions?[0]?.levelID + return levelName if levelName? + @throwMalformedTaskError "The level name couldn't be deduced from the task." + + generateTeamToSessionMap: -> + teamSessionMap = {} + for session in @rawData.sessions + @throwMalformedTaskError "Two players share the same team" if teamSessionMap[session.team]? + teamSessionMap[session.team] = session.sessionID + + teamSessionMap + + throwMalformedTaskError: (errorString) -> + throw new Error "The task was malformed, reason: #{errorString}" + + getFirstSessionID: -> @rawData.sessions[0].sessionID + + getTaskID: -> @rawData.taskID + + getReceiptHandle: -> @rawData.receiptHandle + + getSessions: -> @rawData.sessions + + generateSpellKeyToSourceMap: -> + spellKeyToSourceMap = {} + + for session in @rawData.sessions + teamSpells = session.teamSpells[session.team] + _.merge spellKeyToSourceMap, _.pick(session.code, teamSpells) + + commonSpells = session.teamSpells["common"] + _.merge spellKeyToSourceMap, _.pick(session.code, commonSpells) if commonSpells? + + spellKeyToSourceMap +