テストコード|(JavaScript)プログラマー:クレーン式抽出ゲーム
に質問
ゲーム開発者「Jordy」はクレーン型の抽出機をモバイルゲームに変えようとしている.
ゲームの面白さを高めるために、「Jordie」は画面レイアウトとルールをゲームロジックに反映し、以下のようにします.
ゲーム画面は「1 x 1」サイズのセルからなる「NxN」サイズの正斜角メッシュで、上部にクレーン、右側にバスケットがあります.(上の図は、サイズが「5 x 5」の例を示しています).各格子間には様々なぬいぐるみがあり、ぬいぐるみのない格子は空いています.すべての人形は「1 x 1」の大きさのメッシュを占め、メッシュの一番下から順番に積み上げられます.ゲームユーザーはクレーンを左右に動かし、停止した位置から一番上の人形を持ち上げることができる.拾った人形はかごの中に積み上げられ、かごの一番下の格子から人形は順番にかごの中に積み上げられます.下の図は[1番、5番、3番の位置で人形を順番にかごに入れる様子を示しています.
同じ形の2人の人形が連続してかごに積まれると、2人の人形が爆発してかごから消えてしまいます.上の状態で、次に[5番]の位置で人形をかごに積み上げると、同じ形の人形が2つ消えてしまいます.
クレーンが作動すると、人形が挟まないことはありませんが、人形がないところでクレーンを起動すれば、何も起こりません.また、バスケットが十分大きく、すべての人形を収容できると仮定します.(図中、スクリーン表示制限は5コマのみ表示)
ゲーム画面上の格子状態の2次元配列板と人形を挟むために、起動クレーンの位置を含む配列動作をパラメータとして指定した場合、solution関数を完了し、クレーンをすべて起動させ、爆発して消えた人形の個数を返します.
制限
🎹📢I/O例
ほどく
function solution(board, moves) {
let answer = 0;
let moveIdx = 0, num = 0, stack = [];
// moves가 끝날 때까지 모든 배열을 탐색한다.
while(moveIdx < moves.length){
for(let i = 0; i < board.length; ++i){
// moveIdx에 해당하는 2차 배열 요소의 인형 정보를 대입한다.
num = board[i][moves[moveIdx]-1];
if(num !== 0){
// 스택의 가장 위의 인형와 현재 인형과 같은 경우
// 카운트 2를 증가 시키고 바구니에서 맨 위의 인형을 제거한다.
if(stack[stack.length-1] === num){
answer += 2;
stack.pop();
} else {
// 가장 위의 인형과 같지 않은 경우 바구니에 담는다.
stack.push(num);
}
// 격자 안의 인형을 뺏기 때문에 0으로 채워 인형을 비운 상태로 만든다.
board[i][moves[moveIdx]-1] = 0;
break;
}
}
moveIdx++;
}
return answer;
}
人形情報をかごの配列とかごの一番上の変数に置いて、クレーンという現在の最大の核心は人形情報を比較することです.答えはずっと2だったので、問題をよく見ていなかったので、推測と解答の問題が私の体に戻った.これは人形が消えた数ですが、1だけ数えたので問題が発生しました.だから2に変えて正解~!javascriptでは、配列インデックスのアクセスが正しくない場合、プログラムは定義されていないものを返します.そのため、コードを減らすメリットがあります.
🎈他人の解答
const transpose = matrix =>
matrix.reduce(
(result, row) => row.map((_, i) => [...(result[i] || []), row[i]]),
[]
);
const solution = (board, moves) => {
const stacks = transpose(board).map(row =>
row.reverse().filter(el => el !== 0)
);
const basket = [];
let result = 0;
for (const move of moves) {
const pop = stacks[move - 1].pop();
if (!pop) continue;
if (pop === basket[basket.length - 1]) {
basket.pop();
result += 2;
continue;
}
basket.push(pop);
}
return result;
};
まず、私が書いた元のコードよりも速いです.スタック・ログは
[ [ 3, 4 ], [ 5, 2, 2 ], [ 1, 4, 5, 1 ], [ 3, 4 ], [ 1, 2, 1, 3 ]
transpose()
の役割を理解するためにログを撮った結果、行と列が変化し、再割り当てされました.次のビューを参照してください.[
[ 0, 0, 0, 0, 0 ], => [ 0, 0, 0, 4, 3 ],
[ 0, 0, 1, 0, 3 ], => [ 0, 0, 2, 2, 5 ],
[ 0, 2, 5, 0, 1 ], => [ 0, 1, 5, 4, 1 ],
[ 4, 2, 4, 4, 2 ], => [ 0, 0, 0, 4, 3 ],
[ 3, 5, 1, 3, 1 ] => [ 0, 3, 1, 2, 1 ]
]
非構造化割当ての解を正しく理解し適用したように.reduce
とmap
の役割は分かっていますが、さらに分析する必要があります.const transpose = matrix =>
matrix.reduce((result, row) => {
let r = row.map((_, i) => {
return [...(result[i] || []), row[i]];
})
console.log(r);
return r;
},[]
);
// 출력
[ [ 0 ], [ 0 ], [ 0 ], [ 0 ], [ 0 ] ]
[ [ 0, 0 ], [ 0, 0 ], [ 0, 1 ], [ 0, 0 ], [ 0, 3 ] ]
[ [ 0, 0, 0 ], [ 0, 0, 2 ], [ 0, 1, 5 ], [ 0, 0, 0 ], [ 0, 3, 1 ] ]
[
[ 0, 0, 0, 4 ],
[ 0, 0, 2, 2 ],
[ 0, 1, 5, 4 ],
[ 0, 0, 0, 4 ],
[ 0, 3, 1, 2 ]
]
[
[ 0, 0, 0, 4, 3 ],
[ 0, 0, 2, 2, 5 ],
[ 0, 1, 5, 4, 1 ],
[ 0, 0, 0, 4, 3 ],
[ 0, 3, 1, 2, 1 ]
]
上のコードを少し変更するとログを印刷し、上の出力の結果を表示できます.行ごとのインデックスに相当する1番目のデータが、新しい2番目の配列に順次追加されます.これは結果の蓄積です.アレイ内のカラムに対応する条件として認識し、2番目のアレイのmoveIndex-1
要素を使用してアクセスした場合すなわち,この方法は行でアクセスできるため,最初の配列でアクセスできる.
実行シーケンスの概要
2차 배열의 행과 열의 위치를 바꾼다.
=> POP을 생각해 요소의 순서를 반전시킨다
=> 배열에서 0을 제외시킨 새로운 배열을 반환한다.
=> 크레인 동작 만큼 탐색하며 크레인이 원하는 라인에 해당하는 행의 마지막 요소를 pop
=> 크레인이 뽑은 인형이 0이라면 다음 크레인 동작으로 넘어간다
=> 0이 아니라면 현재 크레인이 뽑은 인형과 바구니에 담겨있는 맨 위의 인형을 비교해서 같으면 맨 위의 인형을 빼고 카운트를 2증가 시킨다. 그리고 다음 크레인 동작으로 넘어간다.
=> 만약 크레인이 뽑은 인형과 바구니에 담겨있는 맨 위의 인형이 같지 않으면 바구니에 담는다.
ふ~分析終わりました参考資料とサイト(ありがとうございます)
Reference
この問題について(テストコード|(JavaScript)プログラマー:クレーン式抽出ゲーム), 我々は、より多くの情報をここで見つけました https://velog.io/@goblin820/코딩테스트-JavaScript-프로그래머스-크레인-인형뽑기-게임テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol