Algorithm Not Properly Killing Go Pieces When Air To Bottom Right - javascript

I've created an algorithm to determine which pieces have been killed in a game of Go. For my algorithm, pieces are stored in a 2D array of rows and columns (from 0-8, as I am using a 9x9 board). Each piece is also an array, where:
piece[0] is the color of the piece, either "empty", "black", or "white".
piece[1] is irrelevant.
piece[2] is a boolean of whether or not it has liberty (initially set to true if an empty square and false if there is a piece there).
piece[3] is whether or not it has been iterated over in the algorithm yet. All pieces start with this as true.
Here is the algorithm for discerning which pieces have liberty:
let oldBoard = 0;
while (board != oldBoard) {
oldBoard = board;
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (board[row][col][2] && !board[row][col][3]) {
board[row][col][3] = true;
if (row != 0 && (board[row][col][0] == "empty" || board[row][col][0] == board[row-1][col][0])) { board[row-1][col][2] = true; }
if (row != 8 && (board[row][col][0] == "empty" || board[row][col][0] == board[row+1][col][0])) { board[row+1][col][2] = true; }
if (col != 0 && (board[row][col][0] == "empty" || board[row][col][0] == board[row][col-1][0])) { board[row][col-1][2] = true; }
if (col != 8 && (board[row][col][0] == "empty" || board[row][col][0] == board[row][col+1][0])) { board[row][col+1][2] = true; }
}
}
}
}
Afterwards, it removes all pieces that are marked as not having liberty (piece[2] == false).
Everything works fine, unless the air spaces are to the bottom/right. For instance, if you put down this configuration:
Then the X-ed out piece will be captured, which it shouldn't be. But, if you put down this configuration:
Then no piece will be captured, which is the expected result.
As best as I can tell from my investigations of the bug, it seems to be that any piece that was marked as having liberty from a piece to its bottom or right is unable to give any adjacent pieces liberty.
You can find the full repository here.

I might be late on this one, but here's my idea.
As I commented, you should look at the stones as a group, instead of looking at it individually.
#maraca 's comment was very helpful. Since adjacent stones to the updated stone is affected, you could check all four adjacent pieces from the updated stone, then check each of those stones' adjacent stones and so on... until it ends. The function can look something like this.
function isGroupAlive(x, y) {
let stack = [];
let alive = false;
const check = (x, y) => {
stack.push([x, y].toString());
let cell = board[x][y];
if (x !== 0 && board[x-1][y][0] === null) alive = true;
else if (x !== 0 && board[x-1][y][0] === cell[0] && stack.includes([x-1, y].toString)) check(x-1, y);
if (x !== size-1 && board[x+1][y][0] === null) alive = true;
else if (x !== size-1 && board[x+1][y][0] === cell[0] && stack.includes([x+1, y].toString)) check(x+1, y);
if (y !== 0 && board[x][y-1][0] === null) alive = true;
else if (y !== 0 && board[x][y-1][0] === cell[0] && stack.includes([x, y-1].toString)) check(x, y-1);
if (y !== size-1 && board[x][y+1][0] === null) alive = true;
else if (y !== size-1 && board[x][y+1][0] === cell[0] && stack.includes([x, y+1].toString)) check(x, y+1);
}
check(x, y);
return alive;
}
I used a stack to keep track of already iterated stones' coordinates, but you could do something else too.

Related

I failed Javascript tech interview but I dont know why

