Javascript - Creating constructor class within object literal - javascript

I'm creating a tic-tac-toe game in Javascript for an online course. I'm trying to set up various properties within an object literal I'm calling "Game". However, I know that when I start writing the AI functions, I will need to create several instances of a state class that holds board state, score & player info. My question is - how do I create a constructor like this from within my Game object? As an example:
var Game = {
board: [0, 1, 2,
3, 4, 5,
6, 7, 8],
// 0 = Empty, 1 = X, 2 = O
boardState: [0, 0, 0,
0, 0, 0,
0, 0, 0],
empty: this.availableMoves(this.board),
// either "human" or "AI"
whoseTurn: "",
// etc.. other initial properties...
//
//
state: {
turn : this.startingPlayer,
boardState: this.boardState,
value: 0
}
}
As I understand it right now, "state" is just an object literal within Game that holds static values for the current state of the board. If I wanted to create new instances of state for the purposes of iterating through possible states, though, how might I go about doing that without affecting the current state? Something like:
function changeState(state){
var state1 = new state();
// edit state1 object without affecting current state.
}
I was originally thinking of creating an entirely different "State" object for this outside of "Game", but to me that didn't seem to be the right way of going about it since states are part of the game. Any advice would be appreciated!

Related

Javascript Map does not contain array of numbers as key

I'm trying to create a map based on certain arrays of three. For example,
const rule30Map = new Map();
rule30Map.set([1, 0, 0], 1);
rule30Map.set([0, 1, 1], 1);
rule30Map.set([0, 1, 0], 1);
rule30Map.set([0, 0, 1], 1);
When I try getting a value based on values in an array, the console returns undefined,
console.log(rule30Map.get([1, 0, 0])); // prints undefined
but the expected output would be 1. Can somebody explain why my logic was misunderstood?
The keys are compared with === comparison. Two separate arrays that look like [1, 0, 0] are still two separate arrays that are not equal to each other.
Working out some automated way of keeping track of key objects by their characteristics somehow would probably be more complicated than using a plain object for storage. Because JavaScript does not provide a generic way for a class of objects to supply hashing and comparison overrides means that Map and Set in JavaScript are somewhat limited in usefulness.
You could do:
const a = [1,0,0];
const map = new Map();
map.set(a.toString(), "value");
map.get([1,0,0].toString());
I assume you are computing the [1,0,0] part.

Recursive Reduce method in ES6 / Immutable

Hope this isn't too difficult a question without context, but here goes nothing. So, I inherited this code from someone, and I can't seem to get it to work!
We're making a Go game. We want to scan a set of pieces on the board and see if they're empty or not. An empty square is called a 'liberty'. Now, at the bottom of the function there we're creating a new 2D array 'visitedBoard' that keeps track of where we've scanned so far.
PROBLEM, the current implementation allows for liberties to be scanned twice! It only seems to be marking something as 'visited' in the board when it is either empty or another color (0), not when it's 1.
BTW, at the bottom - we're iterating through neighbors, which is a 4 item array of objects {row: 2, col: 3} and then recursively running it through this function.
Any assistance is helpful. I'm new to this functional / immutable business.
const getLiberties = function (board, point, color) {
if (board.get(point.row).get(point.col) === C.VISITED) {
return 0; // we already counted this point
} else if (board.get(point.row).get(point.col) === C.EMPTY) {
return 1; // point is a liberty
} else if (board.get(point.row).get(point.col) !== color) {
return 0; // point has an opposing stone in it
}
const neighbours = getNeighbours(board, point)
const visitedBoard = board.setIn([point.row, point.col], C.VISITED)
return neighbours.reduce(
(liberties, neighbour) => liberties + getLiberties(visitedBoard,
neighbour, color), 0)}
instead of .get(point.row).get(point.col) you can use .getIn([point.row, point.col])
inside reduce you always use same visitedBoard for all calls. You have to re-assign new value to variable after reduce callback call

Maintenance: Assigning numbers to constants

