You are browsing as a guest. Sign up (or log in) to start making projects!

No Let

  • 13 Devlogs
  • 38 Total hours

A JavaScript coding puzzle site where you aren't allowed to declare let variables or use anything with mutable state.

Ship #2

No Let: a JS puzzle site where you aren’t allowed to use let or anything with mutable state.

This second ship was about implementing the fantastic suggestions in the feedback I got from my first ship.

  • I added anti-hardcoding checks to stop people from cheesing the puzzles
  • I added two new levels, including a very difficult one
  • I added confetti and visual feedback when a user completes a puzzle
  • I added a favicon
  • …Plus a handful of small tweaks and improvements

I’m looking forward to reading the feedback I get this time :)

  • 7 devlogs
  • 10h
Try project → See source code →
Open comments for this post

40m 56s logged

Final devlog before ship #2 :roo-so-excited:

  • I added difficulty ratings for each puzzle
  • I moved the logic/linter output (aka the checklist) right above the “run” button because it makes more sense there
  • I updated the README and added some screenshots
0
0
27
Open comments for this post

2h 9m 16s logged

How the heck did this take 2 hours…

All that I did in this devlog was improve the Conway’s Game of Life puzzle a bit. I rewrote some of the starter and solution code for simplicity (I can’t believe I forgot about the .flatMap() method), and I also wrote a bunch of comments that explain the starter code and solution code.

Next, I think I’ll add a difficulty indicator for the puzzles. I think I’ll probably be ready to re-ship after that!

0
0
111
Open comments for this post

4h 11m 16s logged

Hi! It’s been a while. Again.

The highlight of this devlog is the new puzzle: Conway’s Game of Life. In the feedback on my first ship, several people mentioned that they wanted more challenging levels. Well, here ya go! This puzzle is much more complex, and it also doesn’t lend itself well to functional programming, so you have to get creative in order to make the linter happy. Personally, after I designed the puzzle and wrote the starter code, it took me over 45 minutes to write the solution code. It’s pretty difficult, so hopefully it’ll satisfy the users who want a challenge.


I also made a few smaller changes:

  • I removed dev.css’s light mode, because all the rest of my styling is meant for dark mode
  • I set Maple Mono as the preferred font, but I intentionally made it only work if you already have Maple Mono installed, because I know that not everybody likes it
  • I added a special message if you try to run empty code

Next, I think I’ll start adding comments to some of the starter code and solution code. I think it’d be helpful for users who aren’t as familiar with JavaScript or function programming, so that they can more easily get acquainted with the starter code, and so that they can learn how the solution works if they choose to use it.

0
0
20
Open comments for this post

1h 5m 55s logged

I made a new puzzle! The puzzle involves implementing a Caesar cipher. That’s it, actually. It’s certainly not a very difficult puzzle, but it does contribute to puzzle variety.

Also, do you notice the new favicon? No more Svelte logo!

0
0
41
Open comments for this post

29m 23s logged

…i think the user would have more feedback/satisfaction if upon completion, something else happens to let them know they successfully completed a puzzle, something like confetti, or even just the “run” button changing color/text

When the puzzle states changes to “passed” (meaning the logic test and linter both passed) from some other status, I made it trigger a confetti effect via canvas-confetti and made the run button turn green.

Next, I’m probably going to make a favicon.

0
0
38
Open comments for this post

27m 31s logged

One thing: I can just cheese everything by changing the output manually. I recommend you use multiple test cases so i can not just type “return 6” and complete the task.

I added secretInput values to the rest of the puzzles to fix the hardcoding cheese. I also mentioned the anti-hardcoding in the README.

Next, I’m going to work on adding some confetti and whatnot for when the user’s code passes both the logic test and the linter.

0
0
45
Open comments for this post

46m 57s logged

Hi again! It’s been a while. I’m coming back to No Let because when I shipped it the first time, the lovely people who rated it took the time to write really thoughtful feedback and suggest great actionable improvements. So i thought it’d be fun to implement your suggestions (and also I was bored).

Here are some excerpts from the feedback I got:

One thing: I can just cheese everything by changing the output manually. I recommend you use multiple test cases so i can not just type “return 6” and complete the task.

Anyway, my biggest critique would be the lack of levels. I think that adding tiers of difficulty, along with 10-15 more levels would take this project to the highest possible level.

…svelte favicon ;)…

…i think the user would have more feedback/satisfaction if upon completion, something else happens to let them know they successfully completed a puzzle, something like confetti, or even just the “run” button changing color/text

I intend to fix/implement each one of these. With the exception of the “10-15 levels” one; that’s a bit more than I’m willing to make, but I will add some new puzzles.


So far, I’ve started implementing the first suggestion. I’m creating secretInput values for each puzzle, and in the test function, after it evaluates the input (which is publicly displayed), it runs the code again using the secretInput.

If the code passes the input check but fails the secretInput check, it fails the logic test with this message:

Failed secret anti-hardcoding check. You need to generalize your logic.

I’ve only added secretInputs for two puzzles so far, so the work is still ongoing.

0
0
19
Ship #1

No Let is a JavaScript puzzle site where you have to use pure functional programming, which means that you aren’t allowed to use let variables or anything else with mutable state.