I was only allowed to use google document for writing.
Could you please tell me what I did wrong? The recruiter wont get back to me when I asked her why I failed
Task 1:
Implement function verify(text) which verifies whether parentheses within text are
correctly nested. You need to consider three kinds: (), [], <> and only these kinds.
My Answer:
const verify = (text) => {
   const parenthesesStack = []; 
   
  for( let i = 0; i<text.length; i++ ) {
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
if(text[i] === “(”  || text[i] === “[” || text[i] === “<”  ) {
parenthesisStack.push(text[i]);
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
   parenthesisStack.pop();
} 
  };
return parenthesesStack.length ? 0 : 1;  
}
Task 2:
Simplify the implementation below as much as you can.
Even better if you can also improve performance as part of the simplification!
FYI: This code is over 35 lines and over 300 tokens, but it can be written in
5 lines and in less than 60 tokens.
Function on the next page.
// ‘a’ and ‘b’ are single character strings
function func2(s, a, b) {
var match_empty=/^$/ ;
if (s.match(match_empty)) {
return -1;
}
var i=s.length-1;
var aIndex=-1;
var bIndex=-1;
while ((aIndex==-1) && (bIndex==-1) && (i>=0)) {
if (s.substring(i, i+1) == a)
aIndex=i;
if (s.substring(i, i+1) == b)
bIndex=i;
i--;
}
if (aIndex != -1) {
if (bIndex == -1)
return aIndex;
return Math.max(aIndex, bIndex);
} else {
if (bIndex != -1)
return bIndex;
return -1;
}
};
My Answer:
const funcSimplified = (s,a,b) => {
if(s.match(/^$/)) {
return -1;
} else {
return Math.max(s.indexOf(a),s.indexOf(b))
}
}
For starters, I'd be clear about exactly what the recruiter asked. Bold and bullet point it and be explicit.
Secondly, I would have failed you from your first 'for' statement.
See my notes:
// Bonus - add jsdoc description, example, expected variables for added intention.
const verify = (text) => {
// verify what? be specific.
const parenthesesStack = [];
for( let i = 0; i<text.length; i++ ) {
// this could have been a map method or reduce method depending on what you were getting out of it. Rarely is a for loop like this used now unless you need to break out of it for performance reasons.
const closingParentheses = parenthesesStack[parenthesesStack.length - 1]
// parenthesesStack.length - 1 === -1.
// parenthesesStack[-1] = undefined
if(text[i] === “(” || text[i] === “[” || text[i] === “<” ) {
parenthesisStack.push(text[i]);
// “ will break. Use "
// would have been more performant and maintainable to create a variable like this:
// const textOutput = text[i]
// if (textOutput === "(" || textOutput === "[" || textOutput === "<") {
parenthesisStack.push(textOutput)
} else if ((closingParentheses === “(” && text[i] === “)”) || (closingParentheses === “[” && text[i] === “]”) || (closingParentheses === “<” && text[i] === “>”) ) {
parenthesisStack.pop();
// There is nothing in parenthesisStack to pop
}
};
return parenthesesStack.length ? 0 : 1;
// Will always be 0.
}
Not exactly what the intention of your function or logic is doing, but It would fail based on what I can see.
Test it in a browser or use typescript playground. You can write javascript in there too.
Hard to tell without the recruiter feedback. But i can tell that you missundertood the second function.
func2("mystrs", 's', 'm') // returns 5
funcSimplified("mystrs", 's', 'm') // returns 3
You are returning Math.max(s.indexOf(a),s.indexOf(b)) instead of Math.max(s.lastIndexOf(a), s.lastIndexOf(b))
The original code start at i=len(str) - 1 and decrease up to 0. They are reading the string backward.
A possible implementation could have been
const lastOccurenceOf = (s,a,b) => {
// Check for falsyness (undefined, null, or empty string)
if (!s) return -1;
// ensure -1 value if search term is empty
const lastIndexOfA = a ? s.lastIndexOf(a) : -1
const lastIndexOfB = b ? s.lastIndexOf(b) : -1
return Math.max(lastIndexOfA, lastIndexOfB)
}
or a more concise example, which is arguably worse (because less readable)
const lastOccurenceOf = (s,a,b) => {
const safeStr = s || '';
return Math.max(safeStr.lastIndexOf(a || undefined), safeStr.lastIndexOf(b || undefined))
}
I'm using a || undefined to force a to be undefined if it is an empty string, because:
"canal".lastIndexOf("") = 5
"canal".lastIndexOf(undefined) = -1
original function would have returned -1 if case of an empty a or b
Also, have you ask if you were allowed to use ES6+ syntax ? You've been given a vanilla JS and you implemented the equivalent using ES6+. Some recruiters have vicious POV.

Simplifying if/else expression

How do I simplify this After Effects expression so I don't list each slider separately?
What is the way to write this as an array of numbers between 1 and 5? I really appreciate any help you can provide.
targetLayer = effect("Layer Source For Grid")("Layer");
check = targetLayer.effect("Enable First ROW Control")("Checkbox");
fAj01 = thisComp.layer("BOX").effect("COLUMN control 1")("Slider");// 1st column
fAj02 = thisComp.layer("BOX").effect("COLUMN control 2")("Slider");// 2st column
fAj03 = thisComp.layer("BOX").effect("COLUMN control 3")("Slider");// 3st column
fAj04 = thisComp.layer("BOX").effect("COLUMN control 4")("Slider");// 4st column
fAj05 = thisComp.layer("BOX").effect("COLUMN control 5")("Slider");// 5st column
if(check == 0 && fAj01 == 0 && fAj02 == 0 && fAj03 == 0 && fAj04 == 0 && fAj05 == 0) {
100;
} else {
0;
}
targetLayer = effect("Layer Source For Grid")("Layer");
const numbers= = Array(5)
const check = targetLayer.effect("Enable First ROW Control")("Checkbox");
const sliders = numbers.map(num => thisComp.layer("BOX").effect("COLUMN control " + (num + 1))("Slider"))
if(check == 0 && sliders.every(slider => slider == 0)) {
100;
} else {
0;
}
not 100% sure map and .every work with expressions in AE. Here's one that uses more basic syntax
const targetLayer = effect("Layer Source For Grid")("Layer");
if (targetLayer.effect("Enable First ROW Control")("Checkbox")){
for (let i = 1; i <= 5; i++){
if (thisComp.layer("BOX").effect("COLUMN control " + i)("Slider").value !== 0){
return 0
};
}
}
100;

Filtering multiple input fields

I'm trying to create a filter with javascript with 4 input fields so I'm guessin 16 combinations of possible searches. I can search all 4 at once or 1 input at a time but for some reason when I add other statements I get wierd results. Is there a better way to implement a filter?
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if (unfilteredFloorplans[i].city == req.body.cityName &&
unfilteredFloorplans[i].building == req.body.buildingName &&
unfilteredFloorplans[i].bedrooms == req.body.minBedroom &&
unfilteredFloorplans[i].baths == req.body.maxBathroom) {
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
So now I need to write 15 more if statements? Rather than copy them in I'd like to ask if this is correct and does anyone know how you could implement this with a switch statement?
Edit: And when I say 15 more statements I mean one for if they just pick city, andother if they pick city and bedrooms etc. It just seems inefficient
A minimal fix would be to combine your "and" with "or", but note how this turns the code into a hard-to-read mess:
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if ((req.body.cityName == '' || unfilteredFloorplans[i].city == req.body.cityName) &&
(req.body.buildingName == '' || unfilteredFloorplans[i].building == req.body.buildingName) &&
(req.body.minBedroom == '' || unfilteredFloorplans[i].bedrooms == req.body.minBedroom) &&
(req.body.maxBathroom == '' || unfilteredFloorplans[i].baths == req.body.maxBathroom)) {
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
(BTW, this looks like a good exercise for combining conjunctions with disjunctions.)
Edit I'd recommend to put the filtering into a separate function, and to introduce an additional helper function. Also, use a more consistent naming and use "===" instead of "==".
function filterByEquality(formValue, dataValue) {
if (formValue === '') return true;
if (formValue === dataValue) return true;
return false;
}
function filterFloorplan(form, data) {
if (!filterByEquality(form.city, data.city)) return false;
if (!filterByEquality(form.building, data.building)) return false;
if (!filterByEquality(form.minBedrooms, data.bedrooms)) return false;
if (!filterByEquality(form.maxBathrooms, data.bathrooms)) return false;
return true;
}
var unfilteredFloorplans = floorplanJSON.floorplanData;
filteredFloorplans = [];
for (var i = 0; i < unfilteredFloorplans.length; i++) {
if (filterFloorplan(req.body, unfilteredFloorplans[i]);
console.log(unfilteredFloorplans[i].city);
filteredFloorplans.push(unfilteredFloorplans[i]);
}
}
You can reduce this code even further by learning about the Array.filter method. And you should fix the bug where for some fields should use ">=" or ">=" instead of "===". But I'll leave those things as an exercise.
Here's a simplified example of what your code may look like (in this example, I hardcoded the values representing the input choices):
var unfilteredFloorplans = [{
city: 'NY',
building: 'A',
bedrooms: 2,
baths: 1,
}];
var filteredFloorplans = unfilteredFloorplans.filter(
function(el) {
return el.city === 'NY' && el.building === 'A' && el.bedrooms >= 1 && el.baths >= 1;
}
);
console.log(filteredFloorplans);
The anonymous function being called inside the filter can be replaced with a named function like so:
function filterFloorplans(floorplan) {
return floorplan.city === 'NY' && floorplan.building === 'A' && floorplan.bedrooms >= 1 && floorplan.baths >= 1;
}
var filteredFloorplans = unfilteredFloorplans.filter(filterFloorplans);
You'll likely want to use this route since you can have any combination of the 4 input choices. As such, you'll want the filterFloorplans function to be "built-up" from other, smaller checks:
function testCity(userInputCity, floorplanCity) {
return userInputCity ? userInputCity === floorplanCity : true;
}
function filterFloorplans(floorplan) {
return testCity('NY', floorplan.city) && floorplan.building === 'A' && floorplan.bedrooms >= 1 && floorplan.baths >= 1;
}
This should be enough to get you started; feel free to comment if you get stuck

BFS on 2D grid with traceable path

the problem may be familiar, but with a little twist. I have a grid (2D array) with possible markings:
"?" - unexplored
"." - walkable
"#" - wall
"G" - goal
Every time I walk in certain direction (no diagonals), I discover 5x5 area around me. Ater I discover "G", I have to find the shortest path to the starting point.
So I am trying BFS for both scenarios. It seems to work on simple paths with one direction like:
????####
????..S#
????####
????????
????????
where the map looks like:
########
#.....S#
#.######
#......#
########
But sometimes it gets stuck when there are many possibilities for me to go. It finds "closest" (not really sure about that) "?" symbol, returns path and I go to the first coordinate and BFS from this point again. But I sometimes get stuck when I go in that direction, BFS, and algorithm finds "closer" "?" in opposite direction, then I go back and forth.
I think something is wrong with my algorithm, because paths returned for e.g. left/right differ with like 3-4 nodes.
function BFS(position,map,checked,target,avoid){
var Q = [[new Node(position.x,position.y)]];
var Path;
d=0;
while(Q.length >0){
Path = Q.shift();
vertex = Path[Path.length-1];
if(Map[vertex.y][vertex.x] == target){
return Path;
}
else if(checked[vertex.y][vertex.x] == 0){
if(vertex.x+1<C && Map[vertex.y][vertex.x+1] !="#" && checked[vertex.y][vertex.x+1] == 0){
new_path = Path.slice();
new_path.push(new Node(vertex.x+1,vertex.y));
Q.unshift(new_path);
}
if(vertex.x+1<C && Map[vertex.y][vertex.x+1] == "G"){
G_discovered = true;
G_position = new Node(vertex.x+1, vertex.y);
}
if(vertex.y+1<R && Map[vertex.y+1][vertex.x] !="#" && checked[vertex.y+1][vertex.x] == 0){
new_path = Path.slice();
new_path.push(new Node(vertex.x,vertex.y+1));
Q.unshift(new_path);
}
if(vertex.y+1<R && Map[vertex.y+1][vertex.x] == "G"){
G_discovered = true;
G_position = new Node(vertex.x, vertex.y+1);
}
if(vertex.x-1>=0 && Map[vertex.y][vertex.x-1] !="#" && checked[vertex.y][vertex.x-1] == 0){
new_path = Path.slice();
new_path.push(new Node(vertex.x-1,vertex.y));
Q.unshift(new_path);
}
if(vertex.x-1>=0 && Map[vertex.y][vertex.x-1] == "G" ){
G_discovered = true;
G_position = new Node(vertex.x-1, vertex.y);
}
if(vertex.y-1>=0 && Map[vertex.y-1][vertex.x] !="#" && checked[vertex.y-1][vertex.x] == 0){
new_path = Path.slice();
new_path.push(new Node(vertex.x,vertex.y-1));
Q.unshift(new_path);
}
if(vertex.y-1>=0 && Map[vertex.y-1][vertex.x] == "G"){
G_discovered = true;
G_position = new Node(vertex.x, vertex.y-1);
}
d++;
checked[vertex.y][vertex.x] = 1;
}
}
return "no path found"
}
Every move I read map in the Map object and every move I clear the checked array

Angular function to take row from model

I have an angularjs function whereby the hope is to take a row away from $scope.model.insuredContact using the splice function. Unfortunately right now it seems the line of code below simply returns the row that hypothetically would be taken away...if that makes any sense? Meaning it just returns the row we are try eliminate but it doesn't really take it out of the array. How to do? Any help would be most appreciated.
$scope.txtChanged = function (i) {
var x = $scope.model.insuredContact[i];
if ((x.ContactName === '' || x.ContactName == undefined) && (x.ContactEmail === '' || x.ContactEmail == undefined) && (x.ContactPhone === '' || x.ContactPhone == undefined)) {
if (i == $scope.model.insuredContact.length - 1) { return; }
$scope.model.insuredContact = $scope.model.insuredContact.splice(i, 1);
}
}

Categories