기둥과 보 설치 - 2020 kakao blind recruitment
처음 wall 변수를 초기화할 때, 자바스크립트의 fill로 객체를 담은 array로 채워주었다.
문제는 wall의 배열들이 같은 배열의 reference였다는 것이다.
const wall = new Array(n + 1).fill(
new Array(n + 1).fill({ pillar: 0, bo: 0 }));
이 문제를 해결하기 위해 fill()로 임의의 값을 넣어준 후, map()을 돌면서 각 요소들을 변형시켜주었다.
const wall = new Array(n + 1)
.fill()
.map((_) => new Array(n + 1).fill().map((_) => ({ pillar: 0, bo: 0 })));
const a = [1, { hi: "hi" }];
const b = [...a];
console.log(b); //[ 1, { hi: 'hi' } ]
b[0] = 100;
b[1].hi = "bye";
console.log(a); // [ 1, { hi: 'bye' } ]
console.log(b); // [ 100, { hi: 'bye' } ]
const PILLAR = 0;
const BO = 1;
const REMOVE = 0;
const INSTALL = 1;
const getInitialWall = (n) => {
const wall = new Array(n + 1)
.fill()
.map((_) =>
new Array(n + 1).fill().map((_) => ({ pillar: false, bo: false }))
);
return wall;
};
const isValidPillar = (wall, x, y) => {
const isOnFloor = y === 0;
const isOnBo = wall[y][x].bo || (x - 1 >= 0 && wall[y][x - 1].bo);
const isOnPillar = y - 1 >= 0 && wall[y - 1][x].pillar;
return isOnFloor || isOnBo || isOnPillar;
};
const isValidBo = (n) => (wall, x, y) => {
const checkOneSideOnPillar =
y - 1 >= 0 &&
(wall[y - 1][x].pillar || (x + 1 <= n && wall[y - 1][x + 1].pillar));
const checkBothOnBo =
x - 1 >= 0 && wall[y][x - 1].bo && x + 1 < n && wall[y][x + 1].bo;
return checkOneSideOnPillar || checkBothOnBo;
};
const toggleStatusOfWall = (wall, x, y, type) => {
wall[y][x][type] = !wall[y][x][type];
};
const checkNoEffect = (validFunc, testWall, locList, n, type) => {
const passAllValidFunc = locList
.filter((loc) => loc.x >= 0 && loc.y <= n && testWall[loc.y][loc.x][type])
.every((loc) => validFunc(testWall, loc.x, loc.y));
return passAllValidFunc;
};
const removeBoIfPossible = (wall, x, y, n) => {
const boLoc = [
{ x: x - 1, y },
{ x: x + 1, y },
];
const pillarLoc = [
{ x, y },
{ x: x + 1, y },
];
toggleStatusOfWall(wall, x, y, "bo");
const noEffectOnBo = checkNoEffect(isValidBo(n), wall, boLoc, n, "bo");
const noEffectOnPillar = checkNoEffect(
isValidPillar,
wall,
pillarLoc,
n,
"pillar"
);
if (noEffectOnBo && noEffectOnPillar) {
return;
}
toggleStatusOfWall(wall, x, y, "bo");
};
const removePillarIfPossible = (wall, x, y, n) => {
const boLoc = [
{ x, y: y + 1 },
{ x: x - 1, y: y + 1 },
];
const pillarLoc = [{ x, y: y + 1 }];
toggleStatusOfWall(wall, x, y, "pillar");
const noEffectOnBo = checkNoEffect(isValidBo(n), wall, boLoc, n, "bo");
const noEffectOnPillar = checkNoEffect(
isValidPillar,
wall,
pillarLoc,
n,
"pillar"
);
if (noEffectOnBo && noEffectOnPillar) {
return;
}
toggleStatusOfWall(wall, x, y, "pillar");
};
const installIfPossible = (validFunc, wall, x, y, type) => {
if (!validFunc(wall, x, y)) {
return;
}
wall[y][x][type] = true;
};
const getFinalFrame = (wall, n) => {
const finalFrame = [];
for (let x = 0; x <= n; x++) {
for (let y = 0; y <= n; y++) {
if (wall[y][x].pillar) {
finalFrame.push([x, y, PILLAR]);
}
if (wall[y][x].bo) {
finalFrame.push([x, y, BO]);
}
}
}
return finalFrame;
};
function solution(n, build_frame) {
const wall = getInitialWall(n);
for (const [x, y, type, action] of build_frame) {
if (type === PILLAR) {
if (action === INSTALL) {
installIfPossible(isValidPillar, wall, x, y, "pillar");
} else {
removePillarIfPossible(wall, x, y, n);
}
} else {
// BO
if (action === INSTALL) {
installIfPossible(isValidBo(n), wall, x, y, "bo");
} else {
removeBoIfPossible(wall, x, y, n);
}
}
}
const finalFrame = getFinalFrame(wall, n);
return finalFrame;
}
원래 소감은 안썼지만 이 문제는 소감을 써야겠다...
이 문제는 나한테 얕은 복사와 깊은 복사
를 몰랐던 나를 아주 크게 혼내주었다.
초반에 초기화할 때, '='연산자로 할당한 배열의 요소들은 original 배열의 메모리를 참조하고 있었다. 따라서 배열에서 한 요소의 값만 바꿔도 전체 배열의 모든 값들이 변경되는 것처럼 보였다.
두 번째 위기는 배열이 깊은 복사가 된다고 생각해서 문제가 생겼다. 알고리즘 풀면서 javascript 이해가 부족했던 점을 채울 수 있어서 다행인 것 같다.