JavaScript

[checkio] Network Attack

あっつくても元気!
ぜっっっっったいにできるんだから!!!!!

ということで今日も今日とてcheckio。
今回のお題はネットワークに接続されたパソコンを侵すウィルスを流し、全てのパソコンを手中に納めるまでの時間を返す。そもそも問題の意味がわからなかった・・・
もうちょっと具体的な説明は、以下のようなフォーマットの2次元配列を引数として渡されて・・・
Screen Shot 2017-07-20 at 10.20.33.png
まず、[0][0]の位置から右下方向にある数値たちがコンピューターを表す。つまり今回は[0,8,2,1,3,2]がコンピューターたち。それぞれの数値はセキュリティの強さを表し、何分で陥落するかという指標。
ではその他の数値たちは何かというと、そのコンピューターが他のどのコンピューターと繋がっているかを表わしている。例えば最初の行で言えば、最初のコンピューターは1,3,5のインデックスのコンピューターと繋がっていて、最初のコンピューターが陥落した場合、これらの接続されたコンピューターに対して侵略が始まる。

そして最終的に完全攻略にかかった分の値を返しておしまい。頭がこんがらがってきた。

自分の回答

function capture(data) {

    //variables
    let tarPC = [];
    let infecteds = data[0];
    let prcsTime = 0;

    /* blueprint
    make use of kidNapper and take out the target numbers.
    checkout the index of infected computer.
    decrease the security one by one according to indexes.
    checking to see if infection completed respectively, if so, check out the infections again.
    checking to see if there are only 0s.
    */

    kidNapper(data, tarPC);
    while(notCompleted(tarPC)) {
        for (let i=0; i<tarPC.length; i++) {
            if (infecteds[i]==1 && tarPC[i]>0) {
                tarPC[i] -= 1;
            }
        }
        for (let i=0; i<tarPC.length; i++) {
            if (tarPC[i]==0) {
                infectionSeeker(data[i], infecteds);
                console.log(`here is the new infecteds -- ${infecteds}`);
            }
        }
        prcsTime+=1;
        console.log(`okay here we go again man -- ${prcsTime} times`);
    }


    //kidnapping the target numbers
    function kidNapper(tarArray, empArray) {
        for (let i=0; i<tarArray.length; i++) {
            empArray.push(tarArray[i][i]);
        }
    }

    //see if poor kid is infected 
    function infectionSeeker(tarArray, infArray) {
        for (let i=0; i<tarArray.length; i++) {
            if (tarArray[i]==1 && infArray[i]==0) {
                infArray[i] = 1;
            }
        }
    }        

    //see if completed
    function notCompleted(array) {
        for (let i of array) {
            if (i!=0) {
                return true;
            }
        }
        return false;
    }

    console.log(`${prcsTime} here is the time!`);
    return prcsTime;
}

while内の二つ目のforブロックのところが無駄が多いなあ。
多少なりともわかりやすいよう関数をいっぱい作るという癖があるけど、これは果たしていいのか悪いのか。
以外にもテンプレートリテラルにcheckioが対応していた。これ便利。

すごいかいとう

function nextStep(matrix, possible, current, infected)
{
    infected.push(current.index);

    possible.forEach(el => el.time -= current.time );

    let neighbours = matrix[current.index]
        .map((el, i) => {
            if (el) return { index: i, time: matrix[i][i] };
            return;})
        .filter(el => el);

    possible = possible.concat(neighbours).filter(el => infected.indexOf(el.index) == -1);

    if (possible.length){
        let nearest = possible.sort((a, b) => b.time - a.time).pop();

        return nearest.time + nextStep(matrix, possible, nearest, infected);
    }
    return 0;
}

function capture(data) {
    let current = {index: 0, time: 0},
        possible = [],
        infected = [];

    return nextStep(data, possible, current, infected);
}

ちょっと見たことのないやり方だったのでピックアップ。
んーミソはnextStepの最後のif節の中で同じ関数を呼び出してるところなのかな。
.filter(el=>el)となっているところはどうもブール値的に真となるものだけの配列を返してくれるぽい。

学び

pop()

  • 引数を指定しなければ配列の最後の要素を取り出して返す。

sort((a,b)=>b-a)

  • b-aの値が1以上ならbをaより小さい添え字に、0以下はbをaより小さければそのまま。

反省

関数の中から自分自身を呼び出してループするというのは馴染みがなかった。そのうち問題で盛り込んでみよう。