Giter Site home page Giter Site logo

vages / svelte-snake-workshop Goto Github PK

View Code? Open in Web Editor NEW
13.0 3.0 12.0 4.24 MB

A workshop that teaches Svelte and SvelteKit through making the classic game Snake

Home Page: https://svelte-snake-workshop.vercel.app

License: MIT License

JavaScript 3.22% HTML 0.37% Svelte 96.41%
snake-game svelte vercel workshop

svelte-snake-workshop's Introduction

svelte-snake-workshop's People

Contributors

98mux avatar arve0 avatar bredeyabo avatar goplen avatar vages avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

svelte-snake-workshop's Issues

Make headDirectionQueue a part of the regular tasks

8e20ea9 introduced the variable headDirectionQueue to src/App.svelte, making it simpler for the user to perform sharp turns. This is a usability improvement, but I'm not sure if it should be part of the regular tasks or some later task.

If it is to be introduced at some pre-existing point, it either has to be introduced at task 2.2 or at task 3.5. Otherwise, we could either make a completely new task for this or leave it out altogether.

My hunch is that introducing it at 2.2 will feel premature to most workshop participants. The task currently instructs the user to disregard the possibility of the snake eating itself, and I think that it's smart to introduce as little as possible to the user at once. Task 3.5 is in my opinion a good stepping stone to understanding the need for queuing itself. This makes me think that adding a new task, for example 3.6, is the best solution.

Use an object to keep track of the state instead of multiple variables

Because svelte can react to assignments within an object as well as to an object itself, perhaps it's best to replace this monstrosity with an object:

  // Letting the state variables go uninitialized is safe,
  // because they are initialized by resetGame before they are ever read
  let apple;
  let gameState;
  let headDirection;
  let headDirectionQueue;
  let score;
  let snake;
  let willGrow;

  function resetGame() {
    const initialSnake = [
      { x: 4, y: 4 },
      { x: 4, y: 3 },
      { x: 4, y: 2 },
    ];
    apple = drawRandomOpenSpace(BOARD_DIMENSIONS, initialSnake);
    gameState = GAME_STATES.START_SCREEN;
    headDirection = DIRECTION.SOUTH;
    headDirectionQueue = [];
    score = 0;
    snake = initialSnake;
    willGrow = false;
  }

Polish the tasks

The tasks currently make some assumptions that I'm not satisfied with.

Other than that, the entire document could do with some more polish, with almost two years in existence.

My current plan is to do this after #5 and before #4

Use tabs instead of spaces for indentation

This blog post changed my mind in the age-old tabs vs. spaces debate: https://adamtuttle.codes/blog/2021/tabs-vs-spaces-its-an-accessibility-issue/

People with less than perfect eyesight can have trouble differentiating indentation when the tab-width is low. For accessibility reasons, we need to be able to see more space. And the more code we're looking at, the more it's needed. Having to scroll down 14 lines of code and keep 6 levels of indentation aligned by eye is so much easier with a wider tab-width.
https://adamtuttle.codes/blog/2021/tabs-vs-spaces-its-an-accessibility-issue/

Also:

The main reason I would like to see this change is for refreshable braille displays that are used by blind programmers a lot. Each space wastes one braille cell and takes away valuable braille realestate. So if the default indentation of a project is 4 spaces per level, a 3rd level indentation wastes 12 braaille cells before code starts. On a 40 cell display, which is the most commonly used with notebooks, this is more than a quarter of the available cells wasted with no information. If each indentation level was represented by only one tab character, there would be three cells occupied by a tab character each, and on the 4th cell, the code would start. That's less than 10 percent occupied on the same length display, but all cells contain valuable information that is easily discoverable and immediately comprehensible.
prettier/prettier#7475 (comment)

Let's just do it.

Use folders instead of branches

Having each task in a separate folder (instead of a separate branch) should make the workshop easier for participants. I would probably have an easier time maintaining the workshop, too. If participants find a problem with the code in a task, it's easier for them to suggest changes.

Cons with the current approach

Less experienced participants spend a lot of time fiddling with git

The workshop currently requires the participants to know some git. This has especially been a problem when performing the workshop with students, some of whom are in their first year. Most of the actual help required has been related to performing

The git structure is too cumbersome

Introducing changes takes time

Currently, the project is structured so that each task is a separate branch. The finished game is found in the main branch. When I first made the workshop, I started with the solution to the last task working my way back to the first task. As a consequence, the branches build backwards, like this: task-5.3-end, task-5.3-begin and so on through task-1.1-begin. While simple to start with, introducing changes is cumbersome, as you can see from the long command I use for introducing changes.

