MediaWiki:BreedingCalculator.js

/* * Initial setup functions */

$(document).ready(function {                  eval(document.getElementById("breedingcalculatordata").innerHTML);        buildDataLists;  	setMenuOptions;      });

function buildDataLists {	window.specific_offspring_list = []; window.specific_parent_pairs = []; window.specific_color_offspring = []; window.dragon_ids = []; window.max_individual_colors = 0; window.offspring_color_groups = buildOffspringIndex(breeds); window.parent_color_groups = buildParentIndex(breeds); window.parent_color_pools = []; window.minor_colors = []; window.recessive_colors = []; window.mixed_colors = []; window.counted_colors = []; for (var color_key in parent_color_groups) {		parent_color_pools.push(color_key.split(",")); }

for (var dragon_id in breeds) {		dragon_ids.push(dragon_id); var dragon_colors = breeds[dragon_id].colors; var specific_offspring = breeds[dragon_id].specificoffspring; var specific_parents = breeds[dragon_id].specificparents; var specific_colors = breeds[dragon_id].specificcolors; // Create a list of key = specific offspring, value = list of parents that generate it, if any exist if (specific_offspring) {						for (var index in specific_offspring) {				if (!specific_offspring_list[specific_offspring[index]]) {					specific_offspring_list[specific_offspring[index]] = []; }				specific_offspring_list[specific_offspring[index]].push(dragon_id); }		}		// Create a list of key = offspring, value = specific parent pairs for the given offspring, if any exist if (specific_parents) {			var offspring_parent_pairs = []; for (var parent_pair_list in specific_parents) {				var parent_pair = specific_parents[parent_pair_list]; offspring_parent_pairs.push(parent_pair); }			specific_parent_pairs[dragon_id] = offspring_parent_pairs; }		// Build the required colors list based on special color rules if (specific_colors && specific_colors.length > 0) {			breeds[dragon_id].requiredcolors = specific_colors; specific_color_offspring.push(dragon_id); }		else {			if (dragon_colors.length == 1) {				breeds[dragon_id].requiredcolors = getColorComponents(dragon_colors[0]); }			else {				breeds[dragon_id].requiredcolors = filterColors(dragon_colors, "recessive"); }		}		var dragon_requiredcolors = breeds[dragon_id].requiredcolors; var num_colors = dragon_colors.length; if (num_colors > max_individual_colors) {			max_individual_colors = num_colors; }	}	for (var color in allColors) {		var color_type = getColorType(allColors[color]); if (color_type == "minor") {			minor_colors.push(allColors[color]); }		else if (color_type == "recessive") {			recessive_colors.push(allColors[color]); }		else if (color_type == "mixed") {			mixed_colors.push(allColors[color]); }		else if (color_type == "counted") {			counted_colors.push(allColors[color]); }	} }

function setMenuOptions {	var menu1 = document.getElementById("breeddragons_dragon1choices"); var menu2 = document.getElementById("breeddragons_dragon2choices"); var menu3 = document.getElementById("findparents_dragonchoices"); for (var dragon_id in breeds) {		var dragon_name = breeds[dragon_id].name; var new_option_1 = document.createElement("option"); new_option_1.text = dragon_name; menu1.add(new_option_1); var new_option_2 = document.createElement("option"); new_option_2.text = dragon_name; menu2.add(new_option_2); var new_option_3 = document.createElement("option"); new_option_3.text = dragon_name; menu3.add(new_option_3); }	document.getElementById("breeddragons").style.display = "inline"; document.getElementById("findparents").style.display = "inline"; }

/* * Content display functions */

function displayHTML(text, id) {  var newNode = document.createElement("p"); newNode.innerHTML = text; document.getElementById(id).appendChild(newNode); }

function clearContentField(name) {	var contentField = document.getElementById(name); while (contentField.hasChildNodes) {		contentField.removeChild(contentField.firstChild); } }

/* * Button events */ function breedButtonClicked {	getBreedingOutcome; }

function findParentsButtonClicked {	getPossibleParents; }

function getBreedingOutcome {		var contentSection = "content_breeddragons"; clearContentField(contentSection); var menu1 = document.getElementById("breeddragons_dragon1choices"); var menu2 = document.getElementById("breeddragons_dragon2choices"); var id1 = dragon_ids[menu1.selectedIndex]; var id2 = dragon_ids[menu2.selectedIndex]; var dragon1Name = breeds[id1].name; var dragon2Name = breeds[id2].name; var parent1_eligibility = getBreedingEligibilityParameters(id1); var parent2_eligibility = getBreedingEligibilityParameters(id2); var parent1_breedable = parent1_eligibility[0]; var parent2_breedable = parent2_eligibility[0]; if (parent1_breedable && parent2_breedable) {		var handler = new HtmlOutput(contentSection); var parent1_specific_offspring = breeds[id1].specificoffspring; var parent2_specific_offspring = breeds[id2].specificoffspring; var parent1_normal = (parent1_specific_offspring && parent1_specific_offspring.length > 0) ? false : true; var parent2_normal = (parent2_specific_offspring && parent2_specific_offspring.length > 0) ? false : true; if (parent1_normal && parent2_normal) {			var possible_offspring = buildBreedList(id1, id2); var outcome_table = renderOutcomeTable(handler, possible_offspring, dragon1Name, dragon2Name); handler.output(outcome_table); }		else {			var output = []; if (!parent1_normal) {				output.push(getSpecificOffspringExplanation(handler, dragon1Name, parent1_specific_offspring)); }			if (!parent2_normal) {				if (!(id2 == id1)) {					output.push(getSpecificOffspringExplanation(handler, dragon2Name, parent2_specific_offspring)); }			}			for (var str in output) {				displayHTML(output[str], contentSection); }		}	}	else {		var output = []; if (!parent1_breedable) {					output.push(getBreedingEligibilityExplanation(dragon1Name, parent1_eligibility[1])); }		if (!parent2_breedable) {			if (!(id2 == id1)) {				output.push(getBreedingEligibilityExplanation(dragon2Name, parent2_eligibility[1])); }		}		for (var str in output) {			displayHTML(output[str], contentSection); }	}	var bottomCoordinate = document.getElementById(contentSection).offsetTop; window.scroll(0, bottomCoordinate); }

function getPossibleParents {	var contentSection = "content_findparents"; clearContentField(contentSection); var menu = document.getElementById("findparents_dragonchoices"); var dragon_id = dragon_ids[menu.selectedIndex]; var dragon_name = breeds[dragon_id].name; var eligibility = getOffspringEligibilityParameters(dragon_id); var breedable = eligibility[0]; if (breedable) {				var possible_parents = buildParentList(dragon_id); var all_color_parents = possible_parents[0]; var some_color_parents = possible_parents[1]; var specific_parents = possible_parents[2]; var handler = new HtmlOutput(contentSection); var all_color_parent_table = ""; var some_color_parent_table = ""; var specific_parent_table = ""; if (all_color_parents.length > 0) {						all_color_parent_table = renderAllColorParentTable(handler, all_color_parents, dragon_name); }		if (some_color_parents.length > 0) {			some_color_parent_table = renderSomeColorParentTable(handler, some_color_parents, dragon_name); }		if (specific_parents && specific_parents.length > 0) {			specific_parent_table = renderSpecificParentTable(handler, specific_parents, dragon_name); }		handler.output([all_color_parent_table, some_color_parent_table, specific_parent_table].join('')); }	else {		displayHTML(getOffspringEligibilityExplanation(dragon_name, eligibility[1]), contentSection); }	var bottomCoordinate = document.getElementById(contentSection).offsetTop; window.scroll(0, bottomCoordinate); }

/* * Breeding functions */

function buildOffspringIndex(breeds) { var index = {}; function addBreed(key, value) { if (!index[key]) { index[key] = []; }       index[key].push(value); }   for (var id in breeds) { var breed = breeds[id]; var colors = []; if (breed.specificcolors && breed.specificcolors.length > 0) {			colors = getSortedColors(breed.specificcolors); }		else {			colors = getSortedColors(breed.colors); }		addBreed(colors.join(','), id); }   for (var key in index) { var value = index[key]; value.sort(function (a,b) {           var breed_a = breeds[a];            var breed_b = breeds[b];            if (breed_a.rarity == breed_b.rarity) {                return strcmp(breed_a, breed_b);            }            return breed_a.rarity - breed_b.rarity;        }); }   return index; }

function buildParentIndex(breeds) { var index = {}; function addBreed(key, value) { if (!index[key]) { index[key] = []; }       index[key].push(value); }   for (var id in breeds) { var breed = breeds[id]; var colors = getSortedColors(breed.colors); var filtered_colors = filterColors(colors, "recessive"); if (filtered_colors.length > 0) {			colors = filtered_colors; }		addBreed(colors.join(','), id); }   for (var key in index) { index[key] = filterParentGroup(index[key], "specificoffspring"); index[key].sort(function (a,b) {           var breed_a = breeds[a];            var breed_b = breeds[b];            if (breed_a.rarity == breed_b.rarity) {                return strcmp(breed_a, breed_b);            }            return breed_a.rarity - breed_b.rarity;        }); }   return index; } function buildBreedList(dragon1_id, dragon2_id) {				var dragon1_colors = breeds[dragon1_id].colors; var dragon2_colors = breeds[dragon2_id].colors; var outcome_colors = getBreedingOutcomeColors(dragon1_colors, dragon2_colors); var possible_offspring = new Array; for (var offspring in specific_parent_pairs) {		var offspring_parent_pairs = specific_parent_pairs[offspring]; for (var pairs in offspring_parent_pairs) {			var parent_pair = offspring_parent_pairs[pairs]; var parent1_id = parent_pair[0]; var parent2_id = parent_pair[1]; if (listsMatch([parent1_id, parent2_id], [dragon1_id, dragon2_id])) {				possible_offspring.push(offspring); }		}	}	for (var index in specific_color_offspring) {		var offspring_id = specific_color_offspring[index]; var breed = breeds[offspring_id]; var breed_colors = breed.colors; // Check if specific color offspring is a pure, which has some special inclusive breeding rules if (breed_colors.length == 1) {			var specific_colors = breed.specificcolors; var color_pool = getSortedColors(getMergedList(dragon1_colors, dragon2_colors)); if (!listContainsElements(color_pool, specific_colors)) {				if (color_pool.length == 1) {					if (color_pool[0] == "diamond") {						// Include as offspring of pure diamond pool possible_offspring.push(offspring_id); }					else if (breed_colors[0] == color_pool[0]) {						// Include as offspring of pure same color pool possible_offspring.push(offspring_id); }				}				else if (color_pool.length == 2 && color_pool[1] == "diamond") {					if (breed_colors[0] == color_pool[0]) {						// Include as offspring of pure + diamond pool possible_offspring.push(offspring_id); }					else {						var color_type = getColorType(color_pool[0]); if (color_type == "minor") {							var color_components = getColorComponents(color_pool[0]);

if (!(listsMatch(color_components, specific_colors)) && 							listContainsElements(color_components, [breed_colors[0]])) {								// Include as pure component result of minor + diamond pool possible_offspring.push(offspring_id); }						}					}				}			}		}				}	for (var i = 0; i < outcome_colors.length; i++) {		var key = outcome_colors[i].join(','); var color_group = offspring_color_groups[key]; if (color_group) {					for (var j = 0; j < color_group.length; j++) {				possible_offspring.push(color_group[j]); }		}	}	return mergeSort(possible_offspring, "offspring_colors"); }

function getBreedingOutcomeColors(dragon1_colors, dragon2_colors) {	var color_pool = filterColors(getSortedColors(getMergedList(dragon1_colors, dragon2_colors)), "recessive"); var out = []; // Make a copy of the color pool for interior modification purposes var virtual_pool = color_pool.slice(0); // Need to preserve this before adding virtual colors from minor colors // Diamond needs the true color total, not the total with virtual colors added var true_color_total = color_pool.length; var combinations_to_remove = []; if (true_color_total == 1) {		if (virtual_pool[0] == "diamond") {			for (var i = 0; i < allColors.length; i++) {				if (getColorType(allColors[i]) != "recessive") {					out.push([allColors[i]]); }			}				}			else if (getColorType(virtual_pool[0]) == "minor") {			out.push(virtual_pool); var color_components = getColorComponents(virtual_pool[0]); for (var index in color_components) {				out.push([color_components[index]]); }		}		else {			out.push(virtual_pool); }	}	else {		var present_minor_colors = getPresentMinorColors(color_pool); for (var i = 0; i < present_minor_colors.length; i++) {			var color_components = getColorComponents(present_minor_colors[i]); for (var j = 0; j < color_components.length; j++) {				if (!listContainsElements(virtual_pool, [color_components[j]])) {					virtual_pool.push(color_components[j]); // Different minor colors may share a component // The presence of enough of these different minor colors would mean that this combination is not supposed to be removed // Ex: A pool with mythic (red + yellow) and pink (red + white) should produce Justice (red + pink) if (!otherMinorsProvideColor(virtual_pool, present_minor_colors[i], color_components[j])) {						combinations_to_remove.push(getSortedColors([color_components[j], present_minor_colors[i]])); }				}			}		}	}	// Sort according to colors in preparation for the combinations step virtual_pool = getSortedColors(virtual_pool); var max_colors = Math.max(virtual_pool.length, max_individual_colors); var virtual_pool_combos = new Array; for (var i = 1; i < max_colors; i++) {		virtual_pool_combos.push(combinations(virtual_pool, i + 1)); }	for (var i = 0; i < virtual_pool_combos.length; i++) {		for (var j = 0; j < virtual_pool_combos[i].length; j++) {			out.push(virtual_pool_combos[i][j]); }	}	// Add all colors that qualify based on the number of colors in the true pool for (var i = 0; i < counted_colors.length; i++) {		var total_color_req = colorCountRequirements[counted_colors[i]]; if (true_color_total >= total_color_req) {			out.push([counted_colors[i]]); }	}	if (virtual_pool.length >= 2) {		// Add all mixed colors that qualify based on the present color components in the virtual pool for (var i = 0; i < mixed_colors.length; i++) {			var required_colors = getColorComponents(mixed_colors[i]); if (listContainsElements(virtual_pool, required_colors)) {				out.push([mixed_colors[i]]); }		}		// Add all minor colors that qualify based on the present color components in the virtual pool for (var i = 0; i < minor_colors.length; i++) {			var required_colors = getColorComponents(minor_colors[i]); if (listContainsElements(virtual_pool, required_colors)) {				out.push([minor_colors[i]]); }		}	}	// Add all color groups that qualify for plain diamond hybrid pools if (color_pool.length == 2 && color_pool[1] == "diamond") {		if (getColorType(color_pool[0]) == "minor") {						// Minor diamond hybrid pools also add pures of the minor color's components var color_components = getColorComponents(color_pool[0]); for (var i = 0; i < color_components.length; i++) {				out.push([color_components[i]]); }		}		else {			out.push([color_pool[0]]); }	}	// Some hybrids were added incorrectly with the virtual colors. Remove them. for (var i = out.length - 1; i >= 0; i--) {		for (var j = 0; j < combinations_to_remove.length; j++) {									if (out[i].length >= 2 && listContainsElements(out[i], combinations_to_remove[j])) {								out.splice(i, 1); break; // Any given dragon needs only to be removed once }		}	}	// Collect the combinations of recessive colors included or not included var possible_recessive_combinations = []; for (var i = 0; i < recessive_colors.length; i++) {					var r_combos = combinations(recessive_colors, i + 1); for (var j = 0; j < r_combos.length; j++) {			possible_recessive_combinations.push(r_combos[j]); }	}	var recessive_pools = []; for (var i = 0; i < out.length; i++) {		for (var j = 0; j < possible_recessive_combinations.length; j++) {							var recessive_pool = getSortedColors(getMergedList(out[i], possible_recessive_combinations[j])); if (!listsMatch(out[i], recessive_pool)) {				recessive_pools.push(recessive_pool); }		}	}	for (var i = 0; i < recessive_pools.length; i++) {		out.push(recessive_pools[i]); }   return out; }

function buildParentList(dragon_id) {	var all_color_parents = []; // Parents that can be paired with anything to generate the desired offspring var some_color_parents = []; // Parents that must be paired together to generate the desired offspring var specific_parents = breeds[dragon_id].specificparents; // A specific parent pair required to breed the desired offspring var dragon_colors = breeds[dragon_id].colors; var dragon_color_req = breeds[dragon_id].requiredcolors; if (dragon_colors.length == 1 && dragon_colors[0] != "diamond" && getColorType(dragon_color_req[0]) != "recessive") {		// Single color dragons have special interactions with Diamond or single color pools of their own color // Pair the pure diamonds together var pure_diamond_group = parent_color_groups["diamond"]; some_color_parents.push([pure_diamond_group, pure_diamond_group]); // Disclude standard minor pures from this group but not special ones like Atlas if (getColorType(dragon_colors[0]) != "minor" ||		!(listsMatch(dragon_color_req, getColorComponents(dragon_colors[0])))) {			var pure_color_group = parent_color_groups[dragon_colors[0]]; var pure_and_diamond_group = parent_color_groups[dragon_colors[0] + ",diamond"]; // Pair the pure same colors together some_color_parents.push([pure_color_group, pure_color_group]); // Pair all the pure same colors and pure diamonds together some_color_parents.push([pure_color_group, pure_diamond_group]); if (pure_and_diamond_group) {				// Pair the pures and diamond hybrids together some_color_parents.push([pure_color_group, pure_and_diamond_group]); some_color_parents.push([pure_diamond_group, pure_and_diamond_group]); some_color_parents.push([pure_and_diamond_group, pure_and_diamond_group]); }		}		// Check for special condition where pure minor color or minor color + diamond pools produce component pures for (var i = 0; i < minor_colors.length; i++) {			if (dragon_colors[0] != minor_colors[i]) {				var components = getColorComponents(minor_colors[i]); for (var j = 0; j < components.length; j++) {					if (dragon_colors[0] == components[j]) {						// Collect the possible parents for plain minor color + diamond pools var minor_color_group = parent_color_groups[minor_colors[i]]; var minor_and_diamond_group = parent_color_groups[minor_colors[i] + ",diamond"]; some_color_parents.push([minor_color_group, minor_color_group]); some_color_parents.push([minor_color_group, pure_diamond_group]); if (minor_and_diamond_group) {							// Pair the parents together some_color_parents.push([minor_color_group, minor_and_diamond_group]); some_color_parents.push([pure_diamond_group, minor_and_diamond_group]); some_color_parents.push([minor_and_diamond_group, minor_and_diamond_group]); }						break; }				}			}		}	}	if (dragon_color_req.length == 1) {		if (getColorType(dragon_color_req[0]) == "recessive") {			// Recessive colors do not count towards color requirements // Do nothing! }		else if (dragon_color_req[0] == "diamond") {			var pure_diamond_group = parent_color_groups["diamond"]; // Pair the pure diamonds together some_color_parents.push([pure_diamond_group, pure_diamond_group]); // Get all pairs for 4+ color groups var four_color_group = []; var max_colors = allColors.length; var desired_num_colors = 4; var r_vals = []; for (var i = desired_num_colors; i < max_colors; i++) {				var vals = getPairRValues(i, max_individual_colors); if (vals.length > 0) {					r_vals.push(vals); }			}

for (var i = 0; i < r_vals.length; i++) {				for (var j = 0; j < r_vals[i].length; j++) {					var left_val = r_vals[i][j][0]; var right_val = r_vals[i][j][1]; var left_combos = combinations(allColors, left_val); var right_combos; var avoid_repeats = false; if (left_val == right_val) {						right_combos = left_combos; avoid_repeats = true; }					else {									right_combos = combinations(allColors, right_val); }					var combined_four_pairs = getCombinedPairs(left_combos, right_combos, avoid_repeats); for (var pair in combined_four_pairs) {						var left_colors = combined_four_pairs[pair][0]; var right_colors = combined_four_pairs[pair][1]; if (getMergedList(left_colors, right_colors).length >= 4) {							var left_color_key = left_colors.join(','); var right_color_key = right_colors.join(','); var left_color_group = parent_color_groups[left_color_key]; var right_color_group = parent_color_groups[right_color_key]; if (left_color_group && right_color_group) {								some_color_parents.push([left_color_group, right_color_group]); }						}					}				}			}		}	}	else {		var candidates = getParentCandidateColors(dragon_color_req); var all_color_candidates = candidates[0]; var some_color_candidates = candidates[1]; var partial_color_pairs = combinations(some_color_candidates, 2); for (var pool in all_color_candidates) {			var desired_pool = all_color_candidates[pool]; var key = all_color_candidates[pool].join(','); var group = parent_color_groups[key]; all_color_parents.push(group); }		for (var i = 0; i < partial_color_pairs.length; i++) {			// Get the color pools for each group in the pair var pool1 = partial_color_pairs[i][0]; var pool2 = partial_color_pairs[i][1]; // Make sure that pools are ordered with left <= right var ordered_pools = mergeSort([pool1, pool2], "color_pools"); // Get the lookup keys for each color pool var left_key = ordered_pools[0].join(','); var right_key = ordered_pools[1].join(','); // Get the groups corresponding to the lookup keys var left_group = parent_color_groups[left_key]; var right_group = parent_color_groups[right_key]; var combined_pool = getMergedList(pool1, pool2); if (listContainsElements(combined_pool, dragon_color_req)) {							some_color_parents.push([left_group, right_group]); }			else {				if (completedByMinors(combined_pool, dragon_color_req)) {					some_color_parents.push([left_group, right_group]); }			}		}	}

var specific_offspring_parents = []; for (var index in specific_offspring_list[dragon_id]) {		specific_offspring_parents.push([specific_offspring_list[dragon_id][index]]); }	all_color_parents = getMergedList(specific_offspring_parents, all_color_parents); possible_parents = [all_color_parents, mergeSort(some_color_parents, "parent_pairs"), mergeSort(specific_parents, "parent_pairs")]; return possible_parents; }

function getEligibleParents(color_group) {	// Only add parents that can breed to the list var eligible_parents = []; for (var i = 0; i < color_group.length; i++) {				var breed_id = color_group[i]; if (getBreedingEligibilityParameters(breed_id)[0]) {			eligible_parents.push(breed_id); }	}	return eligible_parents; }

function getBreedingEligibilityParameters(id) {	// State whether a parent can breed, the reason (if not), and the parent's id	var params = [true, "", id]; var colors = breeds[id].colors; if (colors.length == 1 && colors[0] == "heart") {		params[0] = false; params[1] = "pureheart"; }	return params; }

function getBreedingEligibilityExplanation(dragon_name, reason) {	var reason_text = ""; if (reason == "pureheart") {		reason_text = "pure Heart color dragons cannot breed. Any successful attempts are the result of a glitch."; }	return "*** The " + dragon_name + " Dragon cannot be used as a parent because " + reason_text + " ***"; }

function getOffspringEligibilityParameters(id) {		var params = [true, "", id]; if (breeds[id].expired) {		params[0] = false; params[1] = "expired"; }	else if (breeds[id].goal) {		params[0] = false; params[1] = "goal"; }	else if (breeds[id].crafted) {		params[0] = false; params[1] = "crafted"; }	return params; }

function getOffspringEligibilityExplanation(dragon_name, reason) {	var reason_text = ""; if (reason == "expired") {		reason_text = "The " + dragon_name + " Dragon is an expired limited dragon. You may not breed it at this time."; }	else if (reason == "goal") {		reason_text = "The " + dragon_name + " Dragon cannot be acquired through breeding. You must unlock it with a goal."; }	else if (reason == "crafted") {		reason_text = "The " + dragon_name + " Dragon cannot be acquired through breeding. You must craft it in the Spell Shop."; }	return ("*** " + reason_text + " ***"); }

function getSpecificOffspringExplanation(handler, dragon_name, offspring) {	var offspring_list = handler.renderGroupLinks(offspring); return ("*** Pairing the " + dragon_name + " Dragon with any other dragon will always result in " + offspring_list + " as offspring. ***"); }

function getParentType(id) {		if (breeds[id].specificoffspring && breeds[id].specificoffspring.length > 0) {		return "specificoffspring"; }	return "normal"; }

function filterColors(color_pool, type_to_filter) {	// Add only colors without the specified filter type to the list

var filtered_pool = []; for (var i = 0; i < color_pool.length; i++) {						if (getColorType(color_pool[i]) != type_to_filter) {					filtered_pool.push(color_pool[i]); }	}	return filtered_pool; }

function filterParentGroup(group, type_to_filter) {	var filtered_group = []; for (var i = 0; i < group.length; i++) {		var id = group[i]; var type = getParentType(id); if (type != type_to_filter) {			filtered_group.push(id); }	}	return filtered_group; }

function getPresentMinorColors(pool) {	var present_minor_colors = []; for (var i = 0; i < minor_colors.length; i++) {		if (listContainsElements(pool, [minor_colors[i]])) {			present_minor_colors.push(minor_colors[i]); }	}	return present_minor_colors; }

function filterPresentMinorColors(pool, color_to_filter) {	var filtered_minor_colors = pool.slice(0); for (var i = 0; i < filtered_minor_colors.length; i++) {		if (filtered_minor_colors[i] == color_to_filter) {			filtered_minor_colors.splice(i, 1); }	}	return filtered_minor_colors; }

function comboRequiresColor(color, desired_pool) {	var color_req = getColorComponents(color); if (listContainsElements(desired_pool, color_req)) {	  return true; }	return false; }

function completedByMinors(combined_pool, required_colors) {	// Does the pool fulfill the requirements with the presence of its minor colors? var present_minor_colors = getPresentMinorColors(combined_pool);

if (requirementsMatchMinor(present_minor_colors, required_colors)) {			// Pool contains a minor color that fulfills all the color requirements return true; }

// Collect the combinations of minor colors splitting or not splitting var possible_split_combinations = []; for (var i = 0; i < present_minor_colors.length; i++) {		var r_combos = combinations(present_minor_colors, i + 1); for (var j = 0; j < r_combos.length; j++) {			possible_split_combinations.push(r_combos[j]); }	}	for (var i = 0; i < possible_split_combinations.length; i++) {		var colors_to_split = possible_split_combinations[i]; var split_pool = combined_pool.slice(0); for (var j = 0; j < colors_to_split.length; j++) {						split_pool = filterPresentMinorColors(getSplitColorPool(split_pool, colors_to_split[j]), colors_to_split[j]); }		if (listContainsElements(split_pool, required_colors)) {						return true; }	}	return false; }

function otherMinorsProvideColor(pool, minor_to_compare, color_to_find) {	var other_minor_colors = filterPresentMinorColors(getPresentMinorColors(pool), minor_to_compare); for (var i = 0; i < other_minor_colors.length; i++) {		var color_components = getColorComponents(other_minor_colors[i]); for (var j = 0; j < color_components.length; j++) {			if (color_components[j] == color_to_find) {				return true; }		}	}

return false; }

function isMinorDiamondHybridPool(pool) {	if (pool.length == 2 && listContainsElements(pool, ["diamond"])) {		pool = getSortedColors(pool); if (getColorType(pool[0]) == "minor" && pool[1] == "diamond") {			return true; }		else {			return false; }	}	return false; }

function requirementsMatchMinor(present_minor_colors, required_colors) {	for (var i = 0; i < present_minor_colors.length; i++) {		var color_req = getColorComponents(present_minor_colors[i]); if (listsMatch(color_req, required_colors)) {			return true; }	}	return false; }

function getSplitColorPool(pool, desired_color) {	// Colors only split if the desired color is a minor color var color_type = getColorType(desired_color); if (color_type == "minor") {		var substituted_pool = pool.slice(0); // Make a copy for modification purposes var color_components = getColorComponents(desired_color);

for (var i = 0; i < substituted_pool.length; i++) {			if (pool[i] == desired_color) {				substituted_pool.splice(i, 1); for (var j = 0; j < color_components.length; j++) {					if (!listContainsElements(substituted_pool, [color_components[j]])) {						substituted_pool.push(color_components[j]); }				}				break; }		}		return getSortedColors(substituted_pool); }	return pool; }

function getParentCandidateColors(desired_colors) {	var out = []; var all_color_candidates = []; var partial_color_candidates = []; for (var i = 0; i < parent_color_pools.length; i++) {		if (listContainsElements(parent_color_pools[i], desired_colors)) {			all_color_candidates.push(parent_color_pools[i]); }		else {			var contains_some_colors = false; for (var j = 0; j < desired_colors.length; j++) {				if (listContainsElements(parent_color_pools[i], [desired_colors[j]])) {					contains_some_colors = true; break; }			}			var handle_minor_colors = false; var colors_to_handle = []; for (var j = 0; j < minor_colors.length; j++) {				var color_components = getColorComponents(minor_colors[j]); if (listContainsElements(parent_color_pools[i], [minor_colors[j]])) {					for (var k = 0; k < color_components.length; k++) {						if (listContainsElements(desired_colors, [color_components[k]])) {						  handle_minor_colors = true; colors_to_handle.push(minor_colors[j]); break; }					}				}							}			if (handle_minor_colors) {				if (completedByMinors(parent_color_pools[i], desired_colors)) {										all_color_candidates.push(parent_color_pools[i]); }				else {					partial_color_candidates.push(parent_color_pools[i]); }			}			else if (contains_some_colors) {				partial_color_candidates.push(parent_color_pools[i]); }		}			}	out = [all_color_candidates, partial_color_candidates]; return out; }

/* * Computation functions */ function combinations(arr, n) { var out = []; function rec(chosen, numconsidered) {       if (chosen.length >= n) 		{ out.push(chosen.slice(0)); } 		else if (n - chosen.length <= arr.length - numconsidered) {           chosen.push(arr[numconsidered]); rec(chosen, numconsidered+1); chosen.pop; rec(chosen, numconsidered+1); }   }    rec([], 0); return out; }

function getPairRValues(num_vals, r_limit) {		var r_vals = new Array;

// Finds each way to form num_vals by adding up two numbers where r_limit is the max value for a single number

// Base case if (num_vals == 1) {		return 1,1; }	for (var i = 1; i <= num_vals / 2; i++) {		if (num_vals - i <= r_limit) {			r_vals.push([i,(num_vals - i)]); }	}	return r_vals; }

function getCombinedPairs(left_list, right_list, avoid_repeats) {	var combined_list = []; if (avoid_repeats) {		for (var i = 0; i < left_list.length; i++) {			for (var j = i; j < right_list.length; j++) {				combined_list.push([left_list[i], right_list[j]]); }		}			}	else {		for (var i = 0; i < left_list.length; i++) {			for (var j = 0; j < right_list.length; j++) {				combined_list.push([left_list[i], right_list[j]]); }		}	}	return combined_list; }

/* * List manipulation functions */

function getMergedList(list1, list2) {		var merged_list = []; if (list1.length == 0) {		return list2; }	else if (list2.length == 0) {		return list1; }	for (var i = 0; i < list1.length; i++) {		if (!(listContainsElements(merged_list, [list1[i]]))) {					merged_list.push(list1[i]); }	}	for (var i = 0; i < list2.length; i++) {		if (!(listContainsElements(merged_list, [list2[i]]))) {					merged_list.push(list2[i]); }	}	return merged_list; }

function sortListByRarity(list_to_sort) {	var sorted_list = new Array; var separated_list = new Array; separated_list.push(new Array); // Common index = 0 separated_list.push(new Array); // Rare index = 1 separated_list.push(new Array); // Super Rare index = 2 separated_list.push(new Array); // Ultra Rare index = 3 for (var i = 0; i < list_to_sort.length; i++) {		var rarity = breeds[list_to_sort[i]].rarity; separated_list[rarity - 1].push(list_to_sort[i]); }	for (var i = 0; i < separated_list.length; i++) {				for (var j = 0; j < separated_list[i].length; j++) {			sorted_list.push(separated_list[i][j]); }	}			return sorted_list; }

function getSortedColors(colors) {		var sorted_colors = new Array; for (var i = 0; i < allColors.length; i++) {		for (var j = 0; j < colors.length; j++) {									if (colors[j] == allColors[i]) {								sorted_colors.push(colors[j]); break; }		}	}			return sorted_colors; }

function mergeSort (values, type) {	if (values && values.length > 1) // List requires sorting {					var split_num = parseInt(values.length / 2); var remainder = values.length % 2; var left = new Array; var right = new Array; for (var i = 0; i < split_num; i++) {			left.push(values[i]); right.push(values[i + split_num]); }		if (remainder > 0) // Odd number of values {			right.push(values[values.length - 1]); }		left = mergeSort(left, type); right = mergeSort(right, type); values = merge(values, left, right, type); }	return values; }

function merge(values, left, right, type) {	var n = 0; // index of values var l = 0; // index of left var r = 0; // index of right while (l < left.length && r < right.length) {		if (compareValues(left[l], right[r], type) <= 0) // left < right {						values[n] = left[l]; l++; }		else // right < left {					values[n] = right[r]; r++; }		n++; }	// One of the subarrays has been exhausted. Copy over the remaining elements. while (l < left.length) {		values[n] = left[l]; l++; n++; }	while (r < right.length) {		values[n] = right[r]; r++; n++; }	return values; }

/* * Comparison functions */

function listContainsElements(list, required_elements) {	for (var i = 0; i < required_elements.length; i++) {		var found = false; for (var j = 0; j < list.length; j++) {			if (list[j] == required_elements[i]) {				found = true; break; }		}		if (!found) {			return false; }	}	return true; }

function listsMatch(list1, list2) {	if (list1.length == list2.length) {		var num_to_match = list1.length; var matches = 0; for (var i = 0; i < num_to_match; i++) {			for (var j = 0; j < num_to_match; j++) {									if (list1[i] == list2[j]) {										matches++; break; }			}		}		if (matches == num_to_match) {						return true; }	}	return false; }

function compareValues (first_val, second_val, type) {			if (type == "colors") {		return compareColors(first_val, second_val); }	else if (type == "color_pools") {		return compareColorPools(first_val, second_val); }	else if (type == "offspring_colors") {		return compareOffspringColors(first_val, second_val); }	else if (type == "parent_pairs") {		return compareParentPairs(first_val, second_val); }	else if (type == "pair_pool_size") {		return comparePairPoolSize(first_val, second_val); }	return 0; }

function compareColors(first_color, second_color) {			var first_color_val = getColorValue(first_color); var second_color_val = getColorValue(second_color);

if (first_color_val < second_color_val) {		return -1; }	else if (first_color_val > second_color_val) {		return 1; }	return 0; }

function compareColorPools(first_pool, second_pool) {			var first_pool_size = first_pool.length; var second_pool_size = second_pool.length; // Smallest color pools first if (first_pool_size < second_pool_size) {		return -1; }	else if (first_pool_size > second_pool_size) {		return 1; }	// Color pool sizes are equal for (var i = 0; i < first_pool_size; i++) {		var comparison = compareColors(first_pool[i], second_pool[i]); if (comparison < 0) {			return -1; }		else if (comparison > 0) {					return 1; }	}	return 0; }

function compareOffspringColors(first_val, second_val) {	var first_pool = breeds[first_val].colors; var second_pool = breeds[second_val].colors; return compareColorPools(first_pool, second_pool); }

function compareParentPairs(first_val, second_val) {	// Get the color pools from the parent pair lists in each value var first_left_parent_pool = breeds[first_val[0][0]].colors; var first_right_parent_pool = breeds[first_val[1][0]].colors; var second_left_parent_pool = breeds[second_val[0][0]].colors; var second_right_parent_pool = breeds[second_val[1][0]].colors; // Size of color pool takes priority over colors in the pool for comparison var size_comparison = comparePairPoolSize([first_left_parent_pool, first_right_parent_pool], 	                     [second_left_parent_pool, second_right_parent_pool], "pair_pool_size"); if (size_comparison != 0) {		return size_comparison; }	// Color pool size check has passed; now compare the values of the colors in the pool var left_comparison = compareColorPools(first_left_parent_pool, second_left_parent_pool); if (left_comparison < 0) {		return -1; }	else if (left_comparison > 0) {		return 1; }	var right_comparison = compareColorPools(first_right_parent_pool, second_right_parent_pool); if (right_comparison < 0) {		return -1; }	else if (right_comparison > 0) {		return 1; }	return 0; }

function comparePairPoolSize(first_val, second_val) {	var first_left_size = first_val[0].length; var first_right_size = first_val[1].length; var second_left_size = second_val[0].length; var second_right_size = second_val[1].length; if (first_left_size < second_left_size) {				return -1; }	else if (first_left_size > second_left_size) {			return 1; }	if (first_right_size < second_right_size) {			return -1; }	else if (first_right_size > second_right_size) {			return 1; }	return 0; }

function strcmp(a,b) { if (a < b) { return -1; }   if (a > b) { return 1; }   return 0; }

/* * Dragon color functions */

function getColorValue(color) { for (var i = 0; i < allColors.length; i++) {		if (allColors[i] == color) {			return i + 1; }	}	return 0; }

function getColorType (color) { var type = complexColorTypes[color]; if (type) {		return type; }	return "major"; }

function getColorComponents (color) { var components = complexColorComponents[color]; if (components) {		return components; }  return [color]; }

function getRequiredColorAmount (color) { var amount = colorCountRequirements[color]; if (amount) {		return amount; }  return 0; }

/* * Table rendering code */ function renderOutcomeTable(handler, possible_offspring, parent1_name, parent2_name) {	var intro_text = " Breeding " + parent1_name + " with " + parent2_name + " can result in the following: "; var header_color = "#8EC3CD"; var headers = handler.joinRows([handler.wrapHeader("Dragon Name", header_color, 1, 170), handler.wrapHeader("Colors", header_color, 1, 70), 	handler.wrapHeader("Rarity", header_color, 1, 100), handler.wrapHeader("Game Display Time", header_color, 2, 100), handler.wrapHeader("Cost to Complete", header_color, 2, 100)	]); var rows = handler.joinRows(           possible_offspring.map(function (offspring) { if (getOffspringEligibilityParameters(offspring)[0]) {					var name = breeds[offspring].name; var colors = breeds[offspring].colors; var rarity = rarities[breeds[offspring].rarity - 1]; var incubation = breeds[offspring].incubation.split("_"); var incubation_display = incubation[0]; var incubation_text = incubation[1]; var incubation_cost = incubation[2]; return handler.wrapRow(						handler.joinCells([handler.wrapCell(handler.renderDragonLink(name), "center"), handler.wrapCell(handler.renderDragonColors(colors), "center"), handler.wrapCell("&nbsp &nbsp " + rarity + "&nbsp &nbsp ", "center"), handler.wrapCell(incubation_display, "right"),handler.wrapCell("&nbsp" + incubation_text, "left"), handler.wrapCell("&nbsp " + incubation_cost, "right"),handler.wrapCell(handler.urlToImage(goldImagePageSource, 20, 20), "left") ]));				}           })        );    return handler.wrapTable(handler.joinRows([intro_text, headers, rows])); }

function renderAllColorParentTable(handler, all_color_groups, target_name) {		var intro_text = " The " + target_name + " Dragon can be bred by pairing one of these dragons with any other dragon. ";

var header_color = "#8EC3CD"; var headers = handler.joinRows([handler.wrapHeader("Dragon", header_color, 1, 150), handler.wrapHeader("Colors", header_color, 1, 100)]); var all_color_parents = []; for (var group in all_color_groups) {		var parents = all_color_groups[group]; for (var parent in parents) {			all_color_parents.push(parents[parent]); }	}	mergeSort(all_color_parents, "offspring_colors"); // Make sure the all color table is sorted // Create the rows where a single parent possesses all the required colors var rows = handler.joinRows(		all_color_parents.map(function (id) { var breed_name = breeds[id].name; var colors = breeds[id].colors; return handler.wrapRow(			   handler.joinCells([handler.wrapCell(handler.renderDragonLink(breed_name), "center"), handler.wrapCell(handler.renderDragonColors(colors), "center") ]));		})	);	return handler.wrapTable(handler.joinRows([intro_text, headers, rows])); }

function renderSomeColorParentTable(handler, some_color_groups, target_name) {		var intro_text = " The " + target_name + " Dragon can be bred using one of the following pairs. "; var header_color = "#8EC3CD"; var headers = handler.joinRows([handler.wrapHeader("Group A Dragons", header_color, 1, 200), 	handler.wrapHeader("Group A Colors", header_color, 1, 100),	handler.wrapHeader("Group B Colors", header_color, 1, 100),	handler.wrapHeader("Group B Dragons", header_color, 1, 200)]);

var rows = handler.joinRows(		some_color_groups.map(function (group_pair) { var left_group = getEligibleParents(group_pair[0]); var right_group = getEligibleParents(group_pair[1]); if (left_group.length > 0 && right_group.length > 0) {				var left_colors = breeds[left_group[0]].colors; var right_colors = breeds[right_group[0]].colors; return handler.wrapRow(handler.joinCells([handler.wrapCell(handler.renderGroupLinks(left_group), "center"), handler.wrapCell(handler.renderDragonColors(left_colors), "center"), handler.wrapCell(handler.renderDragonColors(right_colors), "center"), handler.wrapCell(handler.renderGroupLinks(right_group), "center") ]));			}		})	);			return handler.wrapBorderedTable(handler.joinRows([intro_text, headers, rows])); }

function renderSpecificParentTable(handler, specific_parents, target_name) {		var intro_text = " The " + target_name + " Dragon can be bred using the following specific parents. "; var header_color = "#8EC3CD"; var headers = handler.wrapHeader("Parents", header_color, 5, 400); // Create the rows of each specific parent pair var rows = handler.joinRows(		specific_parents.map(function (parent_pair) { var parent1_id = parent_pair[0]; var parent2_id = parent_pair[1]; parent1_name = breeds[parent1_id].name; parent2_name = breeds[parent2_id].name; var parent1_colors = breeds[parent1_id].colors; var parent2_colors = breeds[parent2_id].colors; return handler.wrapRow(			   handler.joinCells([handler.wrapCell("    " + handler.renderDragonColors(parent1_colors) + "  ", "right"), handler.wrapCell(handler.renderDragonLink(parent1_name) + "       ", "left"), handler.wrapCell(" & ", "center"), handler.wrapCell("       " + handler.renderDragonLink(parent2_name), "right"), handler.wrapCell(" " + handler.renderDragonColors(parent2_colors) + "    ", "left") ]));		})	);	return handler.wrapTable(handler.joinRows([intro_text, headers, rows])); }

/* * HTML-specific output handler */

function HtmlOutput(outputElementId) {   this.outputElementId = outputElementId; this.rows = []; }

HtmlOutput.prototype.toUrl = function (link, text, title) { return "" + text + ""; }

HtmlOutput.prototype.renderDragonLink = function (breed_name) { return this.toUrl(dragonPageSource + breed_name + " Dragon", breed_name + " Dragon", breed_name + " Dragon"); }

HtmlOutput.prototype.renderGroupLinks = function(group) { var links = []; for (var dragon in group) {				var breed_name = breeds[group[dragon]].name; links.push(this.toUrl(dragonPageSource + breed_name + " Dragon", breed_name, breed_name + " Dragon")); }	if (links.length == 1) { return links[0]; }	if (links.length == 2) { return links.join(' or '); }	return links.slice(0,links.length-1).join(", ")+", or "+links[links.length-1]; }

HtmlOutput.prototype.urlToImage = function (url, width, height) { return ""; }

HtmlOutput.prototype.colorToImage = function (color) { var url = colorImageUrl[color]; if (url) { return this.urlToImage(url,20,20); } else { return "???"+color+"???"; } }

HtmlOutput.prototype.renderDragonColors = function (colors) { var dragon_colors = [];

for (var color in colors) {		dragon_colors.push(this.colorToImage(colors[color])); }   return dragon_colors.join(' '); }

HtmlOutput.prototype.wrapHeader = function (header, color, span, width) {	var header_style = "width:" + width + "px; height:50px; background-color:" + color + "; text-align: center;"; return ""+header+" "; }

HtmlOutput.prototype.wrapCell = function (cell, align) {   var cell_style = "text-align:" + align + ";"; return ""+cell+" "; }

HtmlOutput.prototype.wrapRow = function (row) {   return " "+row+" " }

HtmlOutput.prototype.joinRows = function (rows) {   return rows.join(''); }

HtmlOutput.prototype.joinCells = function (cells) {   return cells.join(''); }

HtmlOutput.prototype.joinLines = function (lines) {   return lines.join(' '); }

HtmlOutput.prototype.joinLinesDouble = function (lines) {   return lines.join('  '); }

HtmlOutput.prototype.wrapTable = function (content) {   	var table_style = "background-color:#CCCCCC; border-collapse: collapse;"; return " "; }

HtmlOutput.prototype.wrapBorderedTable = function (content) {   	var table_style = "background-color:#CCCCCC; border-collapse: collapse;"; return " "; }

HtmlOutput.prototype.output = function (value) {      document.getElementById(this.outputElementId).innerHTML = value; }