既に良い感じの回答が出てますが、
もう少し深掘りして原理の方を解説します。
JavaScript
1console.log([1, 2, 3] === [1, 2, 3]); // false
2
3var a = [1, 2, 3];
4var b = a;
5console.log(a === b); // true
不思議ですね、どうしてこういう動きするか説明出来ますか?
多分説明出来ないと思います。
JavaScriptの世界では、{name: "hoge"}
というオブジェクトや、[1, 2, 3]
という配列を宣言した時、初めてメモリ空間上にオブジェクト/配列が生成されます。
変数や引数として使う時は全て「メモリ空間のアドレス番地」でやりとりされます(参照やポインタ等と表現されます)
変数に代入された時、目には見えませんしとりだせませんが、オブジェクト/配列の実体ではなく、アドレス番地という数値が代入されていると考えてください。
[1, 2, 3] === [1, 2, 3]
の結果がfalse
になるのは、比較演算子でオブジェクトや配列を比較した場合、配列そのものではなく、「アドレス番地」での比較になります。
1行内に配列宣言が2個ありますので、メモリ空間上に配列2個作られ、それぞれのアドレス番地が帰って来ます。
各々のアドレス番地は当然異なる為、比較結果もfalse
になるというカラクリになっています。
これがどう質問文に影響してくるかを見ていきましょう。
JavaScript
1 var n = 11;
2 var array = [];
3
4 for(var j = 0; j < n; j++) {
5 array.push(0);
6 }
このvar array = [];
で配列を1個生成しました。
for文で配列にぽこぽこ0を挿入していき0を11個含む配列に成長しました。
JavaScript
1 for(var i = 0; i < n; i++) {
2 maze.push(array);
3 }
問題の箇所がこれです。
maze.push(array)
としていますが、arrayには配列のアドレス番地が入ってます。
つまり、11回繰り返した結果mazeは[arrayのアドレス番地, arrayのアドレス番地, arrayのアドレス番地, ...]
という配列になります。
理想はメモリ空間上にmazeとarrayのコピー11個、計12個の配列が存在してmaze
の中身は[array1, array2, array3 ...]
という風になって欲しいはずですが、
実際にはmazeとarrayの計2個の配列しか存在していません。
そりゃarrayの値を1個弄ったら全部変化するよね……という訳で、そのコードは欠陥となるわけです。
配列は基本的に宣言したタイミングで作られるので、
素直に解決するなら多重ループに変更してこういったコードになるでしょう。
JavaScript
1function main (n) {
2 n = 11;
3 var maze = [];
4 for (var i = 0; i < n; i++) {
5 // ループの中で新しい配列を作って育てる
6 var array = [];
7 for (var j = 0; j < n; j++) {
8 array.push(0);
9 }
10 maze.push(array);
11 }
12}
ですが、ループやif文のネストって理解が難しくなるのでできれば避けたいですよね。
そういった時に、メモリ空間上に配列の複製を作ってしまう手法があり、
これをシャローコピーやディープコピーと呼びます。
詳しい記事を見つけたので、具体的な方法はこちらを読んでみてください。
JavaScript の配列のシャローコピーに使えるメソッド3つ(+ 1つ)とその使い分け - おかかウェブ
回答文に上がっている解決策はこのシャローコピーやディープコピーの手法です。
(この手法はどちらもちゃんとGASで使える事を確認しています)
JSON.parse(JSON.stringify(...))
: 簡易的なディープコピー
array.slice()
: スマートなシャローコピー
【おまけ】【修正版】関数作ってワンライナーで頑張る
一撃で行けると思ったのですが、どうもGASはJavaScript1.6ベースでできており、
ECMAScript6の便利機能は全滅、5も動作が怪しいので、注意してください。
参考サイト
そもそも配列の要素を一気につくるイディオムがES6に頼る事になるので、
それに頼れないとなると一気に微妙化しますが、こんな感じで配列作る関数を用意して動作させることになります。
下記のコードは調査済みで動作します…が、array.slice()
の方が明らかに筋が良いですね。参考までにどうぞ。
JavaScript
1function myFunction() {
2 var n = 11;
3 var array = function (num) {
4 var arr = [];
5 for (var i = 0; i < num; i++) {
6 arr.push(0);
7 }
8 return arr;
9 }
10 var maze = array(n).map(function () { return array(n); });
11 Logger.log(maze);
12}
13
14// [18-12-07 17:36:31:549 JST] [[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]]