It's hard to look at the history

Just look at this branch structure. The git GUI in Webstorm can't even.

Screenshot of the git GUI in Webstorm, showing a clusterfuck of branches

I have never had to git-revert any mistakes, but I imagine that doing so would be a nightmare compared to working with a single branch.

The git structure makes it hard to change folders

Because of the advanced git structure, it's hard for outsiders to suggest changes to branches other than the main branch.

Cons with the future approach

Harder to apply changes to several tasks at once

Most changes need to be applied to one or more tasks. While the current approach has its limitations, it's actually quite quick, as long as no merge conflicts appear.

I currently do not know I would apply changes that apply to several tasks as quickly. My guess is that I would have to create some script to create and apply patches semi-automatically to predecing/succeeding tasks, stopping to solve merge-conflicts.

Move CSS variables to board

During work on #25, I noticed that the CSS variables could just as well be applied to the div that represents the board.

That seems a lot cleaner, and it could pave the way for #28.

Remove mentions of the repository

There is still a mention of "Start with the state of the repository". This should refer to the state of the game or the folder state or something.

Stop using the "game" folder

Using the game sub-folder made a lot of sense when we had to hide it from svelte-kit. We changed to the new routing system in da42931, and now it's just a bit confusing.

We could easily place the files on the same level as the +page.svelte file. Will have to rename the references, though.

Use svelte-kit in the workshop

It would be cool to show off some of svelte-kit's capabilities in the workshop. Perhaps we could make the pause and high score screens separate routes

This is a long term goal and not something that I'm going to attempt before issues 4 through 6 are resolved.

Start every sentence on new line in text files for smaller diff size in source and translation files

I read an interesting article earlier this year, Write HTML Right (also see the related discussion on Hacker News).
While I disagree with a lot of the author's points, I found this point to be insightful.

Starting each sentence in a paragraph on its own line (like back in the troff days) makes it easier to rearrange the sentences in a paragraph — something I do more often than I would have expected.
If you hard-wrap your text, starting each sentence on its own line also limits the area affected by edits within a sentence.
http://lofi.limo/blog/write-html-right

We could hopefully translate smaller chunks

I would not have cared too much for this, had it not been for the effect on the translation files.
Because we currently do not wrap lines within a paragraph, we have to translate each paragraph as one large chunk. See for example

#: TASKS.md:block 127 (paragraph)
msgid ""
"We have created the variable `headDirectionQueue`, an array that keeps track"
" of the directions the user has planned for the snake to move in. Instead of"
" changing `headDirection` when the user presses a key, you should append the"
" direction the user entered to `headDirectionQueue`. When it is time for the"
" snake to move, the app should use the first perpendicular direction in the "
"queue as the new value for `headDirection`. In other words: Remove all non-"
"perpendicular directions from the start of the queue until you find a "
"perpendicular direction. Use this element as the next `headDirection` and "
"let the subsequent queue entries remain as they are."
msgstr ""
"Vi har laget variabelen `headDirectionQueue`, et array som holder styr på "
"retningene brukeren har planlagt at slangen skal bevege seg i. I stedet for "
"å legge neste planlagte retning rett i `headDirection`, skal du legge "
"retningen sist i `headDirectionQueue`. Når tiden for at slangen skal bevege "
"seg er inne, skal programmet bruke *den første vinkelrette retningen* i køen"
" som ny verdi for `headDirection`. Med andre ord: Fjern alle ikke-"
"vinkelrette bevegelser fra starten av køen frem til du finner en vinkelrett "
"bevegelse. Bruk denne som neste `headDirection` og la påfølgende bevegelser "
"bli liggende i køen som de er."
md2po also hard-wraps the files after a given number of characters. All in all, this makes diffs unnecessarily large.

I am not sure how md2po behaves if you start each sentence on a new line. I hope it extracts each new line as a separate chunk. If not, I hope it can be configured to do so.

Fix folder references in .md files

Reading through the current version of the norwegian translation of the tasks, I discovered the text «Åpne filen src/routes/game/App.svelte.». This refers to the file structure before #12.

Use references that point to the current version.

Remove lint warnings that may give away the solution

Currently, we get the following warnings:

svelte-snake-workshop/src/routes/task-3.3/problem/+page.svelte
  3:3  error  'DIRECTION' is defined but never used  no-unused-vars
