8つのボール問題、さらに書き直し(JavaScript手習い)

上の続き。

次の指摘をもらって、手直ししました。ありがとうございます。

  1. プロパティ名が大仰すぎ。
  2. thisを返すな。newし忘れたらグローバルオブジェクトが返ってくるから危険。ボール来るわーと思ってミット構えてたら世界が落ちてくる感じ。ヤバイ。
  3. newする必要がない。はずせ。

構造体のようなもの(Ball)を作る必要もない、ともいわれましたが、

var balls = [{index:0, weight:5}, {index:1, weight:5}/* , ... 略 */];

のように、使用側のコードでプロパティ名を何度も書いてオブジェクトを生成するのが嫌で、維持しました。その際に1の指摘を受けたので、おとなしくプロパティ名を短くしました。

書き直した解答その2

googleBall.js

var _ = require("./lib/underscore-min.js");

exports.Ball = function(i, w){
	return {i: i, w: w};
};

exports.solve = function(balls){

	// 3, 3, 2ずつ取り出して比べる
	var right = balls.slice(0, 3);
	var left = balls.slice(3, 6);
	var other = balls.slice(6, 8);

	var rsum = _.reduce(right, function(memo, num){ return memo + num.w; }, 0);
	var lsum = _.reduce(left, function(memo, num){ return memo + num.w; }, 0);

	if(lsum === rsum){
		// 3, 3が釣り合ったら残り2つで比べる
		return other[0].w < other[1].w ? other[1].i : other[0].i;
	}
	// 右(左)の方が重ければ右(左)から1つずつ取り出して比べる
	if(lsum < rsum){
		return comp(right);
	} else {
		return comp(left);
	}

	function comp(targets){
		if(targets[0].w === targets[1].w){
			return targets[2].i;
		}
		return targets[0].w < targets[1].w ? targets[1].i : targets[0].i;
	};
};

テストコード。

var assert = require('assert');
var gb = require("./googleBall.js");

describe('8つのボールから1つだけ重いボールのインデックスを返す', function(){
    it('重いボールが先頭にある場合', function(){
        var Ball = gb.Ball;
    	var answer = gb.solve([Ball(0, 7), Ball(1, 5), Ball(2, 5), Ball(3, 5), Ball(4, 5), Ball(5, 5), Ball(6, 5), Ball(7, 5)]);
        assert(answer === 0);
    })
    it('重いボールが中央付近にある場合', function(){
        var Ball = gb.Ball;
        var answer = gb.solve([Ball(0, 5), Ball(1, 5), Ball(2, 5), Ball(3, 5), Ball(4, 7), Ball(5, 5), Ball(6, 5), Ball(7, 5)]);
        assert(answer === 4);
    })
    it('重いボールが末尾にある場合', function(){
        var Ball = gb.Ball;
        var answer = gb.solve([Ball(0, 5), Ball(1, 5), Ball(2, 5), Ball(3, 5), Ball(4, 5), Ball(5, 5), Ball(6, 5), Ball(7, 7)]);
        assert(answer === 7);
    })
});

ほかの方のコードもどうぞ