-
Notifications
You must be signed in to change notification settings - Fork 1.3k
JavaScript rendering target #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
CC @lmorchard who is writing a pretty complex one in JS |
Yes, this is a good discussion to have -- what are our available options?
We should pick a method and stick with it for all the JS implementations |
I guess option 3 is command line scripting via node (example https://nodejs.org/api/readline.html#readline_rl_question_query_options_callback). Though I recognize that won't be vanilla JS, reading user input via node standard lib. |
FWIW, this is how I've been doing it for Super Star Trek:
Kind of hacked together, but seems to be working decently so far |
Stating the obvious, but if we settled on a common setup for this sort of thing, it wouldn't be too hard to establish a project-wide web-based runner |
Personally, as someone who grew up copying BASIC programs out of magazines and is now a full-time javascript developer, I think the best bet would be option 1 from Jeff's list above. It's closest to the original experience of writing and using BASIC, AND easiest for a brand new user to access. Getting a new user to the point that they can take user input in a Node script is a very different thing (including importing standard library features, callbacks and/or promises, etc.) from using Window.prompt(). Also, the spirit (as I understand it) of this project is to re-implement the games in modern contexts. The examples I'm seeing so far of javascript ports with print(), tab(), input() functions look more like ports than re-implementations. I would think rewriting parts of the BASIC standard library in javascript so that the original source code requires less re-writing doesn't help new users of javascript learn how to think about programming. Am I thinking of this the wrong way? |
Agree. It would be an entirely different, fun, thing to write a BASIC interpreter in all these languages so it can just run the original game....... but that's not what this repo is about. So a straight-up port of |
I am sure we will be doing a lot of refactoring along the way as we go. It is a goal to use all the modern features of the languages to make the code more readable and easier to follow. We're not striving for cleverness, but rather clarity, and "teachability". Is it good, clear code? |
FWIW, the bits I did aren't a BASIC standard library so much as a very minimal interface to work with web vs CLI driver scripts
Personally, I wouldn't want to re-implement everything from scratch. I might be a glutton for punishment, but I started tinkering with Super Star Trek as a literal conversion from the BASIC in order to make sure I at least understood the original. From there, I've kept a few things basically the same - e.g. the original used string manipulation to maintain both the data model and presentation of the current sector in space. I thought it was interesting, so I kept that in JS rather than change to something else like an array. But, there was a fairly complex tangle of code to calculate distance & direction that I couldn't quite make clean without GOTO. So, I just changed that to use Might be nostalgia speaking, but I think it could be interesting to keep a mix of the original flavor with some modernizations. |
@lmorchard I think that conversion to Math.atan2 is a great example. I think you made the right decision there. And like Jeff said, choosing simplicity over cleverness seems like the right approach. My main question was whether we were thinking of this as an exercise in porting or re-writing, the former being totally compatible with re-creating parts of BASIC in javascript, the latter leaning toward substituting modern approaches or the target platform's standard library (like Math in javascript). Certainly not trying to be negative about anyone's work so far, but aiming for constructive criticism. |
I think that's the general approach we want, to use the modern features of modern languages. We definitely aren't looking to emulate BASIC. |
I like the idea of using NodeJS. At least should it not be excluded. Although a little more than just Window.prompt is required to read from stdin, its still very easy todo (see #171). The current browser based javascript implementations emulate a terminal prompt via html / css, which is far more verbose in my opinion, and misses the chance to reduce the code to its functional minimum. |
I think the project should reach the widest possible audience, so working directly in browser is the best solution yet. Also my current input/output solution works both in computers and cellphones. (see second rule: "...strive to replicate the command line / console output and behavior illustrated in the original book. ") I'm having a crash with third rule "Please DO update for modern coding conventions. Support uppercase and lowercase. Use structured programming. Use subroutines. Try to be an example of good, modern coding practices!" because we need to be aware that the original programs weren't exactly an example of structured programming. Even for BASIC standards most programs are terribly ugly! So far my current approach is this:
When the programs are ported, more people should make another pass that will take even more time:
Only the rule 2 from guidelines has prevented me from going text to full graphics XD |
Gee... that remembers me that: "Any application that can be written in JavaScript, will eventually be written in JavaScript." |
FWIW @nanochess With the // Determine if code is running in browser;
// by default there is no window object in Node.js.
const isRunningInBrowser = typeof window !== 'undefined'; And then a simple if enables both browser and Node.js function print(string) {
if (isRunningInBrowser) {
// Adds trailing newline to match console.log behavior
document
.getElementById('output')
.appendChild(document.createTextNode(string + '\n'));
} else {
console.log(string);
}
}
function input() {
if (isRunningInBrowser) {
// Accept input from the browser DOM input
return new Promise(function (resolve) {
let input_element = document.createElement('INPUT');
input_element.setAttribute('type', 'text');
input_element.setAttribute('length', '50');
document.getElementById('output').appendChild(input_element);
input_element.focus();
let input_str = undefined;
input_element.addEventListener('keydown', function (event) {
if (event.code === 'Enter') {
input_str = input_element.value;
document
.getElementById('output')
.removeChild(input_element);
print(input_str);
print('');
resolve(input_str);
}
});
});
} else {
// Accept input from the command line in Node.js
// See: https://nodejs.dev/learn/accept-input-from-the-command-line-in-nodejs
return new Promise(function (resolve) {
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout,
});
readline.question('', function (input) {
resolve(input);
readline.close();
});
});
}
} As console.log comes with newlines, I changed function printInline(string) {
if (isRunningInBrowser) {
document
.getElementById('output')
.appendChild(document.createTextNode(string));
} else {
process.stdout.write(string);
}
} As I’m writing this I realize I could have just used process.stdout.write in |
I really like the style of the input/print functions I found in Acey Ducey. I rewrote them a bit to use modern JS idioms in #332, and factored them into their own module. But the overall style of preserving a "terminal-like" experience in the browser is very nice. |
Something worth considering with modules is—as of current—if you try to load the HTML file locally (i.e. with a file:// URL), you'll run into CORS errors due to JavaScript module security requirements. You need to do your testing through a server. From an instruction standpoint, the reveal of “just double-click the HTML file” seems quite appealing. |
I also think the "javascript" implementation should target node (command line) as a default. That would keep the code simpler (no DOM handling) and we could have one singel implementation for node and the browser. |
Is anything in here helpful? https://github.com/coding-horror/basic-computer-games/tree/main/00_Common |
With #649 I've added a very basic example (without input) as an example on how this could look like. The javascript part is implemented as a node.js script. Together with a very simple polyfill for |
There is also this https://troypress.com/wp-content/uploads/user/js-basic/index.html |
Just a side note as I haven't seen it in this discussion: I absolutely love the Github Page which is generated: |
Yes, we have a decent solution now, closing this. |
With #687 we move to node.js as main target! lacagy HTML Version: node.js version & terminal emuilator: |
This looks amazing ❤️ Small note : on my android phone the new version is not usable as it doesn't show a keyboard. The old version did |
More a question than an Issue - do we have opinions on the rendering target (and template for it) of JavaScript implementations?
I saw a few solutions in here that appear to render text into the browser on a simple HTML page (example https://github.com/coding-horror/basic-computer-games/blob/main/73%20Reverse/javascript/reverse.js#L8 ).
Conversely the language selection process (https://discourse.codinghorror.com/t/updating-101-basic-computer-games-for-2021/7927/34) included the determination if a language is "scripting appropriate" by "running on the command line", which is true for JS, if you run it against
#!/usr/bin/env node
.So I am thinking either
a) don't render it into the browser, but write ES6 for the command line OR
b) we come up with some sort of template for how interacting with the browser should work.
Thoughts?
The text was updated successfully, but these errors were encountered: