I’m struggling to find a good solution to a problem which asks for ALL paths which increase as you traverse a 2D array/matrix (rather than the classic ‘Longest Increasing Path’.
Here’s the question:
Definitions
• Path: a sequence of two or mere spaces for which ea. space is horizontally or vertically adjacent to the previous
• Increasing path: a path for which each space has a greater value than the previous space.
Example 1:
[
[5, 1],
[2, 7]
]
There are 4 Increasing paths.
1 -> 5
1 -> 7
2 -> 5
2 -> 7
Example 2:
[
[0, 4, 3],
[5, 8, 9],
[5, 9, 9]
]
There are 4 Increasing paths.
0 -> 4
0 -> 4 -> 8
0 -> 4 -> 8
0 -> 4 -> 8 -> 9
0 -> 5
0 -> 5 -> 8
... and so on.
I’ve tried a few things, but none of which what I need. Because I don’t want this to seem like an “answer my homework for me”, here’s the code of what I’ve tried (I knew it wouldn’t work 100%, but it was a good start for me, and I wasn’t sure where to go from there)
/*
This attempt was from what I
gathered from longest increasing,
so it clearly isn’t valid.
*/
function(v){
let n=v.length;
let m=v[0].length;
let mem=(new Array(n));
for(let i=0;i<n;i++)mem[i]=(new Array(m)).fill(0);
mem[0][0]=1;
for(let i=1;i<n;i++){
if (v[i][0] > v[i-1][0] && mem[i-1][0] == 1) {
mem[i][0] = 1;
}
}
for(let i=1;i<m;i++){
if (v[0][i] > v[0][i-1] && mem[0][i-1] == 1) {
mem[0][i] = 1;
}
}
for(let i=1;i<n;i++){
for(let j=1;j<m;j++){
if (v[i][j] > v[i-1][j] && mem[i-1][j] == 1) {
mem[i][j] = 1;
}
if (mem[i][j] == 0 && v[i][j] > v[i][j-1] && mem[i][j-1] == 1){
mem[i][j] = 1;
}
}
}
return mem[n-1][m-1] ? n+m-1 : -1;
}
(Note: I come from a strictly UX and front-end background, but I’m trying to improve my skills on this type of programming and move to a more full stack position, so I appreciate the help with a novice question! :))
Some tips:
View the grid as a graph, nodes are each gridpoint and edges are formed where it is possible to move from a to b
An increasing path means going from a smaller value a to a bigger value b.
This ensures that the graph is directed. (you can never go back the same edge)
such a path a->b->c...->f you can never connect to any earlier point in your path, as it would imply that a < b < .. < f < a. this means that the graph has no cycles
A graph with directed edges and no cycles are known as DAGs (directed acyclic graphs). Many graph algorithms are a lot easier on these graphs, including listing all paths.
Your task is simply to write a DFS (depth first search) and start it on every gridpoint (filter out path of length 0 in the end).
The following is the way I have solved using Javascript
const savedPathCount = [];
function getAvailablePath(grid, x, y) {
if (!savedPathCount[x]) {
savedPathCount[x] = [];
}
if (savedPathCount[x][y]) {
return savedPathCount[x][y]
}
savedPathCount[x][y] = 0
const currentValue = grid[x][y];
if (y > 0) {
const topValue = grid[x][y - 1];
if (topValue && topValue > currentValue) {
savedPathCount[x][y]++;
savedPathCount[x][y] += getAvailablePath(grid, x, y - 1)
}
}
if (x > 0) {
const leftValue = grid[x - 1][y];
if (leftValue && leftValue > currentValue) {
savedPathCount[x][y]++;
savedPathCount[x][y] += getAvailablePath(grid, x - 1, y)
}
}
if (grid[x]) {
const rightValue = grid[x][y + 1];
if (rightValue && rightValue > currentValue) {
savedPathCount[x][y]++;
savedPathCount[x][y] += getAvailablePath(grid, x, y + 1)
}
}
if (grid[x + 1]) {
const bottomValue = grid[x + 1][y];
if (bottomValue && bottomValue > currentValue) {
savedPathCount[x][y]++;
savedPathCount[x][y] += getAvailablePath(grid, x + 1, y)
}
}
return savedPathCount[x][y];
}
function paths(grid) {
// Write your code here
let pathCount = 0
for (let x = 0; x < grid.length; x++) {
for (let y = 0; y < grid[x].length; y++) {
pathCount += getAvailablePath(grid, x, y);
}
}
return pathCount;
}
const grid = [[15, 34],[1, 6]]
console.log(grid(path))
Related
I'm trying to solve the following problem :
What I've come up with so far:
function averagePair(arr,tar){
if (arr.length < 2){
return false
}
let x = 0
for (var y = 1; y < arr.length; y++){
if ((arr[x] + arr[y]) / 2 == tar){
return true
}
else {
x++;
}
}
return false
}
I know this solution isn't correct, can someone explain why? It works for some cases but not all
There's a solution with O(1) additional space complexity and O(n) time complexity.
Since an array is sorted, it makes sense to have two indices: one going from begin to end (say y), another from end to begin of an array (say x).
Here's the code:
function averagePair(arr,tar){
// That's now included in for-loop condition
// if (arr.length < 2) {
// return false;
// }
let x = arr.length - 1;
for (var y = 0; y < x; y++) {
// Division may lose precision, so it's better to compare
// arr[x] + arr[y] > 2*tar
// than
// (arr[x] + arr[y]) / 2 > tar
while (y < x && arr[x] + arr[y] > 2*tar) {
x--;
}
if (x != y && arr[x] + arr[y] == 2*tar) {
return true;
}
}
return false;
}
It's kinda two-pointers technique: we'll decrease x until a[x] + a[y] > 2*tar for current loop iteration because we need to find the closest match. At the next for-loop iteration a[y] is greater or equal than the previous one, so it makes no sense to check if a[z] + a[y] == 2*tar for any z > x. We'll do this until indices aren't equal, which means there's no match.
You're only comparing adjacent elements, eg [0] vs [1], and [1] vs [2]. You also need to compare [0] vs [2] and so on. The simplest tweak would be to use a nested loop:
for (let x = 0; x < arr.length; x++) {
for (let y = 0; y < arr.length; y++) {
if (x !== y) {
// test arr[x] against arr[y]
But it'd be more elegant and less computationally complex (O(n) instead of O(n ^ 2)) to use a Set to keep track of what's been found so far:
const nums = new Set();
for (const num of arr) {
if (nums.has(tar - num)) {
return true;
} else {
nums.add(num);
}
}
function averagePair(arr,tar){
const nums = new Set();
for (const num of arr) {
if (nums.has(tar - num)) {
return true;
} else {
nums.add(num);
}
}
return false;
}
console.log(averagePair([-2, 3, 2], 0));
console.log(averagePair([-2, 3, 3], 0));
Description
I'm trying to implement a JS version of Levenshtein distance function, using the matrix method described on this page in Wikipedia.
Problem
The algorithm works as expected, it returns the difference between the strings (the amount of edits you need to do for strings to be equal), except it ignores index 0, no matter what character is at index 0, it always considers it to be "correct":
levenshteinDistance('cat', 'cave') // 2 (correct)
levenshteinDistance('cat', 'cap') // 1 (correct)
levenshteinDistance('cat', 'hat') // 0 (should be 1)
levenshteinDistance('cat', 'rat') // 0 (should be 1)
levenshteinDistance('cat', 'bat') // 0 (should be 1)
Code
https://codepen.io/aQW5z9fe/pen/mdPvJqV?editors=0011
function levenshteinDistance (string1, string2, options) {
if (string1 === string2) { return 0 }
let matrix = []
let cost
let i
let j
// Init first column of each row
for (i = 0; i <= string1.length; i++) {
matrix[i] = [i]
}
// Init each column in the first row
for (j = 0; j <= string2.length; j++) {
matrix[0][j] = j
}
// Fill in the rest of the matrix
for (i = 1; i <= string1.length; i++) {
for (j = 1; j <= string2.length; j++) {
// Set cost
cost = string1[i] === string2[j]
? 0
: 1
// Set the distances
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1, // deletion
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j - 1] + cost // substitution
)
if (
options.allowTypos &&
i > 1 &&
j > 1 &&
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
) {
matrix[i][j] = Math.min(
matrix[i][j],
matrix[i - 2][j - 2] + 1
) // transposition
}
}
}
return matrix[string1.length][string2.length]
}
console.log(
levenshteinDistance('cat', 'hat', { allowTypos: true })
)
I think you just made a small mistake I think this:
cost = string1[i] === string2[j]
Should be :
cost = string1[i-1] === string2[j-1]
Since otherwise you never check for the cost of the first letter in the strings and the cost for the letters after that in case of the substitution is always derived from that.
EDIT:
The part inside the transpose section/ allow typo section should also be changed from:
string1[i] === string2[j - 1] &&
string1[i - 1] === string2[j]
to
string1[i-1] === string2[j - 2] &&
string1[i - 2] === string2[j-1]
After looking at the Wikipedia article they for some reason use 1 indexed arrays for the strings and 0 indexed arrays for the matrix, so I guess that was the root of the problem.
I have a JavaScript code like so:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == myArray.length - 1) { di = -1; }
document.writeln(myArray[i]);
}
I need it to stop right in the middle like 10 and from 10 starts counting down to 0 back.
So far, I've managed to make it work from 0 to 20 and from 20 - 0.
How can I stop it in a middle and start it from there back?
Please help anyone!
Here is an example using a function which accepts the array and the number of items you want to display forwards and backwards:
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
if(myArray.length === 1){
ShowXElementsForwardsAndBackwards(myArray, 1);
}
else if(myArray.length === 0) {
//Do nothing as there are no elements in array and dividing 0 by 2 would be undefined
}
else {
ShowXElementsForwardsAndBackwards(myArray, (myArray.length / 2));
}
function ShowXElementsForwardsAndBackwards(mYarray, numberOfItems){
if (numberOfItems >= mYarray.length) {
throw "More Numbers requested than length of array!";
}
for(let x = 0; x < numberOfItems; x++){
document.writeln(mYarray[x]);
}
for(let y = numberOfItems - 1; y >= 0; y--){
document.writeln(mYarray[y]);
}
}
Just divide your array length by 2
var myArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
for (var i = 0, di = 1; i >= 0; i += di) {
if (i == ((myArray.length / 2) -1 )) { di = -1; }
document.writeln(myArray[i]);
}
Could Array.reverse() help you in this matter?
const array = [0,1,3,4,5,6,7,8,9,10,11,12,13,14,15]
const getArrayOfAmount = (array, amount) => array.filter((item, index) => index < amount)
let arraySection = getArrayOfAmount(array, 10)
let reversed = [...arraySection].reverse()
console.log(arraySection)
console.log(reversed)
And then you can "do stuff" with each array with watever array manipulation you desire.
Couldn’t you just check if you’ve made it halfway and then subtract your current spot from the length?
for(i = 0; i <= myArray.length; i++){
if( Math.round(i/myArray.length) == 1 ){
document.writeln( myArray[ myArray.length - i] );
} else {
document.writeln( myArray[i] );
}
}
Unless I’m missing something?
You could move the checking into the condition block of the for loop.
var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
for (
var i = 0, l = (myArray.length >> 1) - 1, di = 1;
i === l && (di = -1), i >= 0;
i += di
) {
document.writeln(myArray[i]);
}
If you capture the midpoint ( half the length of the array ), just start working your step in the opposite direction.
const N = 20;
let myArray = [...Array(N).keys()];
let midpoint = Math.round(myArray.length/2)
for ( let i=1, step=1; i; i+=step) {
if (i === midpoint)
step *= -1
document.writeln(myArray[i])
}
To make things clearer, I've:
Started the loop iterator variable (i) at 1; this also meant the array has an unused 0 value at 0 index; in other words, myArray[0]==0 that's never shown
Set the the loop terminating condition to i, which means when i==0 the loop will stop because it is falsy
Renamed the di to step, which is more consistent with other terminology
The midpoint uses a Math.round() to ensure it's the highest integer (midpoint) (e.g., 15/2 == 7.5 but you want it to be 8 )
The midpoint is a variable for performance reasons; calculating the midpoint in the loop body is redundant and less efficient since it only needs to be calculated once
For practical purpose, made sizing the array dynamic using N
Updated to ES6/ES7 -- this is now non-Internet Explorer-friendly [it won't work in IE ;)] primarily due to the use of the spread operator (...) ... but that's easily avoidable
I can't find how to determine to which interval an element belongs based on an Array for JavaScript. I want the behavior of bisect.bisect_left from Python. Here is some sample code:
import bisect
a = [10,20,30,40]
print(bisect.bisect_left(a,0)) #0 because 0 <= 10
print(bisect.bisect_left(a,10)) #0 because 10 <= 10
print(bisect.bisect_left(a,15)) #1 because 10 < 15 < 20
print(bisect.bisect_left(a,25)) #2 ...
print(bisect.bisect_left(a,35)) #3 ...
print(bisect.bisect_left(a,45)) #4
I know this would be easy to implement, but why re-invent the wheel?
In case anyone else lands here, here's an implementation of bisect_left that actually runs in O(log N), and should work regardless of the interval between list elements. NB that is does not sort the input list, and, as-is, will likely blow the stack if you pass it an unsorted list. It's also only set up to work with numbers, but it should be easy enough to adapt it to accept a comparison function. Take this as a starting point, not necessarily your destination. Improvements are certainly welcome!
Run it in a REPL
function bisect(sortedList, el){
if(!sortedList.length) return 0;
if(sortedList.length == 1) {
return el > sortedList[0] ? 1 : 0;
}
let lbound = 0;
let rbound = sortedList.length - 1;
return bisect(lbound, rbound);
// note that this function depends on closure over lbound and rbound
// to work correctly
function bisect(lb, rb){
if(rb - lb == 1){
if(sortedList[lb] < el && sortedList[rb] >= el){
return lb + 1;
}
if(sortedList[lb] == el){
return lb;
}
}
if(sortedList[lb] > el){
return 0;
}
if(sortedList[rb] < el){
return sortedList.length
}
let midPoint = lb + (Math.floor((rb - lb) / 2));
let midValue = sortedList[midPoint];
if(el <= midValue){
rbound = midPoint
}
else if(el > midValue){
lbound = midPoint
}
return bisect(lbound, rbound);
}
}
console.log(bisect([1,2,4,5,6], 3)) // => 2
console.log(bisect([1,2,4,5,6], 7)) // => 5
console.log(bisect([0,1,1,1,1,2], 1)) // => 1
console.log(bisect([0,1], 0)) // => 0
console.log(bisect([1,1,1,1,1], 1)) // => 0
console.log(bisect([1], 2)); // => 1
console.log(bisect([1], 1)); // => 0
Speaking of re-inventing the wheel, I'd like to join the conversation:
function bisectLeft(arr, value, lo=0, hi=arr.length) {
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (arr[mid] < value) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
I believe that is the schoolbook implementation of bisection. Actually, you'll find something pretty much the same inside the d3-array package mentioned before.
using the D3-array npm.
const d3 = require('d3-array');
var a = [10,20,30,40];
console.log(d3.bisectLeft(a,0));
console.log(d3.bisectLeft(a,10));
console.log(d3.bisectLeft(a,15));
console.log(d3.bisectLeft(a,25));
console.log(d3.bisectLeft(a,35));
console.log(d3.bisectLeft(a,45));
output:
0
0
1
2
3
4
A faster way than the previously accepted answer that works for same size intervals is:
var array = [5, 20, 35, 50]
//Intervals:
// <5: 0
// [5-20): 1
// [20-35): 2
// [35-50): 3
// >=50: 4
var getPosition = function(array, x) {
if (array.length == 0) return;
if (array.length == 1) return (x < array[0]) ? 0 : 1;
return Math.floor((x - array[0]) / (array[1] - array[0])) + 1
}
console.log(getPosition(array, 2)); //0
console.log(getPosition(array, 5)); //1
console.log(getPosition(array, 15));//1
console.log(getPosition(array, 20));//2
console.log(getPosition(array, 48));//3
console.log(getPosition(array, 50));//4
console.log(getPosition(array, 53));//4
console.log("WHEN SIZE: 1")
array = [5];
//Intervals:
// <5: 0
// >=5: 1
console.log(getPosition(array, 3));
console.log(getPosition(array, 5));
console.log(getPosition(array, 6));
There are no built-in bisection functions in JavaScript, so you will have to roll your own. Here is my personal reinvention of the wheel:
var array = [10, 20, 30, 40]
function bisectLeft (array, x) {
for (var i = 0; i < array.length; i++) {
if (array[i] >= x) return i
}
return array.length
}
console.log(bisectLeft(array, 5))
console.log(bisectLeft(array, 15))
console.log(bisectLeft(array, 25))
console.log(bisectLeft(array, 35))
console.log(bisectLeft(array, 45))
function bisectRight (array, x) {
for (var i = 0; i < array.length; i++) {
if (array[i] > x) return i
}
return array.length
}
Hy,
I am trying to implement an Connect Four Game in javascript / jQuery. First off this is no homework or any other duty. I'm just trying to push my abilities.
My "playground" is a simple html table which has 7 rows and 6 columns.
But now I have reached my ken. I'm stuck with the main functionality of checking whether there are 4 same td's around. I am adding a class to determine which color it should represent in the game.
First I thought I could handle this with .nextAll() and .prevAll() but this does not work for me because there is no detection between.
Because I was searching for siblings, when adding a new Item and just looked up the length of siblings which were found and if they matched 4 in the end I supposed this was right, but no its not :D Is there maybe any kind of directNext() which provides all next with a css selector until something different comes up ?
I will put all of my code into this jsfiddle: http://jsfiddle.net/LcUVf/5/
Maybe somebody has ever tried the same or someone comes up with a good idea I'm not asking anybody to do or finish my code. I just want to get hints for implementing such an algorithm or examples how it could be solved !
Thanks in anyway !
DOM traversal is not particularly efficient so, when you can avoid it, I'd recommend doing so. It'd make sense for you to build this as a 2D array to store and update the state of the game. The table would only be a visual representation of the array.
I know that, normally, you would build the array with rows as the first dimension and columns as the second dimension but, for the purposes of being able to add pieces to each column's "stack," I would make the first dimension the columns and the second dimension the rows.
To do the check, take a look at this fiddle I made:
http://jsfiddle.net/Koviko/4dTyw/
There are 4 directions to check: North-South, East-West, Northeast-Southwest, and Southeast-Northwest. This can be represented as objects with the delta defined for X and Y:
directions = [
{ x: 0, y: 1 }, // North-South
{ x: 1, y: 0 }, // East-West
{ x: 1, y: 1 }, // Northeast-Southwest
{ x: 1, y: -1 } // Southeast-Northwest
];
Then, loop through that object and loop through your "table" starting at the farthest bounds that this piece can possibly contribute to a win. So, since you need 4 pieces in a row, the currently placed piece can contribute in a win for up to 3 pieces in any direction.
minX = Math.min(Math.max(placedX - (3 * directions[i].x), 0), pieces.length - 1);
minY = Math.min(Math.max(placedY - (3 * directions[i].y), 0), pieces[0].length - 1);
maxX = Math.max(Math.min(placedX + (3 * directions[i].x), pieces.length - 1), 0);
maxY = Math.max(Math.min(placedY + (3 * directions[i].y), pieces[0].length - 1), 0);
To avoid any issues with less-than and greater-than (which I ran into), calculate the number of steps before looping through your pieces instead of using the calculated bounds as your conditions.
steps = Math.max(Math.abs(maxX - minX), Math.abs(maxY - minY));
Finally, loop through the items keeping a count of consecutive pieces that match the piece that was placed last.
function isVictory(pieces, placedX, placedY) {
var i, j, x, y, maxX, maxY, steps, count = 0,
directions = [
{ x: 0, y: 1 }, // North-South
{ x: 1, y: 0 }, // East-West
{ x: 1, y: 1 }, // Northeast-Southwest
{ x: 1, y: -1 } // Southeast-Northwest
];
// Check all directions
outerloop:
for (i = 0; i < directions.length; i++, count = 0) {
// Set up bounds to go 3 pieces forward and backward
x = Math.min(Math.max(placedX - (3 * directions[i].x), 0), pieces.length - 1);
y = Math.min(Math.max(placedY - (3 * directions[i].y), 0), pieces[0].length - 1);
maxX = Math.max(Math.min(placedX + (3 * directions[i].x), pieces.length - 1), 0);
maxY = Math.max(Math.min(placedY + (3 * directions[i].y), pieces[0].length - 1), 0);
steps = Math.max(Math.abs(maxX - x), Math.abs(maxY - y));
for (j = 0; j < steps; j++, x += directions[i].x, y += directions[i].y) {
if (pieces[x][y] == pieces[placedX][placedY]) {
// Increase count
if (++count >= 4) {
break outerloop;
}
} else {
// Reset count
count = 0;
}
}
}
return count >= 4;
}
I released a fully working version of the game on Github.
It implements an optimised variation on the algorythm Sirko mentioned.
To avoid any unnecessary redunancy, the algorythm directly checks the DOM rather than a JS table. As that algorythm requires a minimum amount of checks, the performance overhead for accessing the DOM is neglectable.
The current player and a flag for keeping track of whether the game has ended are basicly the only statuses stored in the JS itself.
I even used the DOM to store strings. It has no external dependencies and is supported by all versions of IE from IE6 upwards as well as modern browsers.
Code is optimised for filesize and performance. The latest version also includes animation, even though the total JS code of the game is still only 1.216 bytes after minification.
The Code :
Here's the full, un-minified JS code :
(function (doc, win, onclick, gid, classname, content, showMessage) {
var
a, b, c, colorLabel, cid, players, current, finished, newgameLabel, wonLabel, laststart = 1,
cellAt = function (i, j) {
return doc[gid](cid + i + j);
},
isCurrentColor = function (i, j) {
return cellAt(i, j)[classname] === players[current];
},
start = function () {
current = laststart = (laststart + 1) % 2;
finished = 0;
colorLabel[content] = colorLabel[classname] = players[current = (current + 1) % 2];
for (a = 1; a < 7; a++)
for (b = 1; b < 8; b++)
cellAt(a, b)[classname] = '';
},
makeMove = function (i, j, s) {
s > 0 && (cellAt(s, j)[classname] = '');
cellAt(s + 1, j)[classname] = players[current];
s === i - 1 ? function (i, j) {
return function (i, j) {
for (a = j - 1; 0 < a && isCurrentColor(i, a); a--) {
}
for (b = j + 1; 8 > b && isCurrentColor(i, b); b++) {
}
return 4 < b - a;
}(i, j) || function (i, j) {
for (c = i + 1; 7 > c && isCurrentColor(c, j); c++) {
}
return 3 < c - i;
}(i, j) || function (i, j) {
for (a = i - 1, b = j - 1; 0 < a && !(1 > b) && isCurrentColor(a, b); a--)
b--;
for (c = i + 1, b = j + 1; 7 > c && !(7 < b) && isCurrentColor(c, b); c++)
b++;
return 4 < c - a
}(i, j) || function (i, j) {
for (a = i - 1, b = j + 1; 0 < a && !(7 < b) && isCurrentColor(a, b); a--)
b++;
for (c = i + 1, b = j - 1; 7 > c && !(1 > b) && isCurrentColor(c, b); c++)
b--;
return 4 < c - a;
}(i, j);
}(i, j)
? finished = 1 && win[showMessage](doc[gid](wonLabel)[content].replace("%s", players[current].toLowerCase())) && start()
: colorLabel[content] = colorLabel[classname] = players[current = (current + 1) % 2]
: setTimeout(function () {
makeMove(i, j, s + 1)
}, 20);
};
return function (n, w, c, h, p1, p2) {
cid = c;
newgameLabel = n;
wonLabel = w;
colorLabel = doc[gid](c);
players = [doc[gid](p1)[content], doc[gid](p2)[content]];
for (a = 1; a < 7; a++)
for (b = 1; b < 8; b++)
cellAt(a, b)[onclick] = function (b, a) {
return function () {
if (!finished)
for (a = 6; a > 0; a--)
if (!cellAt(a, b)[classname]) {
makeMove(a, b, 0);
break;
}
};
}(b);
;
doc[gid](h)[onclick] = function () {
win[showMessage](doc[gid](newgameLabel)[content]) && start()
};
start();
};
})(document, window, "onclick", "getElementById", "className", "innerHTML", "confirm")("newgame", "won", "color", "restart", "p1", "p2");
A screenshot :
In general a 2dimensional array would be better suited for checking for a line of 4. You could then do something like the following:
function check( lastPiece, playground, player ) {
// check length in each direction
var l = 1,
i = 1;
// top to bottom
while( (playground[ lastPiece.x ][ lastPiece.y - i ] === player) && ((lastPiece.y - i) >= 0) ) { l += 1; i += 1; };
i = 1;
while( (playground[ lastPiece.x ][ lastPiece.y + i ] === player) && ((lastPiece.y + i) <= MAX_Y) ) { l += 1; i += 1; };
if ( l >= 4 ) { return true; }
// left to right
l = 1;
while( (playground[ lastPiece.x - i][ lastPiece.y ] === player) && ((lastPiece.x - i) >= 0) ) { l += 1; i += 1; };
i = 1;
while( (playground[ lastPiece.x + i][ lastPiece.y ] === player) && ((lastPiece.x + i) <= MAX_X) ) { l += 1; i += 1; };
if ( l >= 4 ) { return true; }
// same for top left to bottom right and bottom left to top right
// . . .
// if we got no hit until here, there is no row of 4
return false;
}
EDIT: added checks for borders of the playground