「10分でコーディング」で15分かかった件

これ以上かかった人は
自分はかなりプログラミングができない。
とつらい事実を認識しましょう。
http://ameblo.jp/programming/entry-10001721422.html

まぁ、そんなもんですよ。
以下、自分の回答。

package xminits;

public class Cards {
	String[] deal(int numPlayers, String deck) {
		String[] goal = new String[numPlayers];
		String cutdeck = cut(numPlayers, deck);
		for (int i = 0; i < numPlayers; i++) goal[i] = mydeck(numPlayers, i, cutdeck);
		return goal;
	}
	
	private String cut(int numPlayers, String deck) {
		return deck.substring(0, deck.length() - (deck.length() % numPlayers));
	}
	
	private String mydeck(int numPlayers, int index, String deck) {
		StringBuilder mine = new StringBuilder();
		for (int i = 0; i < deck.length(); i++) {
			if (i % numPlayers == index) mine.append(deck.charAt(i));
		}
		return mine.toString();
	}
}
  • ってか、配列定義構文とか全く頭から抜けてるw
  • 元記事の回答例はif文とローカル変数が多くて、動作が読みにくい。その点ではこちらの方に軍配が上がるはず。
  • インタフェース設計的には、プレイヤー数を受け取るコンストラクタと、デッキを受け取ってカードを配るdealメソッドを用意する方が綺麗かも。クラス名は「場」的な感じで。
    • numPlayersをインスタンス変数に格納して、dealメソッドで格納してcutメソッドとmydeckメソッドの引数から除外しても動作は同じだろうけど、確実に混乱する。不変オブジェクトとする方を選ぶ。
  • んー、「自分はかなりプログラミングができない。」は、少し煽り過ぎかなー。

というわけで、インタフェース変更

  • コンストラクタでプレイヤー数を受け取る不変オブジェクトにした。
  • 内部クラスを作って、privateメソッドを1個除去。
  • 名前付けに違和感。
    • まぁ、漸近的な設計ということで…。
package xminits;

import static org.junit.Assert.*;

import org.junit.Test;

public class CardsTest {
	@Test
	public void testDeal() {
		Cards target = new Cards(3);
		
		assertArrayEquals(new String[] {"111","222","333"}, target.deal("123123123"));
		assertArrayEquals(new String[] {"11","22","33"}, target.deal("12312312"));
		assertArrayEquals(new String[] {"", "", "" }, target.deal(""));
	}
	
}
package xminits;

public class Cards {
	private final int numPlayers;
	
	public Cards(int numPlayers) {
		this.numPlayers = numPlayers;
	}

	public String[] deal(String deck) {
		return new Deck(deck).goal;
	}
	
	private class Deck {
		final String cutDeck;
		final String[] goal;
		public Deck(String deck) {
			cutDeck = deck.substring(0, deck.length() - (deck.length() % numPlayers));
			goal = new String[numPlayers];
			for (int i = 0; i < numPlayers; i++) goal[i] = mydeck(i);
		}
		
		private String mydeck(int index) {
			StringBuilder mine = new StringBuilder();
			for (int i = 0; i < cutDeck.length(); i++) {
				if (i % numPlayers == index) mine.append(cutDeck.charAt(i));
			}
			return mine.toString();
		}
	}
}

プレイヤー数のチェック追加

コメント欄からの指摘に対応して。

package xminits;

import static org.junit.Assert.*;

import org.junit.Test;

public class CardsTest {
	@Test
	public void testDeal() {
		Cards target = new Cards(3);
		
		assertArrayEquals(new String[] {"111","222","333"}, target.deal("123123123"));
		assertArrayEquals(new String[] {"11","22","33"}, target.deal("12312312"));
		assertArrayEquals(new String[] {"", "", "" }, target.deal(""));
		
	}
	
	@Test(expected=IllegalArgumentException.class)
	public void testNoDeal() {
		Cards target = new Cards(0);
		target.deal("123123123");
	}
}
package xminits;

public class Cards {
	private final int numPlayers;
	
	public Cards(int numPlayers) {
		if (!(numPlayers > 0)) throw new IllegalArgumentException("numPlayers must be > 0");
		this.numPlayers = numPlayers;
	}
	
	public String[] deal(String deck) {
		return new Deck(deck).goal;
	}
	
	private class Deck {
		private final String cutDeck;
		private final String[] goal;
		private Deck(String deck) {
			cutDeck = deck.substring(0, deck.length() - (deck.length() % numPlayers));
			goal = new String[numPlayers];
			for (int i = 0; i < numPlayers; i++) goal[i] = mydeck(i);
		}
		
		private String mydeck(int index) {
			StringBuilder mine = new StringBuilder();
			for (int i = 0; i < cutDeck.length(); i++) {
				if (i % numPlayers == index) mine.append(cutDeck.charAt(i));
			}
			return mine.toString();
		}
	}
}