Consider the following constants I have in my app:
const Actions = {
SONGS_CHANGED: 0,
PREVIEW_TAG_CHANGES: 1,
END_PREVIEW: 2,
SAVE_TAGS: 3,
PATTERNS_UPDATED: 4,
PATTERN_MAPPED: 5,
PATTERN_UNMAPPED: 6,
CHANGE_NUMBER_OF_PARENT_DIRECTORIES: 7,
}
I'm trying to keep these grouped together. But that means if I add one to the first group, then I have to update the numbers for everything below it. Well, obviously I don't have to, I could always just assign it the next higher number (e.g. give the next constant a value of 8 regardless of which "group" I put it in). But as the quantity of constants increases, it will become harder to identify the highest number in order to know what the next one should be.
In python, using something like range() to just generate numbers for the constants removes this issue entirely. What's a good JavaScript approach?
If you really do want to just number them in the order defined, you can use an incrementing variable to do so:
var x = 0;
const Actions = {
SONGS_CHANGED: x++,
PREVIEW_TAG_CHANGES: x++,
END_PREVIEW: x++,
SAVE_TAGS: x++,
PATTERNS_UPDATED: x++,
PATTERN_MAPPED: x++,
PATTERN_UNMAPPED: x++,
CHANGE_NUMBER_OF_PARENT_DIRECTORIES: x++,
}
console.log(Actions.END_PREVIEW); //2
console.log(Actions.SAVE_TAGS); //3
Note that changing constants in this fashion should only be used if the only place these numbers are used is by referencing the constants - if you're storing them elsewhere etc then changing them will break existing stored data. The choice comes down to whether they're just constant at runtime, or should be permanently constant.
If you know (or can estimate) a priori how big each group will ever be then you can use different subranges of numbers like this:
const Actions = {
SONGS_CHANGED: 0,
PREVIEW_TAG_CHANGES: 1,
END_PREVIEW: 2,
SAVE_TAGS: 3,
PATTERNS_UPDATED: 10,
PATTERN_MAPPED: 11,
PATTERN_UNMAPPED: 12,
CHANGE_NUMBER_OF_PARENT_DIRECTORIES: 50,
}
The advantage over James Thorpe's solution is that it is backwards compatible, i.e. you don't modify previously defined values ever.
A completely different approach that may or may not be suitable depending on what values your constants can take, but if they could be strings, for instance, you could use a GUID based approach:
const Actions = {
SONGS_CHANGED: '4e6c355f-d684-4544-8320-529f20c89ce7',
PREVIEW_TAG_CHANGES: '39a34b2b-0467-46f9-9d21-f407f89ae3c7',
END_PREVIEW: '350e1d61-e6f9-4cc5-9364-bbdc14fd7063',
SAVE_TAGS: '32e85a98-e13c-480c-9449-0a5bec7ec13c',
PATTERNS_UPDATED: '16536175-e421-40d9-9d5d-962bcd0f0771',
PATTERN_MAPPED: '0fd2bbd8-91f4-413b-8010-736bcacd1d88',
PATTERN_UNMAPPED: 'b946d566-d951-4695-a0ce-56b0bf987eb6',
CHANGE_NUMBER_OF_PARENT_DIRECTORIES: '5b0736f5-e5e9-48f3-a9a1-bed8d0882beb',
}
You can then add new constants anywhere without worrying about changing existing values, or needing to know roughly how many you may need in the future. There are plenty of ways of generating GUIDs, such as this online tool.

Don't understand train data from convnetjs