svelte-snake-workshop/src/routes/task-3.6/problem/+page.svelte
  27:6  error  'headDirectionQueue' is assigned a value but never used  no-unused-vars

I am not sure if these are to be considered spoilers, but they seem to give away the solution (at least partially).

Possible solution: Delete the imports and rewrite the tasks with hints.

Translate the tasks into English

Now that I am to hold the workshop at Javazone 2021, the tasks have to be available in English as well as the currently available Norwegian bokmål.

In order to minimize the work with maintaining the parallel translations, I want to use some automated tool to generate the markdown files. I hit upon a Stack Overflow thread about translating Markdown documentation files, and I found the tool mdpo. The answer was from 2017, but the tool was updated as recently as the day before I created this issue, so I'm guessing I can count upon it being maintained for the next few years. I am still open to other alternatives, but if no better alternative materializes, I'll go for mdpo.

After translation, the English version of the tasks will be the authoritative version. This makes contribution simpler for people who do not speak Norwegian.

Add file endings to all imports

I have changed my opinion about leaving file extensions out in imports.

import * as api from "$lib/api"; should be import * as api from "$lib/api.js";

EcmaScript Modules also require using file extensions, so why not just go with the times, eh? 🤷

There is probably some eslint rule that enforces this

Extract board as component

A lot of CSS goes into creating the board in every task. For instance, this long, identical of CSS is found in the +page.svelte in every task:

	.board {
		--border-width: var(--cell-size);
		width: calc(var(--board-size-x) * var(--cell-size));
		height: calc(var(--board-size-y) * var(--cell-size));

		position: relative;
		margin: var(--border-width);
		outline: var(--border-width) solid black;

		background-image: linear-gradient(
				45deg,
				var(--checker-color) 25%,
				transparent 25%
			),
			linear-gradient(-45deg, var(--checker-color) 25%, transparent 25%),
			linear-gradient(45deg, transparent 75%, var(--checker-color) 75%),
			linear-gradient(-45deg, transparent 75%, var(--checker-color) 75%);
		background-size: calc(var(--cell-size) * 2) calc(var(--cell-size) * 2);
		background-position: 0 0, 0 var(--cell-size),
			var(--cell-size) calc(-1 * var(--cell-size)),
			calc(-1 * var(--cell-size)) 0;
	}

A lot of this could possibly be helped by extracting the board as a separate component.
Perhaps the task of rendering the snake should be delegated this component as well.

It's important that whatever changes we introduce will be a natural extension of the the tasks' flow.
For instance, many of the early tasks are about placing the different components on the board using CSS.

Currently, components are introduced in part 5.
Perhaps we could introduce them earlier.

Find self-explanatory names for finished and unfinished tasks where the finished variant is sorted later in the alphabet

Working with #12, I grew dissatisfied with my task naming convention: begin and end.
The expressions require too much explanation.
And they simply sound bad.

I settled for working-area and solution. These expressions are the best-fitting I have yet thought of. Solution is self-explanatory. working-area conveys that this is where you should work.

There are two weaknesses with these names:

  1. The workshop participant may think that solution is where he/she is to program his/her solution in the solution (not so important)
  2. working-area comes later than solution in the alphabet. Because the tasks themselves are sorted chronologically in the downward direction, the sub-parts of the task should be sorted chronologically in the same direction.

To avoid problem two, I have prefixed the folders with 0 and 1, so that their chronology flows in the same direction as the tasks themselves.

image

That brings us to the title of this issue: Find self-explanatory names for finished and "unfinished" tasks where the finished variant is later in the alphabet. Any suggestions?

Development server stops serving meaningful content after branch changes

Changing branches while the development server (npm run dev) is running often results in the page going completely blank. Not even a total refresh or opening the tab in a private browser window fixes things.

To reproduce

  • In terminal A: git checkout task-1.3-begin && npm run dev
  • Open the development build by navigating to the development server address in a browser.
  • In terminal B: git checkout task-1.3-end
  • The development build should go blank in a few moments. You can try opening the development build in another browser, in a private window or somewhere else – it will be blank all the same. In Firefox (at the least), I get the following error in the console: "Uncaught SyntaxError: expected expression, got end of script", though I have not made further investigations.

New development servers seem to work completely when you start them – even in parallell with the running server. But nothing is able to get the server started before the branch change running again.

Make App.svelte the new +page.svelte

Right now, the only thing +page.svelte does is import App.svelte and mount it. I don't think this makes a lot of sense.

I think we could simply overwrite +page.svelte with the previous contents of App.svelte and be better off

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.