diff --git a/.github/scripts/extract_percentages.py b/.github/scripts/extract_percentages.py index 89b7811628..7d4fafb433 100644 --- a/.github/scripts/extract_percentages.py +++ b/.github/scripts/extract_percentages.py @@ -24,15 +24,21 @@ def extract_similarity_percentage(html_file): def process_html_files(directory, threshold=50): log("Processing HTML files for plagiarism results...") high_plagiarism_detected = False + high_plagiarism_files = [] for filename in os.listdir(directory): if filename.endswith(".html"): file_path = os.path.join(directory, filename) percentage = extract_similarity_percentage(file_path) if percentage is not None and percentage >= threshold: log(f"High plagiarism detected - {filename.replace('.html', '.js')}: {percentage}%") + high_plagiarism_files.append(filename.replace('.html', '.js') + ": " + str(percentage) + "%") high_plagiarism_detected = True + return high_plagiarism_detected, high_plagiarism_files - return high_plagiarism_detected +def write_to_markdown(file_path, lines): + with open(file_path, 'w') as md_file: + for line in lines: + md_file.write(line + '\n') def main(): if len(sys.argv) != 2: @@ -41,12 +47,19 @@ def main(): sys.exit(1) saved_dir_path = sys.argv[1] - log(f"Received saved directory path: {saved_dir_path}") - if process_html_files(saved_dir_path): + high_plagiarism_detected, high_plagiarism_files = process_html_files(saved_dir_path) + + markdown_lines = ["# Plagiarism Report"] + if high_plagiarism_detected: log("High plagiarism percentages detected.") + markdown_lines.append("## High plagiarism percentages detected in the following files:") + markdown_lines.extend(high_plagiarism_files) + write_to_markdown("plagiarism_report.md", markdown_lines) sys.exit(1) else: log("No high plagiarism percentages detected.") + markdown_lines.append("No high plagiarism percentages detected.") + write_to_markdown("plagiarism_report.md", markdown_lines) if __name__ == "__main__": main() \ No newline at end of file diff --git a/.github/workflows/check_plagiarism.yml b/.github/workflows/check_plagiarism.yml index d87729a397..285521582b 100644 --- a/.github/workflows/check_plagiarism.yml +++ b/.github/workflows/check_plagiarism.yml @@ -26,12 +26,21 @@ jobs: - name: Get list of changed files id: changed-files run: | - base_sha="${{ github.event.pull_request.base.sha }}" - head_sha="${{ github.event.pull_request.head.sha }}" - js_files=$(git diff --name-only --diff-filter=AM $base_sha..$head_sha | grep 'games/.*\.js$' | xargs) - echo "FILES=$js_files" >> $GITHUB_ENV - + echo "Pull Request Base SHA: ${{ github.event.pull_request.base.sha }}" + echo "Pull Request Head SHA: ${{ github.event.pull_request.head.sha }}" + echo "Running git diff..." + git diff --name-only --diff-filter=AM --find-renames --find-copies ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} + echo "Filtering JS files in games/ directory..." + js_files=$(git diff --name-only --diff-filter=AM --find-renames --find-copies ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} | grep 'games/.*\.js$' | xargs) + echo "Found JS files: $js_files" + if [ -z "$js_files" ]; then + echo "No JavaScript files found in the changes." + else + echo "FILES=$js_files" >> $GITHUB_ENV + fi + - name: Run Plagiarism Detection Script + if: env.FILES != '' run: python .github/scripts/plagiarism_check.py ${{ env.FILES }} games output_dir saved_dir - name: Extract and Display Similarity Percentages @@ -45,6 +54,12 @@ jobs: name: compare50-results path: saved_dir/ + - name: Upload Plagiarism Report as Artifact + uses: actions/upload-artifact@v3 + with: + name: plagiarism-report + path: plagiarism_report.md + - name: Check for High Plagiarism Percentages if: steps.extract-percentages.outcome == 'failure' run: echo "Plagiarism percentage over threshold detected." \ No newline at end of file diff --git a/.github/workflows/workflow_run.yml b/.github/workflows/workflow_run.yml new file mode 100644 index 0000000000..4b8e6f207a --- /dev/null +++ b/.github/workflows/workflow_run.yml @@ -0,0 +1,76 @@ +name: Send Plagiarism Result On CI Complete + +permissions: + actions: read + contents: read + +on: + workflow_run: + workflows: ["Plagiarism Checker"] + types: + - completed + +jobs: + on_pr_finish: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download Plagiarism Report Artifact + uses: actions/download-artifact@v3 + with: + name: plagiarism-report + + - name: Post Markdown as Comment + uses: actions/github-script@v7 + env: + WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }} + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const fs = require('fs'); + const path = require('path'); + + console.log("Reading the Markdown report from the artifact..."); + const markdownContent = fs.readFileSync(path.join(process.env.GITHUB_WORKSPACE, 'plagiarism_report.md'), 'utf8'); + + console.log("Fetching associated workflow run..."); + const runId = process.env.WORKFLOW_RUN_ID; + console.log(`Looking for workflow run with ID: ${runId}`); + + const runs = await github.actions.listWorkflowRuns({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'check_plagiarism', + }); + + console.log(`Workflow runs fetched: ${runs.data.total_count}`); + runs.data.workflow_runs.forEach(run => { + console.log(`Run ID: ${run.id}, Name: ${run.name}, Event: ${run.event}, Status: ${run.status}`); + }); + + const associatedRun = runs.data.workflow_runs.find(run => run.id == runId); + if (!associatedRun) { + console.log("No associated workflow run found."); + return; + } + + console.log(`Operating on workflow: ${associatedRun.name}, ID: ${associatedRun.id}`); + + if (!associatedRun.pull_requests || associatedRun.pull_requests.length == 0) { + console.log("No associated pull request found for this workflow run."); + return; + } + + const prNumber = associatedRun.pull_requests[0].number; + console.log(`Found associated pull request: #${prNumber}`); + + console.log("Posting the Markdown content as a comment..."); + await github.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: markdownContent + }); + console.log("Comment posted successfully."); \ No newline at end of file diff --git a/games/Hard-Hat_Helper.js b/games/Hard-Hat_Helper.js new file mode 100644 index 0000000000..5e9248f444 --- /dev/null +++ b/games/Hard-Hat_Helper.js @@ -0,0 +1,553 @@ +//based on Mario vs. Donkey Kong: Mini-Land Mayhem! for the 3DS + +const playerR = "r" +const playerL = "l" +const background = "b" +const goal = "g" +const wall = "w" +const platformOFF = "f" +const platformON = "o" +const lift = "e" +const spring = "s" +const detectionR = "d" +const detectionL = "a" +const detectionDR = "z" +const detectionDL = "c" +const platform = "p" +const rBelt = "t" +const lBelt = "j" + +setLegend( + [ playerR, bitmap` +................ +................ +....00000000.... +...0666666660... +..066600006660.. +..066066660660.. +.06606600660660. +.06066066066060. +0666606666066660 +.000L27LL27L000. +...0L27LL27L0... +...0LLLLLLLL0... +...0LLL00LLL0... +...0CC0..0CC0... +...0CCC0.0CCC0.. +...00000.00000..` ], + [ playerL, bitmap` +................ +................ +....00000000.... +...0666666660... +..066600006660.. +..066066660660.. +.06606600660660. +.06066066066060. +0666606666066660 +.000L72LL72L000. +...0L72LL72L0... +...0LLLLLLLL0... +...0LLL00LLL0... +...0CC0..0CC0... +..0CCC0.0CCC0... +..00000.00000...` ], + [ background, bitmap` +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777 +7777777777777777`], + [ wall, bitmap` +0000000000000000 +010..........010 +0000........0000 +0.010LLLLLL010.0 +0..000....000..0 +0..L010..010L..0 +0..L.000000.L..0 +0..L..0LL0..L..0 +0..L..0LL0..L..0 +0..L.000000.L..0 +0..L010..010L..0 +0..000....000..0 +0.010LLLLLL010.0 +0000........0000 +010..........010 +0000000000000000`], + [ goal, bitmap` +..00000......... +..0CC4400....... +..0CCDD4400..... +..0CC44DD4400... +..0CCDD44DD4400. +..0CC44DD44DD440 +..0CCDD44DD4400. +..0CC44DD4400... +..0CCDD4400..... +..0CC4400....... +..0CC00......... +..0CC0.......... +..0CC0.......... +..0CC0.......... +..0CC0.......... +..0CC0..........`], + [ platformOFF, bitmap` +0000000000000000 +030LLLLLLLLLL030 +030LLLLLLLLLL030 +030LLLLLLLLLL030 +030LL00LLLLLL030 +000L0LL0L0LLL000 +0LLL0LL0LL0LLLL0 +0LLL000LLLL0LLL0 +0LLL0L0LLL0LLLL0 +0LLL0LL0L0LLLLL0 +000LLLLLLLLLL000 +030LLLLLLLLLL030 +030LLLLLLLLLL030 +030LLLLLLLLLL030 +030LLLLLLLLLL030 +0000000000000000`], + [ platformON, bitmap` +LLLLLLLLLLLLLLLL +L4L1111111111L4L +L4L1111111111L4L +L4L1111111111L4L +L4L1100111111L4L +LLL1011010111LLL +L11101101101111L +L11100011110111L +L11101011101111L +L11101101011111L +LLL1111111111LLL +L4L1111111111L4L +L4L1111111111L4L +L4L1111111111L4L +L4L1111111111L4L +LLLLLLLLLLLLLLLL`], + [detectionR, bitmap` +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555`], + [detectionL, bitmap` +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555`], + [detectionDR, bitmap` +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555`], + [detectionDL, bitmap` +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555 +5555555555555555`], + [lift, bitmap` +0000000000000000 +0999999999999990 +090L........L090 +.0L9999999999L0. +.0.90LLLLLL09.0. +.0.9LLLLL0LL9.0. +.0.9L0LL0L0L9.0. +.0.9L0LLLLLL9.0. +.0.9L0LL0L0L9.0. +.0.9L000L0LL9.0. +.0.9LLLLLLLL9.0. +.0.90LLLLLL09.0. +.0L9999999999L0. +090L........L090 +0999999999999990 +0000000000000000`], + [spring, bitmap` +.00000000000000. +0333333003333330 +0333330330333330 +0333303333033330 +0333033333303330 +.00000000000000. +..LL111LL111LL.. +..11LL111LL111.. +..L111LL111LL1.. +..1LL111LL111L.. +..111LL111LL11.. +00LL111LL111LL00 +0LLLLLLLLLLLLLL0 +0LLLLLLLLLLLLLL0 +0LLLLLLLLLLLLLL0 +0000000000000000`], + [platform, bitmap` +.L000000000000L. +L1L9999999999L1L +0L999999999999L0 +0999990999999990 +0999990999999990 +0999990999999990 +0999190000919990 +0991L999999L1990 +091LL999999LL190 +01LLLLL99LLLLL10 +01LLLLL99LLLLL10 +091LL999999LL190 +0991L999999L1990 +0L991999999199L0 +L1L9999999999L1L +.L000000000000L.`], + [lBelt, bitmap` +0.0.0.0.0.0.0.0. +0000000000000000 +1111..1111..1111 +1LL1..1LL1..1LL1 +1LL1CCCCCCCC1LL1 +CCCCC110111CCCCC +9939C101001C9939 +9399C011001C9399 +9399C011010C9399 +9939C101010C9939 +CCCCC110111CCCCC +1LL1CCCCCCCC1LL1 +1LL1..1LL1..1LL1 +1111..1111..1111 +0000000000000000 +.0.0.0.0.0.0.0.0`], + [rBelt, bitmap` +0.0.0.0.0.0.0.0. +0000000000000000 +1111..1111..1111 +1LL1..1LL1..1LL1 +1LL1CCCCCCCC1LL1 +CCCCC110111CCCCC +9799C101001C9799 +9979C011001C9979 +9979C011010C9979 +9799C101010C9799 +CCCCC110111CCCCC +1LL1CCCCCCCC1LL1 +1LL1..1LL1..1LL1 +1111..1111..1111 +0000000000000000 +.0.0.0.0.0.0.0.0`] +) +setBackground(background); + +var level = 0 +const levels = [ + //10 levels + map` +...... +...... +...... +...... +wr..gw +wwwfww`, //1 + map` +...... +...... +...... +...... +wg..rw +wwffww`, //2 + map` +...... +...... +...... +....gw +wr..ww +wwfs..`, //3 + map` +wwwwww +wg...w +wwoo.w +w....w +wl..ew +wwffww`, //4 + map` +...e.ewew +....w.w.w +....w.w.g +....w.w.w +w.l.w...w +wwwwwwwww`, //5 + map` +w.....w +w.....w +w.....w +w.....w +wr...gw +wwp..ww`, //6 + map` +w......g +w...pwww +we.....w +ww..p..w +wr....ew +ww..pwww`, //7 + map` +wwwwwww +w.....w +w.....w +w.....w +w.....w +wr...gw +wwjjjww`, //8 + map` +wr....ew +wwjjjj.w +we.....w +w.jjjjww +w.....ew +wwjjjj.w +wg.....w +wwjjjjww`, //9 + map` +w....ww +w.....w +w.ttt.w +weg...w +www..ew +wr..www +wwfs..w`, //10 + map ` +.......... +.wwww..w.w +..w.www.w. +..w.w.ww.w +.......... +.......... +.......... +.......... +wr.......w +wwwwwwwwww` +] +setMap(levels[level]); +setSolids([platformON, playerR, playerL, wall, spring, platform, lBelt, rBelt]); + +onInput("l", () => { + platformONOFF() +}); +onInput("w", () => { + liftUP() +}); +onInput("s", () => { + liftDOWN() +}); +onInput("a", () => { + mpL() +}); +onInput("d", () => { + mpR() +}); +onInput("j", () =>{ + beltC(); +}) + +const movep = setInterval(move, 1000) + +//moving platforms +function mpR(){ + for(let i = 0; i < getAll(platform).length; i++){ + getAll(platform)[i].x += 1 + } +} +function mpL(){ + for(let i = 0; i < getAll(platform).length; i++){ + getAll(platform)[i].x -= 1 + } +} + +//turns the platforms on or off +var num = 1; +function platformONOFF(){ + num += 1 + if(num % 2 == 0){ + for(let i = 0; i < getAll(platformOFF).length; i++){ + let px = getAll(platformOFF)[i].x + let py = getAll(platformOFF)[i].y + getAll(platformOFF)[i].remove() + addSprite(px, py, platformON) + } + } + if(num % 2 != 0){ + for(let i = 0; i < getAll(platformON).length; i++){ + let px = getAll(platformON)[i].x + let py = getAll(platformON)[i].y + getAll(platformON)[i].remove() + addSprite(px, py, platformOFF) + } + } +} + +//belt controlls +var num2 = 1; +function beltC(){ + num2 += 1 + if(num2 % 2 == 0){ + for(let i = 0; i < getAll(lBelt).length; i++){ + let px = getAll(lBelt)[i].x + let py = getAll(lBelt)[i].y + getAll(lBelt)[i].remove() + addSprite(px, py, rBelt) + } + } + if(num2 % 2 != 0){ + for(let i = 0; i < getAll(rBelt).length; i++){ + let px = getAll(rBelt)[i].x + let py = getAll(rBelt)[i].y + getAll(rBelt)[i].remove() + addSprite(px, py, lBelt) + } + } +} + +//move charater back and forth,wall & floor detection, and check win condition +function move(){ + if(tilesWith(playerR, goal).length > 0 || tilesWith(playerL, goal).length > 0){ + level = level + 1; + setMap(levels[level]); + } +//right -> left + for( let i = 0; i < getAll(playerR).length; i++){ + let px = getAll(playerR)[i].x + let py = getAll(playerR)[i].y + let dx = px + 1 + let dy = py + 1 + addSprite(dx, py, detectionR) + addSprite(dx, dy, detectionDR) + if(tilesWith(detectionR, wall).length == 1 || tilesWith(detectionDR, wall).length == 0 && tilesWith(detectionDR, platformON).length == 0 && tilesWith(spring, detectionDR).length == 0 && tilesWith(detectionR, lift).length == 0 && tilesWith(platform, detectionDR).length == 0 && tilesWith(rBelt, detectionDR).length == 0){ + getAll(playerR)[i].remove() + getAll(detectionR)[i].remove() + getAll(detectionDR)[i].remove() + addSprite(px, py, playerL) + }else if (tilesWith(detectionDR, spring).length == 1){ + getAll(playerR)[i].x += 1 + getAll(playerR)[i].y -= 1 + getAll(playerR)[i].x += 1 + getAll(detectionR)[i].remove() + getAll(detectionDR)[i].remove() + }else{ + getAll(playerR)[i].x += 1 + getAll(detectionR)[i].remove() + getAll(detectionDR)[i].remove() + } + } + //left -> right + for(let i = 0; i < getAll(playerL).length; i++){ + let px = getAll(playerL)[i].x + let py = getAll(playerL)[i].y + let dx = px - 1 + let dy = py + 1 + addSprite(dx, py, detectionL) + addSprite(dx, dy, detectionDL) + if(tilesWith(detectionL, wall).length == 1 || tilesWith(detectionDL, wall).length == 0 && tilesWith(detectionDL, platformON).length == 0 && tilesWith(spring, detectionDL).length == 0 && tilesWith(detectionL, lift).length == 0 && tilesWith(platform, detectionDL).length == 0 && tilesWith(lBelt, detectionDL).length == 0){ + getAll(playerL)[i].remove() + getAll(detectionL)[i].remove() + getAll(detectionDL)[i].remove() + addSprite(px, py, playerR) + }else if (tilesWith(detectionDL, spring).length == 1){ + getAll(playerL)[i].x -= 1 + getAll(playerL)[i].y -= 1 + getAll(playerL)[i].x -= 1 + getAll(detectionL)[i].remove() + getAll(detectionDL)[i].remove() + }else{ + getAll(playerL)[i].x -= 1 + getAll(detectionL)[i].remove() + getAll(detectionDL)[i].remove() + } + } +} + +//lift functions up and down +function liftUP(){ + for(let i = 0; i < getAll(lift).length; i++){ + for(let i = 0; i < getAll(playerR).length; i++){ + if(tilesWith(playerR, lift).length == 1){ + getAll(playerR)[i].y -= 1 + } + } + for(let i = 0; i < getAll(playerL).length; i++){ + if(tilesWith(playerL, lift).length == 1){ + getAll(playerL)[i].y -= 1 + } + } + getAll(lift)[i].y -= 1 + } +} +function liftDOWN(){ + for(let i = 0; i < getAll(lift).length; i++){ + for(let i = 0; i < getAll(playerR).length; i++){ + if(tilesWith(playerR, lift).length == 1){ + getAll(playerR)[i].y += 1 + } + } + for(let i = 0; i < getAll(playerL).length; i++){ + if(tilesWith(playerL, lift).length == 1){ + getAll(playerL)[i].y += 1 + } + } + getAll(lift)[i].y += 1 + } +} diff --git a/games/Morse_trainer.js b/games/Morse_trainer.js new file mode 100644 index 0000000000..e47f94fff5 --- /dev/null +++ b/games/Morse_trainer.js @@ -0,0 +1,244 @@ +/* +Morse code trainer by Yutaro +Has two modes: Morse to text and text to morse +Used for learning morse code +*/ + +//backgrounds +const titleScreen = "t"; +const menuSelect = "m"; + +const maps = [ + map`` +] +setLegend( + [titleScreen,bitmap` +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +2222222222222222 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000`], + [menuSelect,bitmap` +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000`], +) + +setMap(map`.`) + +let currentState = "title"; +let sound = false; +//display screen drawing function +function drawScreen(){ + clearText() + if (currentState == "title"){ + setBackground(titleScreen); + addText("Morse Trainer", { + x: 4, + y: 4, + color: color`3` + }) + + //sound message + addText(`Sound: ${sound}`, { + x: 4, + y: 6, + color: color`3` + }) + + //addText("Press A to start\nD to toggle sound", { + // x: 2, + // y: 12, + // color: color`3` + //}) + } + + if (currentState == "modeSelect"){ + setBackground(menuSelect); + addText("W: Instructions", { + x: 1, + y: 5, + color: color`3` + }) + + addText("S: morse -> text", { + x: 1, + y: 7, + color: color`3` + }) + + addText("A: text -> morse", { + x: 1, + y: 9, + color: color`3` + }) + } + +} + +drawScreen(); + + +//character database +const characters = {"0":"-----","1":".----","2":"..---","3":"...--","4":"....-","5":".....","6":"-....","7":"--...","8":"---..","9":"----.","a":".-","b":"-...","c":"-.-.","d":"-..","e":".","f":"..-.","g":"--.","h":"....","i":"..","j":".---","k":"-.-","l":".-..","m":"--","n":"-.","o":"---","p":".--.","q":"--.-","r":".-.","s":"...","t":"-","u":"..-","v":"...-","w":".--","x":"-..-","y":"-.--","z":"--..",".":".-.-.-",",":"--..--","?":"..--..","!":"-.-.--","-":"-....-","/":"-..-.","@":".--.-.","(":"-.--.",")":"-.--.-"} + +//sorted version +const charIndex = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"] + +//funciton to convert the typed morese code to text +function findCharacter(moresePattern){ + //not found + let ret = "NF"; + let keys = Object.keys(characters); + for(let i = 0;i { + if(currentState == "title"){ + sound = !sound; + drawScreen(); + } + if(currentState == "morseText"){ + currentMorse = ""; + game(); + return; + } + if(currentState == "textMorse"){ + textMorsedisplay = ""; + charLen = 0; + game(); + } +}); + +onInput("a", () => { + if(currentState == "title"){ + currentState = "modeSelect"; + drawScreen(); + return; + } + if(currentState == "modeSelect"){ + currentState = "textMorse"; + game(); + return; + } + if(currentState == "morseText"){ + let tem = findCharacter(currentMorse); + currentMorse = ""; + if(tem != "NF")currentCharacterBuffer+=tem; + game(); + return; + } + + if(currentState == "textMorse"){ + charLen+=characters[charIndex[currentCharIndex]].length+1; + if(charLen>15) {textMorsedisplay+="\n";charLen = 0;} + textMorsedisplay+=characters[charIndex[currentCharIndex]]+" "; + game(); + } +}); + +onInput("w", () => { + if(currentState == "modeSelect"){ + currentState = "instructions"; + game(); + return; + } + if(currentState == "morseText"){ + currentMorse+="."; + game(); + } + if(currentState == "textMorse"){ + if(currentCharIndex { + if(currentState == "modeSelect"){ + currentState = "morseText"; + game(); + return; + } + if(currentState == "morseText"){ + currentMorse+="-"; + game(); + } + if(currentState == "textMorse"){ + if(currentCharIndex>=0)currentCharIndex-=1; + game(); + } +}); + + diff --git a/games/img/Morse_trainer.png b/games/img/Morse_trainer.png new file mode 100644 index 0000000000..b8eea73caf Binary files /dev/null and b/games/img/Morse_trainer.png differ diff --git a/games/metadata.json b/games/metadata.json index d9f58dc195..2fa01abc3b 100644 --- a/games/metadata.json +++ b/games/metadata.json @@ -3294,5 +3294,29 @@ "img": "", "tags": [""], "addedOn": "2023-12-19" + }, + { + "filename": "Hard-Hat_Helper", + "title": "Hard-Hat_Helper", + "author": "Nathan Jereb", + "img": "", + "tags": [""], + "addedOn": "2023-12-21" + }, + { + "filename": "Morse_trainer", + "title": "Morse_trainer", + "author": "Yuuta", + "img": "", + "tags": [""], + "addedOn": "2023-12-21" + }, + { + "filename": "starjump", + "title": "starjump", + "author": "skifli", + "img": "", + "tags": ["sokoban-style"], + "addedOn": "2023-12-21" } ] diff --git a/games/starjump.js b/games/starjump.js new file mode 100644 index 0000000000..14581deb70 --- /dev/null +++ b/games/starjump.js @@ -0,0 +1,521 @@ +/* +@title: Starjump +@author: skifli + +Instructions: + +Hit "run" to execute the code and +start the game (you can also press shift+enter). + +The objective is to get all the stars. Use WASD to move. Later levels also require keys to be obtained to gain access to the stars. +Press k to reset the level. +*/ + +const PLAYER = "p" +const KEY = "k" +const STAR = "s" +const WALL = "w" +const WALL_BOTTOM = "g" +const WALL_DIRT = "o" +const WALL_DIRT_SIDES = "i" +const WALL_DIRT_TOPS = "v" +const WALL_DIRT_LSIDE = "j" +const WALL_DIRT_RSIDE = "h" +const WALL_LSIDE = "l" +const WALL_RSIDE = "r" +const WALL_BOTTOM_LSIDE = "y" +const WALL_BOTTOM_RSIDE = "n" +const WALL_3_TOP = "f" +const WALL_3_BOTTOM = "m" + +const MAP_SIZE = 15 +const MIDDLE = Math.floor(MAP_SIZE/2) + +const move = tune` +500: A4~500, +15500` +const star = tune` +250: A4-250, +250: E5-250, +250: A5-250, +7250` +var key = tune` +166.66666666666666: A4/166.66666666666666, +166.66666666666666: C5/166.66666666666666 + G4^166.66666666666666, +166.66666666666666: E5/166.66666666666666, +166.66666666666666: G4^166.66666666666666, +4666.666666666666` +const newLevel = tune` +250: A4~250 + E5-250, +250: G4~250 + D5-250, +250: F4~250 + C5-250, +7250` +const finishedTune = tune` +125: A4~125 + C4-125, +125: A4~125 + D4^125, +125: C4-125 + C5^125, +125: D4^125 + G4/125, +125: D5~125 + C4-125, +125: F5~125 + D4^125 + F4^125, +125: C4-125 + A4/125, +125: D4^125, +125: D5~125 + C4-125, +125: A4~125 + D4^125 + C5/125, +125: C4-125, +125: F4~125 + D4^125 + C5^125, +125: A4~125 + C4-125, +125: D4^125 + F4/125 + C5/125, +125: C4-125, +2125` + +var won = false; +var finished = false; + +function handleMove() { + if (!finished) { + playTune(move) + + let coords = getFirst(PLAYER) + let starCoords = getFirst(STAR) + let keyCoords = getFirst(KEY) + + if (keyCoords != undefined) { + let keys = getAll(KEY) + + for (let i = 0; i < keys.length; i++) { + let keyFound = keys[i] + + if (coords.x == keyFound.x && coords.y == keyFound.y) { + playTune(key) + + keyFound.remove() + + return + } + } + + return + } + + if (coords.x == starCoords.x && coords.y == starCoords.y) { + playTune(star) + + won = true + addText("PRESS L", {x: MIDDLE, y: MIDDLE, color: color`8`}) + } + } +} + +setLegend( + [ PLAYER, bitmap` +................ +...00..0000..... +...0800888000... +..088888888800.. +..088HH888800... +..0888888880.... +...000CCCCCL.... +.....LCC29CL.... +....LLCC29CCL... +....LCCCCCCCL... +....L7777777L... +....L777777L.... +.....L77577L.... +.....F77575L.... +....FF705750.... +....FFF007500...` ], + [ STAR, bitmap` +.......00....... +......0660...... +......0660...... +.....066660..... +0000006666000000 +0666666666666660 +.06666066066660. +..066606606660.. +...0660660660... +...0666666660... +..066666666660.. +..066666666660.. +.06666600666660. +.066600..006660. +06600......00660 +000..........000`], + [ KEY, bitmap` +................ +................ +......000....... +.....07770...... +....077.770..... +....07...70..... +....077.770..... +.....07770...... +......070....... +......070....... +......070....... +......0770...... +......070....... +......0770...... +.......00....... +................`], + [ WALL, bitmap` +D4D4DD4DD44DD4DD +DDDDD44444DDDD4D +D4444DDD444D4DD4 +CCCCCCCCCCCCCCCC +CCCCCCCC11CCCCCC +CCL1CCCCLCCCCCCC +CC11CCCCCCC1L1CC +CCCCCCCCCCC111CC +CCCCCCCCCCCCCCCC +CCCCCCC11CCCCCCC +CC1LCCCL1CCCC11C +CC11CCCCCCCCC1LC +CCCCCCCCCCCCCCCC +CLCCCCCCCC11CCCC +C11CCCCCCC1LCCCC +CCCCCCCCCCCCCCCC`], + [ WALL_BOTTOM, bitmap` +CCCCCCCCCCCCCCCC +C11CCCCCCC1LCCCC +CLCCCCCCCC11CCCC +CCCCCCCCCCCCCCCC +CC11CCCCCCCCC1LC +CC1LCCCL1CCCC11C +CCCCCCC11CCCCCCC +CCCCCCCCCCCCCCCC +CCCCCCCCCCC111CC +CC11CCCCCCC1L1CC +CCL1CCCCLCCCCCCC +CCCCCCCC11CCCCCC +CCCCCCCCCCCCCCCC +D4444DDD444D4DD4 +DDDDD44444DDDD4D +D4D4DD4DD44DD4DD`], + [ WALL_DIRT, bitmap` +CCCCCCCCCCCCCCCC +CCC11CCCCCCL1CCC +CCC1LCCCCCC11CCC +CCCCCCCCCCCCCCCC +CCCCCCCC11CCCCCC +CCL1CCCCLCCCCCCC +CC11CCCCCCC1L1CC +CCCCCCCCCCC111CC +CCCCCCCCCCCCCCCC +CCCCCCC11CCCCCCC +CC1LCCCL1CCCC11C +CC11CCCCCCCCC1LC +CCCCCCCCCCCCCCCC +CLCCCCCCCC11CCCC +C11CCCCCCC1LCCCC +CCCCCCCCCCCCCCCC`], + [ WALL_DIRT_SIDES, bitmap` +4DCCCCCCCCCCCC4D +44C11CCCCCCL1C4D +D4C1LCCCCCC11C4D +D4CCCCCCCCCCCC44 +D4CCCCCC11CCCCD4 +D4L1CCCCLCCCCCD4 +4411CCCCCCC1L1D4 +4DCCCCCCCCC111D4 +4DCCCCCCCCCCCCD4 +4DCCCCC11CCCCCD4 +441LCCCL1CCCC144 +D411CCCCCCCCC14D +D4CCCCCCCCCCCC4D +D4CCCCCCCC11CC4D +D41CCCCCCC1LCC4D +D4CCCCCCCCCCCC4D`], + [ WALL_DIRT_TOPS, bitmap` +DDDDD44444DDDD44 +444444DDD444444D +C1CC11CCC1LCCCCC +CCCC1LCCC11CC11C +CCCCCCCCCCCCCL1C +CCCCCCCCCCCCCCCC +CCCCCCCCCCCCCCCC +CCCCCL1CCCCCCCCC +CCCCC11CCCL1CCCC +CCCCCCCCCCC1CCCC +C11CCCCCCCCCCCCC +CL1CCCCC11CCC1LC +CCCCCCCC1LCCC11C +CCCC11CC11CCCCCC +444444DDDDDD4444 +DDDDD44444444DDD`], + [ WALL_DIRT_LSIDE, bitmap` +4DCCCCCCCCCCCCCC +44C11CCCCCCL1CCC +D4C1LCCCCCC11CCC +D4CCCCCCCCCCCCCC +D4CCCCCC11CCCCCC +D4L1CCCCLCCCCCCC +4411CCCCCCC1L1CC +4DCCCCCCCCC111CC +4DCCCCCCCCCCCCCC +4DCCCCC11CCCCCCC +441LCCCL1CCCC1CC +D411CCCCCCCCC1CC +D4CCCCCCCCCCCCCC +D4CCCCCCCC11CCCC +D41CCCCCCC1LCCCC +D4CCCCCCCCCCCCCC`], + [ WALL_DIRT_RSIDE, bitmap` +CCCCCCCCCCCCCC4D +CCC11CCCCCCL1C4D +CCC1LCCCCCC11C4D +CCCCCCCCCCCCCC44 +CCCCCCCC11CCCCD4 +CCL1CCCCLCCCCCD4 +CC11CCCCCCC1L1D4 +CCCCCCCCCCC111D4 +CCCCCCCCCCCCCCD4 +CCCCCCC11CCCCCD4 +CC1LCCCL1CCCC144 +CC11CCCCCCCCC14D +CCCCCCCCCCCCCC4D +CCCCCCCCCC11CC4D +CC1CCCCCCC1LCC4D +CCCCCCCCCCCCCC4D`], + [ WALL_LSIDE, bitmap` +D4D4DD4DD44DD4DD +DDDDD44444DDDD4D +D4444DDD444D4DD4 +44CCCCCCCCCCCCCC +D4CCCCCC11CCCCCC +D4L1CCCCLCCCCCCC +D411CCCCCCC1L1CC +4DCCCCCCCCC111CC +4DCCCCCCCCCCCCCC +4DCCCCC11CCCCCCC +4D1LCCCL1CCCC11C +4D11CCCCCCCCC1LC +4DCCCCCCCCCCCCCC +D4CCCCCCCC11CCCC +D41CCCCCCC1LCCCC +D4CCCCCCCCCCCCCC`], + [ WALL_RSIDE, bitmap` +DD4DD44DD4DD4D4D +D4DDDD44444DDDDD +4DD4D444DDD4444D +CCCCCCCCCCCCCC44 +CCCCCC11CCCCCC4D +CCCCCCCLCCCC1L4D +CC1L1CCCCCCC114D +CC111CCCCCCCCCD4 +CCCCCCCCCCCCCCD4 +CCCCCCC11CCCCCD4 +C11CCCC1LCCCL1D4 +CL1CCCCCCCCC11D4 +CCCCCCCCCCCCCCD4 +CCCC11CCCCCCCC4D +CCCCL1CCCCCCC14D +CCCCCCCCCCCCCC4D`], + [ WALL_BOTTOM_LSIDE, bitmap` +D4CCCCCCCCCCCCCC +D41CCCCCCC1LCCCC +D4CCCCCCCC11CCCC +4DCCCCCCCCCCCCCC +4D11CCCCCCCCC1LC +4D1LCCCL1CCCC11C +4DCCCCC11CCCCCCC +4DCCCCCCCCCCCCCC +4DCCCCCCCCC111CC +D411CCCCCCC1L1CC +D4L1CCCCLCCCCCCC +D4CCCCCC11CCCCCC +44CCCCCCCCCCCCCC +D4444DDD444D4DD4 +DDDDD44444DDDD4D +D4D4DD4DD44DD4DD`], + [ WALL_BOTTOM_RSIDE, bitmap` +CCCCCCCCCCCCCC4D +CCCCL1CCCCCCC14D +CCCC11CCCCCCCC4D +CCCCCCCCCCCCCCD4 +CL1CCCCCCCCC11D4 +C11CCCC1LCCCL1D4 +CCCCCCC11CCCCCD4 +CCCCCCCCCCCCCCD4 +CC111CCCCCCCCCD4 +CC1L1CCCCCCC114D +CCCCCCCLCCCC1L4D +CCCCCC11CCCCCC4D +CCCCCCCCCCCCCC44 +4DD4D444DDD4444D +D4DDDD44444DDDDD +DD4DD44DD4DD4D4D`], + [ WALL_3_TOP, bitmap` +D4D4DD4DD44DD4DD +DDDDD44444DDDD4D +D4444DDD444D4DD4 +44CCCCCCCCCCCC4D +D4CCCCCC11CCCC4D +D4L1CCCCLCCCCC4D +D411CCCCCCC1L14D +4DCCCCCCCCC11144 +4DCCCCCCCCCCCC44 +4DCCCCC11CCCCC44 +4D1LCCCL1CCCC14D +4D11CCCCCCCCC144 +4DCCCCCCCCCCCC44 +D4CCCCCCCC11CCD4 +D41CCCCCCC1LCCD4 +D4CCCCCCCCCCCCD4`], + [ WALL_3_BOTTOM, bitmap` +D4CCCCCCCCCCCCD4 +D41CCCCCCC1LCCD4 +D4CCCCCCCC11CCD4 +4DCCCCCCCCCCCC44 +4D11CCCCCCCCC144 +4D1LCCCL1CCCC14D +4DCCCCC11CCCCC44 +4DCCCCCCCCCCCC44 +4DCCCCCCCCC11144 +D411CCCCCCC1L14D +D4L1CCCCLCCCCC4D +D4CCCCCC11CCCC4D +44CCCCCCCCCCCC4D +D4444DDD444D4DD4 +DDDDD44444DDDD4D +D4D4DD4DD44DD4DD`], +) + +let currentLevel = 1 +let levels = [map` +p.jh....i...jooo +..yn..r.i...jooo +.....ln.i...yggg +wwr.ln..i....... +gggwn...ywr.lr.. +...i.....yn.jh.. +...i........jn.. +...i.......ln... +...i..lwwwwh..lw +...ywwogggggr.yg +....joh.....i... +....ygh.....jwr. +.lr...jwwr..joh. +.yh...yooh..joh. +..jwr..ygn..ygn. +s.joh...........`, map` +pjh...joh....... +.yh..lgggvr....l +..yr.i....i.lr.j +r..i.i.lr.i.jh.j +h..i.i.yh.i.jh.j +h.lh.i..i.i.jh.j +h.yowor.i.i.jh.j +h..yggn.i.i.jh.j +or......i.i.jn.j +oor...lvn.i.i..j +ooowwvn...i.i.lo +ooooh....ln.i.jo +ogoon..lwn..i.yo +h.yn...yn..lh..y +h..........jh... +owwwwwwwwwwoh..s`,map` +pjooooooh....... +.joogooon..lr... +.ygn.yoh..lggr.. +......yn.lh..i.l +...lr....jh..i.j +wwwoowwr.yn.lh.j +oooggggh....jh.j +ooh....jvwvvoh.j +oon.lr.i.i..yn.j +on..jh.i.i.....y +h...ynsi.i..lr.. +or....lh.i..jh.. +oh....jh.ik.jh.. +oor...yn.jwwoh.. +ooh......ygggn.. +ooowwwwr........`, map` +p.yggggggggogggo +r..........i...j +or....lwwr.i.f.j +oor...yooh.m.i.j +ooor...yoh...i.j +oooor...yowwwh.j +ooooh....yoooh.j +ooooor....yooh.j +oooooh.....yoh.j +oogggn......jh.j +on..........yhkj +h......lr....ywo +h..lwwvggr....yo +h..ygn...yr....y +h.........yr.... +owwwwwwwr.kjr.s.`, map` +pi...i......jooo +.i.f.i......yggg +.i.i.i..lwr..... +.i.i.i..joh..f.. +.i.i.i.looh..i.. +.i.i.i.jooh..i.. +.i.i.i.jooh..i.. +.i.i.i.jooh..i.. +.i.i.i.joon..i.. +.i.i.i.joo..ln.. +.i.i.i.jon..i... +.i.i.i.jo..lh... +.i.i.i.jn..ygr.k +.i.i.iki.....yww +.m.i.ygn.lwr..yo +...i.....joor.sj`] + +setMap(levels[currentLevel]) +setSolids([PLAYER, WALL, WALL_BOTTOM, WALL_DIRT, WALL_DIRT_SIDES, WALL_DIRT_TOPS, WALL_DIRT_LSIDE, WALL_DIRT_RSIDE, WALL_LSIDE, WALL_RSIDE, WALL_BOTTOM_LSIDE, WALL_BOTTOM_RSIDE, WALL_3_TOP, WALL_3_BOTTOM]) + +onInput("w", () => { + if (!won) { + getFirst(PLAYER).y -= 1 + } +}) + +onInput("s", () => { + if (!won) { + getFirst(PLAYER).y += 1 + } +}) + +onInput("a", () => { + if (!won) { + getFirst(PLAYER).x -= 1 + } +}) + +onInput("d", () => { + if (!won) { + getFirst(PLAYER).x += 1 + } +}) + +onInput("l", () => { + if (won) { + currentLevel++ + clearText() + + if (currentLevel == levels.length) { + playTune(finishedTune) + addText("YOU WON", {x: MIDDLE, y: MIDDLE, color: color`6`}); + + finished = true; + } else { + won = false + + setMap(levels[currentLevel]) + } + + playTune(newLevel) + } +}) + + +onInput("k", () => { + setMap(levels[currentLevel]) +}) + +afterInput(() => { + handleMove() +}) \ No newline at end of file diff --git a/src/lib/game-saving/gallery.ts b/src/lib/game-saving/gallery.ts index 6c49e74eea..7512771bf7 100644 --- a/src/lib/game-saving/gallery.ts +++ b/src/lib/game-saving/gallery.ts @@ -1,3 +1,5 @@ +import metadata from '../../../games/metadata.json' + export interface GameMetadata { filename: string title: string @@ -8,4 +10,4 @@ export interface GameMetadata { isNew: true | undefined } -export const getGalleryGames = async () => await fetch('https://raw.githubusercontent.com/hackclub/sprig/main/games/metadata.json').then((res) => res.json()) as GameMetadata[] \ No newline at end of file +export const getGalleryGames = () => metadata as GameMetadata[] \ No newline at end of file diff --git a/src/pages/gallery/[filename].astro b/src/pages/gallery/[filename].astro index 5ec4f6607c..6fec957e36 100644 --- a/src/pages/gallery/[filename].astro +++ b/src/pages/gallery/[filename].astro @@ -27,7 +27,7 @@ let tutorial: string[] | undefined = files ?.map(md => md.compiledContent()) if (tutorial.length == 0) tutorial = undefined -const games = await getGalleryGames() +const games = getGalleryGames() const metadata = games.find(game => game.filename === filename) const name = metadata?.title const authorName = metadata?.author diff --git a/src/pages/gallery/index.astro b/src/pages/gallery/index.astro index 741490019c..20fa6ece1b 100644 --- a/src/pages/gallery/index.astro +++ b/src/pages/gallery/index.astro @@ -9,7 +9,7 @@ import Gallery from "./gallery"; const session = await getSession(Astro.cookies); -const games = await getGalleryGames(); +const games = getGalleryGames(); const tags = [ ...new Set(games.reduce((p, c) => [...p, ...c.tags], [])), ];