I was wondering how a quick random player might fare so I made a simple one. Paste this into your inspector console (or in chrome type "javascript:" into the URL bar and paste it):
My background seems to be significantly different from most people here - what you've written there is something I'd like to learn about, but have no idea where to start.
I've copied your code, hit "F12" in Firefox, but where do I paste it? Where/how does it run?
How can I learn the basics of this stuff without wading through the mindless tutorials intended for people who have never coded?
For reference, I've written safety-critical real-time embedded systems in assembler and C, and these days I write number-theory and expert systems code in Python.
Where can I start that doesn't patronise me to death?
I'm a non-programmer [I've only made programs in BASIC, Fortran, C, C++, assembler, smalltalk, javascript, BASH, probably a couple I forgot (does Maple count), and most recently python (lol - I mean to say my level is 'interested amateur')] but I found this [1] quite a nice reintroduction to javascript the other day.
It gives a good review of javascript syntax, goes over the intricacies of the loose typing system and variable scope, covers some detail on avoiding memory leaks and some browser specifics (which I think are probably out of date; I didn't review it thoroughly I was playing Minecraft at the time) and gets up to anonymous functions and closures.
Aside: Incidentally if someone would like to explain closures to me I'd appreciate it - I don't really understand them.
Code Academy's [2] javascript looks very basic but Code School [3] seems to have better beginner stuff - I've done their git/jQuery courses before and they were quite well done.
As an old joke (a ha-ha only serious joke) goes, closures are a poor man's object orientation, and object orientation is a poor man's closure. Going on the list of languages you have above I'll take it from the object orientation side of the argument. Object orientation works by binding functions to data; the data is persistent for this instance of the object (in the sense that the data remains available as long as the object does) and can be manipulated by the functions bound to that data. Closures on the other hand bind data to functions; so the function is always callable but the data is bound to this instance of the function. So you can have many instances of a function each with it's own data bound to it. In most languages that support closures functions are considered a "first class" data type; i.e. individual functions (and the data bound to them) can be passed just like variables (sometimes with caveats depending on the implementation). Typically this comes hand in hand with "anonymous" functions; functions that don't have an entry in the symbol table, i.e. they don't have a name in the function / object namespace.
If you truly want to understand how it works then you'd probably want to write a compiler that supports closures; you'd then need to cover issues like how to allocate functions on the heap, the difference between locally allocated (typically on the stack) data bound to functions and globally allocated (typically on the heap) data bound to functions.
The second part to closures is understanding the theory, or the why and the high level functionality that it enables, such as callbacks with state or interactions with the likes of recursive (y-combinator like) functions.
Am I correct in my understanding that with a closure, it is one or more data bound to one function, while with object orientation, one or more functions are bound to one or more data?
A singular closure is 1+ data bound to an entity (function). A singular object is multiple data/functions bound to one entity (object).
In the link above there are examples of either generating multiple closures tied to the same set of data (like tel's example), and also examples of having a singular closure that takes as a first parameter a "method" name and branching based on that. Using either solution you have an OO system using closures as your basis.
Closure is a function that "remembers" all variables that were in scope at the place where that function was created. It can then use these variables (as if they were global variables), even if they are outside of the scope when the function is invoked.
These variables also won't get garbage collected because of that.
This feature is most useful when you create anonymous functions that you pass around.
Example:
function foo() {
var localVariable = 3;
return (function () { // this anonymous function can reference localVariable because it is a closure and remembers outside scope
localVariable++;
alert(localVariable);
})
}
var increase = foo(); //foo returns freshly created anonymous function that we assign to local variable "increase".
//foo also created local variable "localVariable"
//and it went out of scope when foo returned,
//but that variable won't be GC-ed as long we keep reference to "increase",
//because increase has that "localVariable" in scope
increase() // we call that variable - it executes that functions and writes 4
function bar() {
var localVariable = 100; //this is different variable with the same name
increase(); //bar can reference increase because bar is a closure, so it remembers outside scope
}
bar(); // writes 5
increase(); //writes 6
var increase2 = foo(); // this creates another function and another localVariable
increase2(); //writes 4
increase(); //writes 7
It's useful for similar things as objects in OO programming (grouping data with code), but encourages different approach to this.
Closures also make functional code with passing functions bearable - without it you would have to explicitly pass variables from scope to each function, or to depend on dynamic scope, so your functions would use different variables depending where they are called.
> These variables also won't get garbage collected because of that.
I should probably be more precise - only the variables from outside scope that the closure actually uses won't get GCed as long as that closure is referenced. Other variables will.
Closures are one implementation of functions. In a language which also has mutable variables, closures create a special kind of private variable behavior.
You're used to thinking of functions which act on things passed into them via their parameters. For instance:
function apply(f, x) { return f(x); }
My example, apply, is a bit unique in that it only uses things passed in through the parameters. More normally, you might also use names of things available in the scope when you define the function, for instance:
function log(x) { console.log(x); }
In this example, the behavior of add depends not only on the parameter x but also the fact that console.log is defined ambiently.
What a closure refers to is the fact that functions can capture names which are only ever available locally thus hiding a reference inside of them. A simple example might be:
function makeExample() {
var exampleText = "Hello world";
return function printer() {
console.log(exampleText);
}
}
var myPrinter = makeExample();
printer();
// Hello world
In this case, the variable `exampleText` is clearly being captured in the definition of `printer`, but since `exampleText` is only defined in the scope of `makeExample`, we have no way of accessing it. The function stored at `myPrinter` has closed over its own copy of `exampleText` can uses it internally in a way we cannot access.
So finally we can turn to the more interesting examples where we combine this closure/capture property with mutability. The canonical example is the counter:
function makeCounter() {
var count = 0;
return {
get: function get() { return count; },
inc: function inc() { count += 1; },
dec: function dec() { count -= 1; }
}
}
var myCounter = makeCounter();
var get = myCounter.get;
var inc = myCounter.inc;
var dec = myCounter.dec;
assert(get() === 0);
inc();
assert(get() === 1);
dec();
assert(get() === 0);
Here, `makeCounter` returns a struct of functions which have all independently captured a reference to the same hidden variable `count`. While I return them all together in an object, I also destructure that object to stress that there's nothing funny going on—the three functions have to be created together to capture the same `count` variable, but afterward they can be separated far and wide.
Since all three functions reference the same hidden variable state they can manipulate it together. This is the magic of variable capture under mutable state: closures.
---
So what's the point?
Well, we've essentially created a private mutable variable on a home-grown object system. There is no way for someone to access the secret `count` reference except via the get/inc/dec functions which have closed over it. This can be very valuable for data encapsulation.
To skip to the punch, Javascript only has a reasonable module system because of closures. If you're familiar with the IIFE-based modules of Javascript they go a little like this
exports = {};
(function(exports) {
var count = 0;
function inc() { count += 1 };
function dec() { count -= 1 };
// With only this function and not `get` exported we can never
// actually view the value of count. This can be very useful
// for implementation hiding and building a minimal API.
function isEven() { return count % 2 == 0 };
exports = { inc: inc, dec: dec, isEven: isEven };
})(exports)
Here we see that the IIFE creates a private, local scope where names like `count` can be created and closed over by exported functions like `inc`, `dec`, and `isEven`. This public/private API building is the core of module creation and, ultimately, it rests upon the creation of closures.
in the console window of the browser tools in chrome or firefox. https://developer.chrome.com/devtools#console note: javascript always runs in the context of a root object. in the browser, it's the window object. if the webpage has multiple frames, you might have to select the correct frame for the console to execute the js in.
This is pretty great - it scored 16 for me on the first go which is higher than my own first attempt of 14.
This script also highlights my main issue with the game. It feels like the rules are not strict enough for this style of game. The real-time nature of the physics combined with the concurrent actions taken by the user results in quite loose game mechanics.
If it wasn't so late I might get into it but I think this could be dramatically improved by just detecting whether a piece is currently underneath another piece. Assuming you can eliminate those as possible choices for the random select process, you would avoid the issue of iterating through a bunch of pieces that can't even be moved during the late game!
Yeah, that would probably help a lot. It is pretty dumb in its current state. That said, sometimes it can join matching tiles that are next to each other in the bottom of the pile, so that can still be useful.
If this was able to achieve any arbitrary number score or even if it was able to consecutively hit scores beyond what a decent player could get, I would agree. But just because playing random works somewhat doesn't make it bad. I'm sure there are new players who would lose in Go to a computer that only placed pieces randomly in valid positions. But with a little skill, another player (or designed algorithm) should be able to almost always beat such the random algorithm.
Yes, of course, in the sense that it is not the best game possible. But it is much less bad than this game. Look at what a Chess AI does and look at this AI.
The highest I've seen it manage is 17.