I learned how to use QuickJS-emscripten, Prism code editor, and AcornJS, all of which are skills that I intend to reuse for later projects. I also learned a lot about pure functional programming itself while designing the puzzles.

I’m especially proud of how the linter/test messages smoothly animate in and out. The animation itself was just a simple slide transition with Svelte, but in order to make it work I had to refactor and unify the error message generation into one big array, which was unexpectedly difficult.

  • 6 devlogs
  • 28h
  • 18.96x multiplier
  • 499 Stardust
Try project → See source code →
Open comments for this post

3h 12m 10s logged

I wrote the README and also fixed a minor performance bug.

Because Prism code editor only initializes once Svelte finishes hydrating, there’s a delay of a few hundred milliseconds between when the page becomes visible and when the editor initializes. This caused a layout shift on each puzzle page, which was making Lighthouse take away a few points in the performance category. So I precalculated the height of each puzzle editor in advance and applied that minimum height to the placeholder text. This fixed the layout shift, so now Lighthouse gives the site perfect 100s in performance, best practices, and SEO, which is cool.

0
0
14
Open comments for this post

47m 39s logged

I just added some error handling for infinite loops and infinite recursion.

Before, if you wrote while (true) {} in the editor and pressed run, it would permanently lock up the UI and crash the browser tab. Now the logic test just interrupts the execution after 1000ms and fails your code for taking too long.

Likewise, if you wrote const r=()=>r();r(); and ran it, QuickJS would silently throw an uncaught error and the logic test would be stuck at “Waiting…” forever. Now it just instantly fails the code because it recurses too deeply and QuickJS can’t execute it.

I’m probably going to ship No Let soon, unless I have more puzzle ideas, find more bugs to patch, or think of more features to add.

0
0
5
Open comments for this post

3h 29m 25s logged

I spent the last 3.5 hours making a single puzzle. It’s the hardest puzzle yet and took the most time to create, and by a lot.

The puzzle is called Headcount, and it involves extracting a total count from a deeply-nested data object. I considered using nested arrays instead, but that would have a pretty trivial solution: return input.flat(Infinity).length. JS has far fewer built-in utilities for manipulating objects than it does for arrays, so I figured that using objects would pose more of a challenge, which I think it does.

You can play the new puzzle here: https://ethmarks.github.io/nolet/headcount.

0
0
8
Open comments for this post

1h 56m 42s logged

I added more puzzles and wrote a congrats page for users who finish the whole site.

The congrats page finally gave me the excuse to reference xkcd 1312, which I’d been dying to do since I started this project.

Next, I just need to make more puzzles. I have 4 so far, which I don’t think is nearly enough. Puzzle design is really hard though.

0
0
5
Open comments for this post

11h 27m 53s logged

I’ve made a lot of progress since my last devlog. I’d say that No Let is basically feature-complete now. All that’s left to do is adding polish and creating a bunch more puzzles.

You can try No Let right now at https://ethmarks.github.io/nolet/.

Here are some of the highlights of the changes in this devlog.

  • I added the Output.svelte component that runs the logic test and the linter and outputs their results into a human-readable HTML list. I also made it use Svelte’s slide transition, which required a lot of refactoring.
  • I made each puzzle a separate page. I was originally planning on making the site an SPA, but I decided that a MPA was probably a better fit. Because the puzzles are defined as classes and not as separate Svelte routes, I had to add a dynamic route. I’m using SvelteKit’s static adapter because I prefer static sites, but that meant that I had to tell SvelteKit which pages to prerender.
  • I added description text and suggested solutions for each puzzle. The descriptions provide instructions, tips, and flavor text, and the solutions should keep users from getting stuck or frustrated.

But most of the work I did has been refactors, fixes, and creating new puzzles.

0
0
6
Open comments for this post

6h 54m 25s logged

So my idea for this project is that it’s a JavaScript puzzle site which forces you to use pure functional programming, which means that you aren’t allowed to use let or anything else with mutable state.

Basically, pure functional programming says that you should never ever reassign variables after you declare them. Ever. Because you can’t reassign variables, you also can’t increment counters, which means that it’s impossible to use for loops. The same logic applies to while loops, and to a few other things. These extremely restrictive self-imposed limitations force you to do things the functional programming way, which involves lambda calculus, recursive functions, currying, etc.

I think that this project will have four main parts. I’ve been working on it for about 7 hours and I’ve made some good progress, but there’s still a lot to do.

  1. Running the user’s code and reading the result. I can just wrap quickjs-emscripten and remove a few built-in methods like Math.random() that are considered “impure” by functional programming because they’re non-deterministic.
  2. Linting the user’s code to check if it uses any banned syntax like let. I can use acornjs to parse the code into an AST, then applying a bunch of custom rules to it.
  3. Allowing the user to write their code. The conventional choice would be to use Monaco or CodeMirror, but they’re extremely heavy and I don’t like VSCode anyways, so I’m going with Prism code editor, which is much lighter and in my opinion nicer.
  4. Having puzzles for the user to complete. Each puzzle should have a test function that can check if the code logic is correct, and also should have some initial code that has correct logic but fails the linting because it uses let and whatnot.

Right now I have minimal versions of parts 1, 2, and 3. They do work (mostly), but they’re missing features and don’t integrate well with each other.

1
0
10

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…