var chessboard = [[2,1,0],[2,1,0],[0,0,0]];
function checkwins(array){}//The function is too long.I will explain here.It decides
//whether there is a winner.If there is a winner it will return 1 or 0
//(1 stand for number 2's win on the chessboard 0 stands for number 1's win)If there is no winner, it will return 2)
function score(board,depth){
if(checkwins(board)===0)return depth-10;
if(checkwins(board)==1)return 10-depth;
else return 0;
}
function count_move(board,depth,current_turn){
board = board.slice();
var possible_moves = possible_movements(board);
if(checkwins(board)!=2|| possible_moves.length===0)return score(board,depth);
var move_score;
var new_board;
depth++;
if(current_turn===0)move_score = -1000;
else move_score = 1000;
if(!current_turn){
possible_moves.forEach(function(possible_location){
var new_board = board.slice();
new_board[possible_location[0]][possible_location[1]] = 1;
var current_score = count_move(new_board,depth,1);
if(current_score > move_score)move_score = current_score;
});
}else{
possible_moves.forEach(function(possible_location){
var new_board = board.slice();
new_board[possible_location[0]][possible_location[1]] = 2;
var current_score = count_move(new_board,depth,0);
if(current_score < move_score)move_score = current_score;
});
}
return move_score;
}
function ai(board){
var possible_moves = possible_movements(board);
var best_move;
var move_score = -1000;
var current_score ;
possible_moves.forEach(function(move){
var next_board = board.slice();
next_board[move[0]][move[1]] = 1;
current_score = count_move(next_board,0,1);
console.log("Current Move :"+move+"\nCurrent Score :"+current_score+'\nCurrent Board :'+next_board+'\n');
if(current_score > move_score){
move_score = current_score;
best_move = move;
}
});
console.log(best_move);
}
console.log(chessboard);
ai(chessboard);
console.log(chessboard);
I am writing a Tic tac toe game Ai by using Minimax algorithm.I currently have some problems with javascript.I found that when I passed array as argument into function and then revise it in the function.It will change the array passing even outside the function.The console results is below:
[ [ 2, 1, 0 ], [ 2, 1, 0 ], [ 0, 0, 0 ] ]
Current Move :0,2
Current Score :-8
Current Board :2,1,1,2,1,2,2,2,2
Current Move :1,2
Current Score :10
Current Board :2,1,1,2,1,1,2,2,2
Current Move :2,0
Current Score :-10
Current Board :2,1,1,2,1,1,1,2,2
Current Move :2,1
Current Score :-10
Current Board :2,1,1,2,1,1,1,1,2
Current Move :2,2
Current Score :-10
Current Board :2,1,1,2,1,1,1,1,1
[ 1, 2 ]
[ [ 2, 1, 1 ], [ 2, 1, 1 ], [ 1, 1, 1 ] ]
Then I found it seems to use
new_array = array.slice()
inside the function should avoid it, so I add it in my function.The results still don't change.I get quite confused here.
slice performs a shallow copy of an array. That means that the array itself is copied but not any of the objects inside of it.
var a = [ [1], [2], [3] ];
var b = a.slice();
b.push(4);
// Change b does not change a
console.log('A:', JSON.stringify(a));
console.log('B:', JSON.stringify(b));
console.log('');
// However, changing the internal arrays will affect both
b[0][0] = 10;
console.log('A:', JSON.stringify(a));
console.log('B:', JSON.stringify(b));
console.log('');
You need to perform a deep copy, meaning you copy not just the outer array but also the inner arrays.
function copy2DArray(array) {
var copy = [];
array.forEach(function(subArray) {
var copiedSubArray = subArray.slice();
copy.push(copiedSubArray);
});
return copy;
}
var a = [ [1], [2], [3] ];
var b = copy2DArray(a);
// Now you won't change a by modifying b
b[0][0] = 10;
console.log('A:', JSON.stringify(a));
console.log('B:', JSON.stringify(b));
Related
I have the following array :
for (let i of lastBal) {
var amtToDetect = received_amt;
console.log('amt to detect', amtToDetect);
var lpcForLoop = i.lpc;
var lic_fee_for_loop = i.lic_fee;
var daysDifference_for_loop = i.lpdays;
var onlineLPC_for_loop = i.onlinelpc;
var total_amt_for_loop = i.total_amt;
console.log('lic fee for loop', i.lic_fee);
if (amtToDetect >= lic_fee_for_loop) {
var remainAmtAfterLPC = Math.floor(amtToDetect - lpcForLoop);
var paidLPC = amtToDetect - remainAmtAfterLPC;
if (remainAmtAfterLPC > 0) {
if (remainAmtAfterLPC >= lic_fee_for_loop) {
var remainBalanceAfterLicFee = remainAmtAfterLPC - lic_fee_for_loop
var paidLicFee = remainAmtAfterLPC - remainBalanceAfterLicFee;
var total_amt_payment = Math.floor(paidLicFee + lpcForLoop);
//for balance entry
var bal_lic_fee = Math.floor(lic_fee_for_loop - paidLicFee);
var bal_LPC = Math.floor(lpcForLoop - lpcForLoop);
var bal_total_amt = Math.floor(bal_lic_fee + bal_LPC);
}
}
}
//console.log('demand in for loop',demandInsertData);
let difference = paymentDate - lic_fee_due_date;
var daysDifference = Math.floor(difference / 1000 / 60 / 60 / 24);
var onlineLPC = Math.floor(lic_fee * 0.18 * daysDifference / 365);
var currentLPC = Math.floor(onlineLPC + bal_LPC);
var total_amt = Math.floor(lic_fee + currentLPC);
console.log('in end for loop');
i.lpc = onlineLPC;
i.lic_fee = lic_fee - i.lic_fee;
console.log('in end for loop lic fee', i.lic_fee);
i.lpdays = daysDifference;
i.total_amt = total_amt;
received_amt = remainBalanceAfterLicFee;
console.log('in end for loop received_amt', received_amt);
}
In the above for loop, I want to replace some elements from lastBal array.
At the end of the for loop, I tried to replace some elements as follows :
i.lic_fee = lic_fee - i.lic_fee;
However, values are not being replaced during the next iteration. Instead, old values are being assigned.
How can I find the issue here?
Edit
After changing elements values I want to use them in same for loop.
Means after 1st iteration in for loop I want to change the values of element and use the updated values in next iteration.
Here at end of loop values are updated, but in second iteration old values form lastBal are assign.
Edit 2: Added lastBal
last bal [ RowDataPacket {
demand_id: 42,
user_id: 4,
lic_id: 4,
description: 'Balance',
demand_start_date: '2020-07-01',
demand_end_date: '2020-09-30',
demand_fin_year: '2020-2021',
lic_fee: 27000,
form_fee: 0,
lic_fee_due_date: '2020-06-30',
lrc: 0,
srtax: 0,
lpc: 1224,
total_amt: 28224,
outstanding_amt: 28224,
lpdays: 92,
onlinelpc: 1224,
flag: 0,
lic_fee_pay_id: 0,
demand_added_date: '2020-04-28 19:43:14',
payment_date: '0000-00-00 00:00:00' },
RowDataPacket {
demand_id: 44,
user_id: 4,
lic_id: 4,
description: 'Balance',
demand_start_date: '2020-10-01',
demand_end_date: '2020-12-31',
demand_fin_year: '2020-2021',
lic_fee: 54000,
form_fee: 0,
lic_fee_due_date: '2020-09-30',
lrc: 0,
srtax: 0,
lpc: 1224,
total_amt: 55224,
outstanding_amt: 55224,
lpdays: 0,
onlinelpc: 0,
flag: 0,
lic_fee_pay_id: 0,
demand_added_date: '2020-04-28 19:52:25',
payment_date: '0000-00-00 00:00:00' } ]
Above array is fetch from database.I want to updated 2nd RowDataPacket after 1st iteration in for loop.values to updated 2nd RowDataPacket are dynamic.
Well, I did try to reproduce with your code while putting some sample values in the fields wherever necessay and I do see the expected modifications. Hence, you need to clarify where exactly you're not seeing the changes that you're expecting.
var lastBal = [{ lpc: 1, lic_fee: 2, lpdays: 9, onlinelpc: 4, total_amt: 2 }, { lpc: 3, lic_fee: 4, lpdays: 2, onlinelpc: 5, total_amt: 1 }];
var editedValues = {};
for (let i of lastBal) {
if (!(Object.keys(editedValues).length === 0 && editedValues.constructor === Object)) {
i = {...i, ...editedValues} ;
}
var amtToDetect = 5;
console.log('amt to detect', amtToDetect);
var lpcForLoop = i.lpc;
var lic_fee_for_loop = i.lic_fee;
var daysDifference_for_loop = i.lpdays;
var onlineLPC_for_loop = i.onlinelpc;
var total_amt_for_loop = i.total_amt;
console.log('lic fee for loop', i.lic_fee);
if (amtToDetect >= lic_fee_for_loop) {
var remainAmtAfterLPC = Math.floor(amtToDetect - lpcForLoop);
var paidLPC = amtToDetect - remainAmtAfterLPC;
if (remainAmtAfterLPC > 0) {
if (remainAmtAfterLPC >= lic_fee_for_loop) {
var remainBalanceAfterLicFee = remainAmtAfterLPC - lic_fee_for_loop
var paidLicFee = remainAmtAfterLPC - remainBalanceAfterLicFee;
var total_amt_payment = Math.floor(paidLicFee + lpcForLoop);
//for balance entry
var bal_lic_fee = Math.floor(lic_fee_for_loop - paidLicFee);
var bal_LPC = Math.floor(lpcForLoop - lpcForLoop);
var bal_total_amt = Math.floor(bal_lic_fee + bal_LPC);
}
}
}
//console.log('demand in for loop',demandInsertData);
var daysDifference = 5000;
var onlineLPC = 2000;
var currentLPC = 1000;
var total_amt = 1500;
console.log('in end for loop');
i.lpc = onlineLPC;
i.lic_fee = 4000 - i.lic_fee;
console.log('in end for loop lic fee', i.lic_fee);
i.lpdays = daysDifference;
i.total_amt = 7000;
received_amt = 11000;
console.log('in end for loop received_amt', received_amt);
editedValues = {
pc: onlineLPC,
lic_fee: lic_fee - i.lic_fee,
lpdays: daysDifference,
total_amt: total_amt,
onlinelpc: onlineLPC,
received_amt: remainBalanceAfterLicFee
} // Whatever values you'd like to retain for the subsequent execution
}
console.log(lastBal);
EDIT
- Updated accordingly as you updated your requirements.
Because you are not accessing the array index/key, or in this case the object in javascript.
Take a look at the code below, I can't change "b to bb" assigning "bb" to the variable display the value in the for loop (key). In this case key='bb' will print the value but it will not change it.
var test = [];
test = ['a','b','c','d','e','f','g','h','i'];
for (let key of test){
if (key == 'b') { key = 'bb'}
console.log(key);
}
test[1] = 'cc';
for (let key of test){
console.log(key);
}
In order to change the value in the object/array you need to reference the index/key from the original array. test[1]='cc'; then the value will be changed.
Run the code commenting the test[1]='cc'; line, you will see that the value was not change in the initial loop, then run it uncommenting the line.
I have an application that takes in multiple arrays of data each or variable length. I plan on cycling through and displaying every combination of data for each array I'm given. My first inclination was to have a single number represent the state of each array since I know the number of combinations is the product of the number of elements of each array.
So for example:
A = [0,1,2,3]
B = [0,1,2,3]
C = [0,1]
So 4 x 4 x 2 = 32 combinations I need to represent
I've managed to represent all states by applying modulo and division to a given index using each array.length. My problem is that it doesn't order well (see snippet below). Has anyone solved a similar problem or know how I could change the algorithm to get it in order?
function multiArrayIndex(index, ...args) {
var arrays = args.slice();
var output = [];
for (var i = 0, curIndex = index; i < arrays.length; i++) {
var curArray = arrays[i];
var valueIndex =(curIndex % curArray.length);
output.push(curArray[valueIndex]);
curIndex = Math.ceil(curIndex / curArray.length);
}
return output;
}
demoP = document.getElementById("demo");
for(var i = 32; i>=1; i--){
demoP.innerHTML = demoP.innerHTML + i + " - " + multiArrayIndex(i, [0,1,2,3], [0,1,2,3], [0,1] ) + "<br />";
}
<p id="demo"></p>
Keeping the indices separate would be a nicer approach in my opinion.
Incrementing the indices could work kinda similar to how we added two numbers by hand in elementary school - if an index is too large, set it to zero and increment the next one by one:
var a = [0, 1, 2, 3]
var b = [0, 1, 2, 3]
var c = [0, 1]
var state = {
a: 0,
b: 0,
c: 0
}
function increment() {
state.a++;
if (state.a >= a.length) {
state.b++;
state.a = 0;
}
if (state.b >= b.length) {
state.c++;
state.b = 0;
}
if (state.c >= c.length) {
state.c = 0;
}
console.log(state);
}
console.log(state);
<button onclick='increment()'>Increment</button>
Updating the document based on the state should be trivial from here.
I have an array like [1,4,3,1,6,5,1,4,4]
Here Highest element frequency is 3 ,I need to select all elements from array that have 3 frequency like [1,4] in above example.
I have tried with this
var count = {},array=[1,4,3,1,6,5,1,4,4],
value;
for (var i = 0; i < array.length; i++) {
value = array[i];
if (value in count) {
count[value]++;
} else {
count[value] = 1;
}
}
console.log(count);
this will output array element with their frequency , now i need all elements that have highest frequency.
I'd approach this problem as follows.
First, write down how you think the problem can be solved IN ENGLISH, or something close to English (or your native language of course!). Write down each step. Start off with a high-level version, such as:
Count the frequency of each element in the input.
Find the highest frequency.
and so on. At this point, it's important that you don't get bogged down in implementation details. Your solution should be applicable to almost any programming language.
Next flesh out each step by adding substeps. For instance, you might write:
Find the highest frequency.
a. Assume the highest frequency is zero.
b. Examine each frequency. If it is higher than the current highest frqeuency, make it the current highest frequency.
Test your algorithm by executing it manually in your head.
Next, convert what you have written about into what is sometimes called pseudo-code. It is at this point that our algorithm starts to look a little bit like a computer program, but is still easily human-readable. We may now use variables to represent things. For instance, we could write "max_freq ← cur_freq". We can refer to arrays, and write loops.
Finally, convert your pseudo-code into JS. If all goes well, it should work the first time around!
In recent years, a lot of people are jumping right into JavaScript, without any exposure to how to think about algorithms, even simple ones. They imagine that somehow they need to be able to, or will magically get to the point where they can, conjure up JS out of thin air, like someone speaking in tongues. In fact, the best programmers do not instantly start writing array.reduce when confronted with a problem; they always go through the process--even if only in their heads--of thinking about the approach to the problem, and this is an approach well worth learning from.
If you do not acquire this skill, you will spend the rest of your career posting to SO each time you can't bend your mind around a problem.
A proposal with Array.prototype.reduce() for a temporary object count, Object.keys() for getting the keys of the temporary object, a Array.prototype.sort() method for ordering the count results and Array.prototype.filter() for getting only the top values with the most count.
Edit: Kudos #Xotic750, now the original values are returned.
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4],
result = function () {
var temp = array.reduce(function (r, a, i) {
r[a] = r[a] || { count: 0, value: a };
r[a].count++;
return r;
}, {});
return Object.keys(temp).sort(function (a, b) {
return temp[b].count - temp[a].count;
}).filter(function (a, _, aa) {
return temp[aa[0]].count === temp[a].count;
}).map(function (a) {
return temp[a].value;
});
}();
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Bonus with a different attempt
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4],
result = array.reduce(function (r, a) {
r.some(function (b, i) {
var p = b.indexOf(a);
if (~p) {
b.splice(p, 1);
r[i + 1] = r[i + 1] || [];
r[i + 1].push(a);
return true;
}
}) || (
r[1] = r[1] || [],
r[1].push(a)
);
return r;
}, []).pop();
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
you can try this
var input = [1,4,3,1,6,5,1,4,4];
var output = {};
for ( var counter = 0; counter < input.length; counter++ )
{
if ( !output[ input[ counter ] ] )
{
output[ input[ counter ] ] = 0;
}
output[ input[ counter ] ]++;
}
var outputArr = [];
for (var key in output)
{
outputArr.push([key, output[key]])
}
outputArr = outputArr.sort(function(a, b) {return b[1] - a[1]})
now initial values of outputArr are the ones with highest frequency
Here is the fiddle
Check this updated fiddle (this will give the output you want)
var input = [1,4,3,1,6,5,1,4,4];
var output = {}; // this object holds the frequency of each value
for ( var counter = 0; counter < input.length; counter++ )
{
if ( !output[ input[ counter ] ] )
{
output[ input[ counter ] ] = 0; //initialized to 0 if value doesn't exists
}
output[ input[ counter ] ]++; //increment the value with each occurence
}
var outputArr = [];
var maxValue = 0;
for (var key in output)
{
if ( output[key] > maxValue )
{
maxValue = output[key]; //find out the max value
}
outputArr.push([key, output[key]])
}
var finalArr = []; //this array holds only those keys whose value is same as the highest value
for ( var counter = 0; counter < outputArr.length; counter++ )
{
if ( outputArr[ counter ][ 1 ] == maxValue )
{
finalArr.push( outputArr[ counter ][ 0 ] )
}
}
console.log( finalArr );
I would do something like this. It's not tested, but it's commented for helping you to understand my approach.
// Declare your array
var initial_array = [1,4,3,1,6,5,1,4,4];
// Declare an auxiliar counter
var counter = {};
// Loop over the array
initial_array.forEach(function(item){
// If the elements is already in counter, we increment the repetition counter.
if counter.hasOwnProperty(item){
counter[item] += 1;
// If the element is not in counter, we set the repetitions to one
}else{
counter[item] = 1;
}
});
// counter = {1 : 3, 4 : 3, 3 : 1, 6 : 1, 5 : 1}
// We move the object keys to an array (sorting it's more easy this way)
var sortable = [];
for (var element in counter)
sortable.push([element, counter[element]]);
// sortable = [ [1,3], [4,3], [3,1], [6,1], [5,1] ]
// Sort the list
sortable.sort(function(a, b) {return a[1] - b[1]})
// sortable = [ [1,3], [4,3], [3,1], [6,1], [5,1] ] sorted, in this case both are equals
// The elements in the firsts positions are the elements that you are looking for
// This auxiliar variable will help you to decide the biggest frequency (not the elements with it)
higgest = 0;
// Here you will append the results
results = [];
// You loop over the sorted list starting for the elements with more frequency
sortable.forEach(function(item){
// this condition works because we have sorted the list previously.
if(item[1] >= higgest){
higgest = item[1];
results.push(item[0]);
}
});
I'm very much with what #torazaburo had to say.
I'm also becoming a fan of ES6 as it creeps more and more into my daily browser. So, here is a solution using ES6 that is working in my browser now.
The shims are loaded to fix browser browser bugs and deficiencies, which is recommended in all environments.
'use strict';
// Your array of values.
const array = [1, 4, 3, 1, 6, 5, 1, 4, 4];
// An ES6 Map, for counting the frequencies of your values.
// Capable of distinguishing all unique values except `+0` and `-0`
// i.e. SameValueZero (see ES6 specification for explanation)
const frequencies = new Map();
// Loop through all the `values` of `array`
for (let item of array) {
// If item exists in frequencies increment the count or set the count to `1`
frequencies.set(item, frequencies.has(item) ? frequencies.get(item) + 1 : 1);
}
// Array to group the frequencies into list of `values`
const groups = [];
// Loop through the frequencies
for (let item of frequencies) {
// The `key` of the `entries` iterator is the value
const value = item[0];
// The `value` of the `entries` iterator is the frequency
const frequency = item[1];
// If the group exists then append the `value`,
// otherwise add a new group containing `value`
if (groups[frequency]) {
groups[frequency].push(value);
} else {
groups[frequency] = [value];
}
}
// The most frequent values are the last item of `groups`
const mostFrequent = groups.pop();
document.getElementById('out').textContent = JSON.stringify(mostFrequent);
console.log(mostFrequent);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.4.1/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.34.0/es6-shim.js"></script>
<pre id="out"></pre>
you can do like this to find count occurrence each number
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4];
var frequency = array.reduce(function(sum, num) {
if (sum[num]) {
sum[num] = sum[num] + 1;
} else {
sum[num] = 1;
}
return sum;
}, {});
console.log(frequency)
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
I have a function (getCoeff()) which returns one-dimensional arrays. I try to use it to fill a two-dimensional array:
//set up an 3x3 array for A
A = new Array(3);
for (var i=0; i<3; i++) {
A[i] = new Array(3);
}
//fill it per row using getCoeff()
for (var i=0; i<3; i++) {
A[i] = getCoeff(i+1);
}
console.log(A);
console.log(getCoeff(1));
console.log(getCoeff(2));
console.log(getCoeff(3));
but I only get the first row filled and the other two remain empty:
[ [ -3, 2, -1 ], [ , , ], [ , , ] ]
[ -3, 2, -1 ]
[ 2, -3, 2 ]
[ 1, -1, 3 ]
As you can see the function returns the rows correctly but for some reason It doesnt work inside the loop.
On the other hand if I try something like this:
for (var i=0; i<3; i++) {
A[i] = [1,2,3];
}
console.log(A);
it works fine!
[ [ 1, 2, 3 ], [ 1, 2, 3 ], [ 1, 2, 3 ] ]
What's wrong with my code?!
Update:
My original full code before the edits:
var fs = require('fs');
var input = "LPinput.txt";
var c = new Array();
var A = new Array();
var b = new Array();
var Eqin = new Array();
var MinMax;
open(input);
console.log(c);
console.log(A);
console.log(b);
console.log(Eqin);
console.log(MinMax);
function open(filename) {
if (fs.existsSync(filename)) {
var data = fs.readFileSync(filename).toString().split("\n");
analyse(data);
} else {
console.log("ERROR: File doesnt exist!");
}
}
function analyse(data) {
//clean up whitespaces
for (i in data) {
data[i] = data[i].replace(/\s/g, '');
}
//check LP type & clean up
if (data[0].substring(0,3) == "max") {
MinMax = 1;
data[0] = data[0].replace("max","");
} else if (data[0].substring(0,3) == "min") {
MinMax = -1;
data[0] = data[0].replace("min","");
} else {
console.log("ERROR: Invalid format!");
return;
}
//check constraints format & clean up
if ( data[1].substring(0,4) != "s.t.") {
console.log("ERROR: Invalid format!");
return;
} else {
data[1] = data[1].replace("s.t.","");
}
//get variables
var variables = data[data.length-1].split(",");
var last = variables[variables.length-1];
variables[variables.length-1] = last.substring(0,last.indexOf(">"));
//get number of constraints
var constraints = data.length-2;
c = getCoeff(0);
//===============================
//I JUST NEED TO POPULATE A TO FINISH THIS
for (var i=0; i<constraints; i++) {
A[i] = getCoeff(i+1);
}
//===============================
for (var i=1; i<data.length-1; i++) {
var end = data[i].length;
var start = end;
while (data[i].charAt(start) != "=") {
start = start - 1;
}
b[i-1] = parseInt(data[i].substring(start+1,end));
if (data[i].charAt(start-1) == "<") {
Eqin[i-1]=-1;
} else if (data[i].charAt(start-1) == ">") {
Eqin[i-1]=1;
} else {
Eqin[i-1]=0;
}
}
function getCoeff(row) {
var coeff = new Array();
for (i in variables) {
var pos = data[row].indexOf(variables[i]);
if ((data[row].charAt(pos-1) == "+") || (pos-1 < 0)) {
coeff[i]=1;
} else if (data[row].charAt(pos-1) == "-") {
coeff[i]=-1;
} else if (data[row].charAt(pos-1) == "*") {
var end = pos-1;
var start = end;
while ( (start > -1) && (data[row].charAt(start) != "+") && (data[row].charAt(start) != "-") ) {
start = start - 1;
}
coeff[i] = parseInt((data[row].substring(start,end)));
}
}
return coeff;
}
}
LPinput.txt:
max 2*x1+x2-4*x3-15
s.t.-3*x1+2*x2-x3>=5
2*x1-3*x2+2*x3<=9
x1-x2+3*x3<=5
x1,x2,x3>=0
Update #2:
Console output:
[ 2, 1, -4 ]
[ [ -3, 2, -1 ] ]
[ 5, 9, 5 ]
[ 1, -1, -1 ]
1
It should be:
[ 2, 1, -4 ]
[ [ -3, 2, -1 ],[ 2, -3, 2 ],[ 1, -1, 3 ]]
[ 5, 9, 5 ]
[ 1, -1, -1 ]
1
Here is the real problem:
you are using an i variable in your outer scope.
for (var i=0; i<constraints; i++) {
A[i] = getCoeff(i+1);
}
When you go inside the getCoef you have this for loop
for (i in variables) {
and since you have not declared the i here, it uses the same i declared in the outer scope. After the first run of the for loop (which fills the first row of A), i is changed to "0" as opposed to the numeric value 0. Therefore the condition of the for loop is no longer valid and it exits the loop.
There you go!
In my case, I got last 2 populated. Anyways, if you run loop from 0, you better write
A[i] = getCoeff(i+1);
OR
you run that loop starting from 1 to less than equals 3.
In your code:
A = new Array(3);
you should declare varaibles, and initialising an array with a length is usually unnecessary. Also, variables starting with a capital letter are, by convention, reserved for construtors (though some use variable names in all capitals to represent constants).
Consider using an array initialiser:
var a = [];
for (var i=0; i<3; i++) {
Initialising arrays in the following loop is a bit useless as you replace them in the next loop:
a[i] = [];
}
In the next loop, i is needlessly declared again (there is no block scope in javascript). It is common to use a different variable in these cases (though re-using i has no ill effects, it's just not liked):
for (var j=0; j<3; j++) {
a[j] = getCoeff(j + 1);
}
So creating a getCoeff function that just returns an array of the value passed to it (purely for testing):
function getCoeff(v){
return [v,v,v];
}
"works":
console.log(a.join(' - ')); // 1,1,1 - 2,2,2 - 3,3,3
Ok, consider this:
I have a big array containing arrays, -1, a and b.
The -1 means the field is empty:
var board = [
[-1,-1, a],
[-1,-1, b],
[ b,-1, a]
]
Now i want to check smaller arrays agains this:
var solutions = [
[
[1, 1, 1]
],
[
[1],
[1],
[1]
],
[
[1],
[0,1],
[0,0,1]
],
[
[0,0,1],
[0,1],
[1]
]
]
To see if one existing value from board match the pattern in solutions.
Does a match any of pattern?
Does b match any of the pattern?
Can any of you see a better way than making a crazy nested loop:
var q,w,e,r,t,y;
q=w=e=r=t=y=0;
for( ; q < 3; q++ ) {
for( ; w < 3; w++ ) {
for( ; e < SOLUTIONS.length; e++ ) {
.... and so on...
}
}
}
In this example I have used tic-tac-toe.
But i could be anything.
What you can do is to compile the patterns for speed. The same way as same languages allow regular expressions to be compiled for speed.
function compile(pattern) {
var code = "matcher = function(a) { return "
var first = null
for (var n = 0; n < pattern.length; n++) {
for (var m = 0; m < pattern[n].length; m++) {
if (pattern[n][m] == 0) continue
var nm = "["+n+"]["+m+"]"
if (first == null) {
code += "a" + nm + " != -1";
first = " && a" + nm + " == "
}
code += first + "a" + nm
}
}
code += "; }";
eval(code);
return matcher
}
So what is this doing?
For example
compile([[1],[0,1],[0,0,1]]).toString()
will create the following function
"function (a) { return a[0][0] != -1 && a[0][0] == a[0][0] && a[0][0] == a[1][1] && a[0][0] == a[2][2]; }"
So how do you use it?
To match positions on your board use it as follows
var patterns = solutions.collect(function(each) { return compile(each); })
var matches = patterns.any(function(each) { return each(board); })
NB, the very last snipped above assumes you're using one of the many popular higher-order programming libraries, as for example lodash, to provide collect and any functions on the array prototype, if not use plain old for loops instead.
Very interesting question. +1 :) Here is my take on this.
Check my fiddle http://jsfiddle.net/BuddhiP/J9bLC/ for full solution. I'll try to explain the main points in here.
I start with a board like this. I've used 0 instead of -1 because its easier.
var a = 'a', b = 'b';
var board = [
[a, 0, a],
[b, b, b],
[a, 0, a]
];
My Strategy is simple.
Check if any of the rows has the same player (a or b), if so we have a winner.
Else, Check if any of the columns has the same player
Else, Check if diagonals has a player
Those are the three winning cases.
First I created a function which can take set of rows (Ex: [a,0,b]), and check if entire row contains the same value, and if that value is not zero (or -1 in your case).
checkForWinner = function () {
lines = Array.prototype.slice.call(arguments);
// Find compact all rows to unique values.
var x = _.map(lines, function (l) {
return _.uniq(l);
});
// Find the rows where all threee fields contained the same value.
var y = _.filter(x, function (cl) {
return (cl.length == 1 && cl[0] !== 0);
});
var w = (y.length > 0) ? y[0] : null;
return w;
};
Here I take unique values in a row, and if I can find only one unique value which is not ZERO, the he is the winner.
If there is no winner in the rows, I then check for columns. In order to reuse my code, I use _.zip() method to transform columns into rows and then use the same function above to check if we have a winner.
var board2 = _.zip.apply(this, board);
winner = checkForWinner.apply(this, board2);
If I still don't find a winner, time to check the diagonals. I've written this function to extract two diagonals from the board as two rows, and use the same checkForWinner function to see if diagonals are dominated by any of the players.
extractDiagonals = function (b) {
var d1 = _.map(b, function (line, index) {
return line[index];
});
var d2 = _.map(b, function (line, index) {
return line[line.length - index - 1];
});
return [d1, d2];
};
Finally this is where I actually check the board for a winner:
// Check rows
winner = checkForWinner.apply(this, board);
if (!winner) {
var board2 = _.zip.apply(this, board);
// Check columns, now in rows
winner = checkForWinner.apply(this, board2);
if (!winner) {
var diags = extractDiagonals(board);
// Check for the diagonals now in two rows.
winner = checkForWinner.apply(this, diags);
}
}
If any of you wonder why I use apply() method instead of directly calling the function, reason is apply() allows you to pass an array elements as a list of arguments to a function.
I believe this should work for 4x4 or higher matrics as well, although I did not test them.
I had very little time to test the solution, so please let me know if you find any errors.
No, you only do need three nested loops: One to loop over your patterns, and two to loop your two-dimensional playing field:
function checkPatterns(patterns, player, field) {
pattern: for (var p=0; p<patterns.length; p++) {
for (var i=0; i<patterns[p].length; i++)
for (var j=0; j<patterns[p][i].length; j++)
if (patterns[p][i][j] && player !== field[i][j])
continue pattern;
// else we've matched all
return p;
}
// else none was found
return -1;
}
function getSolution(player)
return SOLUTIONS[checkPatterns(SOLUTIONS, player, currentBOARD)] || null;
}
OK, you might need a fourth loop for the players (players.any(getSolution)), but that doesn't make it any crazier and might be inlined for only two players as well.
However, it might be easier than formulating "pattern arrays" to construct algorithms for the patterns themselves:
function hasWon(player, field) {
vert: for (var i=0; i<field.length; i++) {
for (var j=0; j<field[i].length; j++)
if (field[i][j] !== player)
continue vert;
return "vertical";
}
hor: for (var j=0; j<field[0].length; j++) {
for (var i=0; i<field.length; i++)
if (field[i][j] !== player)
continue hor;
return "horizontal";
}
for (var i=0, l=true, r=true, l=field.length; i<l; i++) {
l == l && field[i][i] === player;
r == r && field[l-i-1][l-i-1] === player;
}
if (l || r)
return "diagonal";
return null;
}
You can have your board to be a string:
var board =
"-1,-1,a,
-1,-1,b,
b,-1,a"
and your solutions can be an array of strings (similar to the board)
var solutions = [
"1,1,1,
0,0,0,
0,0,0"
,
"1,0,0,
0,1,0,
0,0,1"
]
then for comparison, replace the -1 and b with 0s and a with 1s
then simply compare the strings
this is much faster than having 10 different loop inside another loop
You will always need loops to go trough it all. You can just make it easier to read and more flexible. The code below will work for any number of rows/cols larger then 1 and with a simple adjustment also for more then 2 players.
var board1 = [
[-1,-1, 'a'],
[-1,-1, 'b'],
['b',-1, 'a']
];
var board2 = [
['a','a', 'a'],
[-1,-1, 'b'],
['b',-1, 'a']
];
var board3 = [
[-1,'b', 'a'],
[-1,'b', 'b'],
['b','b', 'a']
];
var board4 = [
['a',-1, 'a'],
[-1,'a', 'b'],
['b',-1, 'a']
];
var solutions = [
[
[1, 1, 1]
],
[
[1],
[1],
[1]
],
[
[1],
[0,1],
[0,0,1]
],
[
[0,0,1],
[0,1],
[1]
]
];
function checkForWinner(playfield) {
var sl = solutions.length; //solutions
var bl = playfield.length; //board length
var bw = playfield[0].length; //board width
while(sl--) {
//foreach solution
var l = solutions[sl].length;
if (l==1) {
//horizontal
//loop trough board length to find a match
var tl = bl;
while(tl--) {
var pat = playfield[tl].join('')
var r = checkRow(pat)
if (r!==false)
return r;
}
} else {
//vertical or diagonal
var l1 = solutions[sl][0].length;
var l2 = solutions[sl][1].length;
if (l1==l2) {
//vertical
var tw = bw;
while (tw--) {
//loop for each column
var pat = "";
var tl = l;
while(tl--) {
//loop for vertical
pat += playfield[tl][tw];
}
var r = checkRow(pat)
if (r!==false)
return r;
}
} else {
//diagonal
var pat = "";
while(l--) {
//loop for vertical
var tw = solutions[sl][l].length;
while (tw--) {
//loop for horizontal
if (solutions[sl][l][tw]!=0)
pat += playfield[l][tw];
}
}
var r = checkRow(pat)
if (r!==false)
return r;
}
}
}
return 'no winner';
}
function checkRow(pat) {
if (!(pat.indexOf('a')>=0 || pat.indexOf('-1')>=0)) {
//only b on row. player B won
return 'B';
}
if (!(pat.indexOf('b')>=0 || pat.indexOf('-1')>=0)) {
//only a on row. player A won
return 'A';
}
return false;
}
console.log(checkForWinner(board1));
console.log(checkForWinner(board2));
console.log(checkForWinner(board3));
console.log(checkForWinner(board4));