I'm trying to predict some data using a neural network in javascript. For that I found convnetjs that seems easy to use.
In the example, they use one thing that they call MagicNet, so you don't need to know about NN to work with it. This is the example of use:
// toy data: two data points, one of class 0 and other of class 1
var train_data = [new convnetjs.Vol([1.3, 0.5]), new convnetjs.Vol([0.1, 0.7])];
var train_labels = [0, 1];
// create a magic net
var magicNet = new convnetjs.MagicNet(train_data, train_labels);
magicNet.onFinishBatch(finishedBatch); // set a callback a finished evaluation of a batch of networks
// start training MagicNet. Every call trains all candidates in current batch on one example
setInterval(function(){ magicNet.step() }, 0});
// once at least one batch of candidates is evaluated on all folds we can do prediction!
function finishedBatch() {
// prediction example. xout is Vol of scores
// there is also predict_soft(), which returns the full score volume for all labels
var some_test_vol = new convnetjs.Vol([0.1, 0.2]);
var predicted_label = magicNet.predict(some_test_vol);
}
What I don't understand is this:
They create train data like [new convnetjs.Vol([1.3, 0.5]), new convnetjs.Vol([0.1, 0.7])] and then use 2 labels. Those labels, are one for each position of array or for each element of subarray in those positions??
Here is a visual example:
It's like [new 0, new 1] or like [new convnetjs.Vol([0, 1]), new convnetjs.Vol([0, 1])]?
The sample new convnetjs.Vol([1.3, 0.5]) has label 0.
The sample new convnetjs.Vol([0.1, 0.7]) has label 1.
In general, in machine learning, you'd usually have samples which can be quite high-dimensional (here they are only two-dimensional), but you'd have a single label per sample which tells you which "class" it belongs in. What the classes actually mean depends on the problem you are trying to solve; for instance, they could be the digits that are represented by images of hand-written digits.

Javascript array of canvas objects? Scope issue? ocanvas.js

I'm new to javascript and canvas, but not entirely new to programming (I have some HTML/PHP experience).
I've always had an interest in web games that use grids, so after taking a few javascript courses online, I found some javascript code that dynamically created hexagonal grids of canvas objects.
I've been playing around with the code, adding click events to highlight the hex you're on, trying to put random numbers on the hexes to depict numbers of "units" etc. Sort of mocking up what a game might look like, just for the learning experience.
One thing that I've been trying to do, and I can't seem to figure out, is how to define canvas objects in an array, so that I can reference them by row/column. It seems like it would be much easier, in the context of a game, to reference a grid cell by row/column so that you can do actions based on that location.
I'm using ocanvas.js to create canvas objects, so ideally I'd love to be able to define a grid cell as:
hex[row][col] = canvas.display.polygon({
x: x0,
y: y0,
sides: 6,
radius: this.radius,
rotation: 0,
fill: fillColor,
stroke: "outside 1px #000",
row: row,
col: col,
zIndex: "back",
selected: false
});
hex[row][col].add();
However, I've noticed that mutlidimensional arrays don't work in javascript like they do in PHP. In PHP, you don't have to predefine the scope of an array. You can just do:
$array = [];
$array[1][5] = "foo";
And it'll put that value in the [1][5] position. In my hex code here: http://tny.cz/14282e49 about 3/4 down I have a comment showing that I want to call my hex[col][row] object... but I'm always getting "Uncaught TypeError: Cannot read property '5' of undefined" errors, where '5' is the column its trying to access.
So, this is a 2 part question:
1) Am I not defining my hex array correctly to access the canvas objects like that?
2) Is there a better way that I'm just not seeing, to access specific canvas objects in a column/row grid format?
Part I:
Before assigning a value to hex[row][col], you need to make sure that hex[row] exists.
hex[row] = hex[row] || [];
hex[row][col] = canvas.display.polygon({
x: x0,
y: y0,
sides: 6,
radius: this.radius,
rotation: 0,
fill: fillColor,
stroke: "outside 1px #000",
row: row,
col: col,
zIndex: "back",
selected: false
});
hex[row][col].add();
The line hex[row] = hex[row] || []; says "if hex[row] exists, use it. otherwise create a new array. Assign the result to hex[row]."
The || "or" operator is used as a "default" here. See this page as a reference: http://seanmonstar.com/post/707078771/guard-and-default-operators
Part II:
http://www.redblobgames.com/grids/hexagons/#coordinates
I recommend using the "axial coordinate" system used at that resource. Read the entire thing. It's a long post and is way too much information for a SO answer here.

Categories