Facing Time limit exceeded error for large test cases. Any optimization suggestions would be helpful. if possible please provide links to guide on how to optimize JavaScript code for performance. Thanks in advance
using my own implementation of Queue data structure since JavaScript by default doesn't have one.
wallsAndGates(grid) {
// write your code here
class QNode {
constructor(data){
this.data = data;
this.next = null;
}
}
class Queue {
constructor() {
this.front = null;
this.rear = null;
this.length = 0;
}
enqueue(data) {
const newNode = new QNode(data);
if(this.front === null && this.rear === null) {
this.front = newNode;
this.rear = newNode;
}
else {
this.rear.next = newNode;
this.rear = newNode;
}
this.length += 1;
}
dequeue() {
if(this.front === null && this.rear === null)
return null;
else {
const data = this.front.data;
if (this.front === this.rear){
this.front = null;
this.rear = null;
}else {
this.front = this.front.next;
}
this.length -= 1;
return data;
}
}
peek() {
if (this.front === null) return null;
else return this.front.data;
}
}
const noOfRows = grid.length;
const noOfCols = grid[0].length;
const imutCord = (i, j) => `${i},${j}`;
const getCord = cord => cord.split(',').map(n => parseInt(n));
const blankAndGateNodes = new Set();
const gateNodes = new Queue();
for (let i = 0; i < noOfRows; i++){
for (let j = 0; j < noOfCols; j++){
const cord = imutCord(i, j);
if(grid[i][j] >= 0) blankAndGateNodes.add(cord);
if(grid[i][j] === 0) gateNodes.enqueue(cord);
}
}
const multiSourceBFS = (sourceQueue, visitNodes, grid) => {
const tempQueue = new Queue();
let noOfLayer = 0;
while (sourceQueue.length !== 0 || tempQueue.length !== 0){
while (sourceQueue.length !== 0){
const cord = sourceQueue.dequeue();
let i, j;
[i, j] = getCord(cord);
if(i >= 0 && j >= 0 && i < noOfRows && j < noOfCols && visitNodes.has(cord)){
visitNodes.delete(cord);
if(grid[i][j] > 0) grid[i][j] = noOfLayer;
tempQueue.enqueue(imutCord(i+1, j));
tempQueue.enqueue(imutCord(i, j+1));
tempQueue.enqueue(imutCord(i-1, j));
tempQueue.enqueue(imutCord(i, j-1));
}
}
while(tempQueue.length !== 0) sourceQueue.enqueue(tempQueue.dequeue());
noOfLayer++;
}
}
multiSourceBFS(gateNodes, blankAndGateNodes, grid);
}
lintcode link: https://www.lintcode.com/problem/663/
Related
Could you please help me to find a proper way to fix it?
Why is there an error "TypeError: Cannot read properties of undefined" for the row with gameState[move.i] = playerAi? What did I do wrong?
let scoreCounter = function() {
//....
return scores
}
function bestMove() {
let bestScore = -Infinity;
let move;
for (let i = 0; i < gameState.length; i++) {
if (gameState[i] === "") {
gameState[i] = playerAi;
let score = minimax(gameState, 0, false)
gameState[i] = "";
if (score > bestScore) {
bestScore = score;
move = {
i
};
}
}
}
gameState[move.i] = playerAi;
document.getElementById(move.i).innerHTML = playerAi;
}
//actual minimax
function minimax(gameState, depth, maximization) {
let result = scoreCounter();
if (result !== null) {
return scores;
}
if (maximization) {
let bestScore = -Infinity;
for (let i = 0; i < gameState.length; i++) {
if (gameState[i] === "") {
gameState[i] = playerAi;
let score = minimax(gameState, depth + 1, false)
gameState[i] = "";
bestScore = Math.max(score, bestScore)
}
}
return bestScore
} else {
let bestScore = Infinity;
for (let i = 0; i < gameState.length; i++) {
if (gameState[i] === "") {
gameState[i] = playerX;
let score = minimax(gameState, depth + 1, true)
gameState[i] = "";
bestScore = Math.min(score, bestScore)
}
}
return bestScore
}
}
You need to initialize the move variable, I suggest setting it to the first possible move, which in your case would be 0.
I am kind of new to this, but this is giving me a headache.
Heres my code what i am trying to solve:
function parseComponents(data: any, excelAttributesArray: string[]) {
let confs = "";
let isValues = false;
let listValues = "";
if (!data) return confs;
if (data["Part"]) {
const part = data["Part"];
excelAttributesArray.forEach((attribute) => {
let attributeValue = part[attribute];
if (attributeValue !== null) isValues = true;
if (attributeValue !== null && attributeValue.Value) {
attributeValue = attributeValue.Value;
}
listValues += attributeValue + ",";
});
const number = part["Number"];
if (isValues) {
confs += `${listValues}${number}`;
}
}
if (data["Components"] && data["Components"].length > 0) {
for (let i = 0; i < data["Components"].length; i++) {
const tmp = parseComponents(
data["Components"][i],
excelAttributesArray
);
if (tmp && tmp.length > 0)
confs += (confs.length > 0 ? "|" : "") + tmp;
}
}
return confs;
}
The confs value is returned as a string. How do i get it return as array?
Please see this leetcode solution. In the function it returns [''] which actually return an array of answer. Could someone tell me what's going on there?
[The problem is solved. Actually it will return in the middle of the code.]
https://leetcode.com/problems/remove-invalid-parentheses/discuss/154272/JavaScript-BFS-solution
function removeInvalidParentheses(s) {
let queue = new Set([s]);
while (queue.size) {
const next = new Set();
for (let v of queue) {
if (isValid(v)) {
return [...queue].filter(isValid);
}
for (let i = 0; i < v.length; i++) {
next.add(v.slice(0, i) + v.slice(i+1));
}
}
queue = next;
}
return [''];
}
function isValid(str) {
let bal = 0;
for (let ch of str) {
if (ch === '(') {
bal++;
} else if (ch === ')') {
bal--;
}
if (bal < 0) {
return false;
}
}
return bal === 0;
}
The function returns an array with a single empty string if the prior code (line 7) does not return a result. It is simply a default value so that calling code sees some result from the method.
function removeInvalidParentheses(s) {
let queue = new Set([s]);
while (queue.size) {
const next = new Set();
for (let v of queue) {
if (isValid(v)) {
return [...queue].filter(isValid);
}
for (let i = 0; i < v.length; i++) {
next.add(v.slice(0, i) + v.slice(i+1));
}
}
queue = next;
}
return [''];
}
function isValid(str) {
let bal = 0;
for (let ch of str) {
if (ch === '(') {
bal++;
} else if (ch === ')') {
bal--;
}
if (bal < 0) {
return false;
}
}
return bal === 0;
}
I am trying to build tic-tac-toe AI using min max algorithm. I was referring to this post from geekforgeeks for writing my code. But strangely when I'm using 1D array instead of 2D array by modifying the code as given below, I'm not getting the right output from findBestMove function. It is supposed to return index as 4, but it always returns 2. what am I doing wrong?
function Move(x,y){
this.row = x,
this.col = y;
};
const player = 'o', opponent = 'x';
const isMovesLeft = (board) => {
for (let i = 0; i<3; i++)
for (let j = 0; j<3; j++)
if (board[i][j]=='_')
return true;
return false;
}
const isMovesLeft2 = (board) => {
for (let i = 0; i<9; i++)
if (board[i]=='_')
return true;
return false;
}
const evaluate = (b) =>{
for (let row = 0; row<3; row++)
{
if (b[row][0]==b[row][1] &&
b[row][1]==b[row][2])
{
if (b[row][0]==player)
return +10;
else if (b[row][0]==opponent)
return -10;
}
}
for (let col = 0; col<3; col++)
{
if (b[0][col]==b[1][col] &&
b[1][col]==b[2][col])
{
if (b[0][col]==player)
return +10;
else if (b[0][col]==opponent)
return -10;
}
}
if (b[0][0]==b[1][1] && b[1][1]==b[2][2])
{
if (b[0][0]==player)
return +10;
else if (b[0][0]==opponent)
return -10;
}
if (b[0][2]==b[1][1] && b[1][1]==b[2][0])
{
if (b[0][2]==player)
return +10;
else if (b[0][2]==opponent)
return -10;
}
return 0;
}
const evaluate2 = (b) =>{
for (let row = 0; row<3; row++)
{
if (b[row]==b[row+1] &&
b[row+1]==b[row+2])
{
if (b[row]==player)
return +10;
else if (b[row]==opponent)
return -10;
}
}
for (let col = 0; col<3; col++)
{
if (b[col]==b[col+3] &&
b[col+3]==b[col+6])
{
if (b[col]==player)
return +10;
else if (b[col]==opponent)
return -10;
}
}
if (b[0]==b[4] && b[4]==b[8])
{
if (b[0]==player)
return +10;
else if (b[0]==opponent)
return -10;
}
if (b[2]==b[4] && b[4]==b[6])
{
if (b[2]==player)
return +10;
else if (b[2]==opponent)
return -10;
}
return 0;
}
const minimax = (board , depth, isMax) => {
let score = evaluate(board);
if (score == 10)
return score;
if (score == -10)
return score;
if (isMovesLeft(board)==false)
return 0;
if (isMax)
{
let best = -1000;
for (let i = 0; i<3; i++)
{
for (let j = 0; j<3; j++)
{
if (board[i][j]=='_')
{
board[i][j] = player;
best = Math.max( best,
minimax(board, depth+1, !isMax) );
board[i][j] = '_';
}
}
}
return best;
}
else
{
let best = 1000;
// Traverse all cells
for (let i = 0; i<3; i++)
{
for (let j = 0; j<3; j++)
{
if (board[i][j]=='_')
{
board[i][j] = opponent;
best = Math.min(best,
minimax(board, depth+1, !isMax));
board[i][j] = '_';
}
}
}
return best;
}
}
const minimax2 = (board , depth, isMax) => {
let score = evaluate2(board);
if (score == 10)
return score;
if (score == -10)
return score;
if (isMovesLeft2(board)==false)
return 0;
if (isMax)
{
let best = -1000;
for (let i = 0; i<9; i++)
{
if (board[i]=='_')
{
board[i] = player;
best = Math.max( best,
minimax2(board, depth+1, !isMax) );
board[i] = '_';
}
}
return best;
}
else
{
let best = 1000;
for (let i = 0; i<9; i++)
{
if (board[i]=='_')
{
board[i] = opponent;
best = Math.min(best,
minimax2(board, depth+1, !isMax));
board[i] = '_';
}
}
return best;
}
}
const findBestMove = (board) =>{
let bestVal = -1000;
let bestMove = new Move(-1,-1);
for (let i = 0; i<3; i++)
{
for (let j = 0; j<3; j++)
{
if (board[i][j]=='_')
{
board[i][j] = player;
let moveVal = minimax(board, 0, false);
board[i][j] = '_';
if (moveVal > bestVal)
{
bestMove.row = i;
bestMove.col = j;
bestVal = moveVal;
}
}
}
}
return bestMove;
}
const findBestMove2 = (board) =>{
let bestVal = -1000;
let bestMove = -1;
for (let i = 0; i<9; i++)
{
if (board[i]=='_')
{
board[i] = player;
let moveVal = minimax2(board, 0, false);
board[i]= '_';
if (moveVal > bestVal)
{
bestMove = i
bestVal = moveVal;
}
}
}
return bestMove;
}
const test = () => {
const board = [['x','_','_'],
['_','_','_'],
['_','_','_']];
const board2 = ['x','_','_',
'_','_','_',
'_','_','_'];
console.log(findBestMove(board));
console.log(findBestMove2(board2));
}
test();
When the test() is executed first function call returns best move as (1,1) but second function returns 2. It should be 4 ideally.
In function evaluate2, you loop like this:
for (let row = 0; row<3; row++)
You should loop like this
for (let row = 0; row<9; row+=3)
I am trying to create a chess AI using the chess.js library. I am using the minimax solution with Alpha-Beta pruning, but for some reason, when the program runs it continues even after the depth reaches 0. Can anyone tell me why?
var Buddha = function() {
this.movehistory = 0;
this.color = "b";
this.opp = "w";
this.minimax = function(board, depth, alpha, beta) {
console.log(depth);
if(depth === 0 || board.game_over() === true) {
console.log("Depth == 0");
return [this.eval_board(board), null]
} else {
if(board.turn() === this.color) {
var bestmove = null
var possible_moves = board.moves()
for (index = 0; index < possible_moves.length; ++index) {
var new_board = new Chess(board.fen());
new_board.move(possible_moves[index])
var mini = this.minimax(new_board, --depth, alpha, beta)
var score = mini[0];
var move = mini[1];
if(score > alpha) {
alpha = score;
bestmove = possible_moves[index];
if(alpha >= beta) {
break;
}
}
}
return [alpha, bestmove]
} else if(board.turn() === this.opp) {
var bestmove = null
var possible_moves = board.moves()
for (index = 0; index < possible_moves.length; ++index) {
var new_board = new Chess(board.fen());
new_board.move(possible_moves[index])
var mini = this.minimax(new_board, --depth, alpha, beta)
var score = mini[0];
var move = mini[1];
if(score < beta) {
beta = score;
bestmove = possible_moves[index];
if(alpha >= beta) {
break;
}
}
}
return [beta, bestmove]
}
}
}
this.eval_board = function(board) {
if(board.in_check()) {
if(board.turn() == this.opp) {
return Number.POSITIVE_INFINITY;
} else {
return Number.NEGATIVE_INFINITY;
}
} else if(board.in_checkmate()) {
if(board.turn() == this.opp) {
return Number.POSITIVE_INFINITY;
} else {
return Number.NEGATIVE_INFINITY;
}
} else if(board.in_stalemate()) {
if(board.turn() == this.opp) {
return Number.POSITIVE_INFINITY;
} else {
return Number.NEGATIVE_INFINITY;
}
}
}
this.move = function(board) {
var bestmove = this.minimax(board, 1, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY)
}
}
function minimax(board, depth, alpha, beta) {
if(depth === 0 …) { …
return …
} else {
…
for (index = 0; index < possible_moves.length; ++index) {
… minimax(new_board, --depth, alpha, beta)
// ^^
…
}
}
}
Here you're decrementing the depth in a loop. Use depth <= 0 for the base case, and/or pass depth - 1 as an argument or put the decrement statement before the loop.