diff --git a/src/dictionary-tree.mjs b/src/dictionary-tree.mjs
index fbf9a37e8ed66a347e0a23ae3ac5d139f18a960a..291a4e7e7ead1bf7249b895a9fbe568cc15d5fac 100644
--- a/src/dictionary-tree.mjs
+++ b/src/dictionary-tree.mjs
@@ -5,12 +5,13 @@ export function buildTreeStruct(monoLineString) {
 	const stringAsArray = monoLineString.split('');
 	const rawTree = leftParser(stringAsArray);
 	const outOfScope = stringAsArray.length;
-	if (outOfScope) throw `fail to build tree from : "${monoLineString}" parsed: ${JSON.stringify(rawTree)} unparsed/failed: ${stringAsArray.join('')}`;
+	if (outOfScope) throw new Error(`fail to build tree from : "${monoLineString}" parsed: ${JSON.stringify(rawTree)} unparsed/failed: ${stringAsArray.join('')}`);
 	let lastTree, tree = rawTree;
 	do {
 		lastTree = JSON.stringify(tree);
 		tree = flattenTree(tree);
 	} while (JSON.stringify(tree) !== lastTree)
+	preRouteAlt(tree);
 	return tree;
 }
 
@@ -18,7 +19,7 @@ export function buildTreeStruct(monoLineString) {
  * leftParser stuff
  */
 function flushNoEmptyString(data) {
-	if (data.str.length) data.tree.alt[data.tree.alt.length - 1].step.push(data.str);
+	if (data.str.length) data.tree.alt[data.tree.alt.length - 1].step.push({str:data.str});
 	data.str = '';
 }
 
@@ -73,7 +74,7 @@ function concatStrings(array) {
 		tree: {alt: [{step: []}]}, // Output array
 	};
 	array.forEach(e => {
-		if (isString(e)) appendToString(e, data);
+		if (isString(e)) appendToString(e.str, data);
 		else {
 			flushNoEmptyString(data)
 			data.tree.alt[data.tree.alt.length - 1].step.push(e);
@@ -87,7 +88,7 @@ function flattenTree(tree) {
 	if (isString(tree)) return tree;
 	const objType = isAlt(tree)?'alt':'step';
 	tree[objType] = tree[objType].map(flattenTree);
-	if (tree[objType].length === 0) return '';
+	if (tree[objType].length === 0) return {str:''};
 	if (tree[objType].length === 1) return tree[objType][0];
 
 	if (isAlt(tree)) {
@@ -102,7 +103,7 @@ function flattenTree(tree) {
 }
 
 function isString(element) {
-	return typeof element === 'string';
+	return typeof element === 'object' && typeof element.str === 'string';
 }
 
 function isStep(element) {
@@ -121,18 +122,63 @@ function trivialDedup(tree) {
 }
 
 export function serialize(treeStruct) {
-	if (isString(treeStruct)) return treeStruct;
+	if (isString(treeStruct)) return treeStruct.str;
 	if (isStep(treeStruct)) return treeStruct.step.map(serialize).join('');
 	if (isAlt(treeStruct)) return `(${treeStruct.alt.map(serialize).join('|')})`;
 	throw new Error(`Error: how to serialize ${JSON.stringify(treeStruct)} RAW: ${treeStruct}`);
 }
+function preRouteAlt(treeStruct){
+	if (isString(treeStruct)) {
+		treeStruct.altCount =1;
+		treeStruct.indexCost=1;
+		return 1;
+	}
+	if (isAlt(treeStruct)) {
+		treeStruct.altCount = treeStruct.alt.reduce((acc, cur) => acc + preRouteAlt(cur), 0);
+		treeStruct.indexCost = treeStruct.altCount-1;
+		return treeStruct.altCount;
+	}
+	if (isStep(treeStruct)) {
+		treeStruct.altCount = treeStruct.step.reduce((acc, cur) => acc * preRouteAlt(cur), 1);
+		// last alt indexCost*1, previous alt group indexCost * last alt altCount, firstAltGroup * nextAltGroup * nextAltGroup... * lastAltGroup
+		let weigth = 1;
+		for(let i = treeStruct.step.length-1;i>=0;i--){
+			const step = treeStruct.step[i];
+			if (isAlt(step)){
+				step.alt.forEach(alt=>applyCostWeigth(alt,weigth));
+				weigth*=step.altCount;
+			}
+		}
+		treeStruct.indexCost = treeStruct.altCount;
+		return treeStruct.altCount;
+	}
+}
+function applyCostWeigth(tree,weigth){
+	tree.indexCost*=weigth;
+	if (isStep(tree)) tree.step.forEach(subTree=>applyCostWeigth(subTree,weigth));
+	if (isAlt(tree)) tree.alt.forEach(subTree=>applyCostWeigth(subTree,weigth));
+}
 
 export function altCount(treeStruct) {
-	if (isString(treeStruct)) return 1;
-	if (isStep(treeStruct)) return treeStruct.step.reduce((acc, cur) => acc * altCount(cur), 1);
-	if (isAlt(treeStruct)) return treeStruct.reduce((acc, cur) => acc + altCount(cur), 0);
+	return treeStruct.altCount;
 }
 
-export function getAlternative(altNumber, tree) {
-	return 'abc';
+export function getAlternative(altIndex, tree) {
+	const refAltIndex = {index:altIndex};
+	return _getAlternative(refAltIndex, tree);
+}
+export function _getAlternative(refAltIndex, tree) {
+	if (isString(tree)) return tree.str;
+	if (isStep(tree)) {
+		return tree.step.map(subTree =>_getAlternative(refAltIndex, subTree) ).join('');
+	}
+	if (isAlt(tree)){
+		for (const altTree of tree.alt){
+			// Keep me for debug case
+			// Keep console.debug(`In ${serialize(tree)}  ${refAltIndex.index} < ${altTree.indexCost} ${refAltIndex.index < altTree.indexCost?'choose':'avoid'} ${serialize(altTree)}`);
+			if(refAltIndex.index < altTree.indexCost) return _getAlternative(refAltIndex, altTree);
+			else refAltIndex.index -= altTree.indexCost;
+		}
+	}
+	throw new Error(`index out of bound : ${refAltIndex.index+altCount(tree)}/${altCount(tree)} in ${serialize(tree)}`);
 }
diff --git a/src/dictionary-tree.test.mjs b/src/dictionary-tree.test.mjs
index 8fd0f4c695e8ebf8261d9c45aae5640cafb4867d..b84f43769ae8d50b9e81a6e87c2cd48e61760342 100644
--- a/src/dictionary-tree.test.mjs
+++ b/src/dictionary-tree.test.mjs
@@ -5,7 +5,7 @@ const buildTreeThenSerialize = str => app.serialize(app.buildTreeStruct(str));
 
 test('simple string still simple string', t => t.is(buildTreeThenSerialize('abc'), 'abc'));
 test('(a|b) alt still (a|b)', t => t.is(buildTreeThenSerialize('(a|b)'), '(a|b)'));
-test('a)b throw', t => t.throws(() => buildTreeStruct('a)b')));
+test('a)b throw', t => t.throws(()=>app.buildTreeStruct('a)b')));
 // Ok to be permissive test('(a throw',t=>t.throws(()=>buildTreeStruct('(a')));
 // Ok to be permissive test('a|b throw',t=>t.throws(()=>buildTreeStruct('a|b')));
 test('(|b) keep empty choice', t => t.is(buildTreeThenSerialize('(|b)'), '(|b)'));
@@ -17,9 +17,25 @@ test('build complexe tree with (|) pattern', t => t.is(buildTreeThenSerialize('(
 test('serialize incorrect tree throw', t => t.throws(() => app.serialize({plop: ['a']})));
 
 
-const exampleTree = () => app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')
-test.skip('mono altCount', t => t.is(app.altCount(app.buildTreeStruct('ipsum')), 1));
-test.skip('simple altCount', t => t.is(app.altCount(app.buildTreeStruct('(lore|ipsu)m')), 2));
-test.skip('multi altCount', t => t.is(app.altCount(app.buildTreeStruct('(a|b|c)(d|e|f)g(h|i|j|k)')), 36));
-test.skip('multi level tree altCount', t => t.is(app.altCount(app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')), 9));
-test.skip('getAlternative 0', t => t.is(app.getAlternative(0, exampleTree()), 'abc'));
+test('mono altCount', t => t.is(app.altCount(app.buildTreeStruct('ipsum')), 1));
+test('simple altCount', t => t.is(app.altCount(app.buildTreeStruct('(lore|ipsu)m')), 2));
+test('multi altCount', t => t.is(app.altCount(app.buildTreeStruct('(a|b|c)(d|e|f)g(h|i|j|k)')), 36));
+test('multi level tree altCount', t => t.is(app.altCount(app.buildTreeStruct('a(b(c|d)|e(f|g|h)ij(k|l)|@@@@m)')), 9));
+
+const exampleTree = () => app.buildTreeStruct('a(b(c|d)|e(f|g(h|i)|j)kl(m|n(o|p)|q(r|s)|t)|(u|v)w)');
+console.log(JSON.stringify(exampleTree()));
+console.log(app.serialize(exampleTree()));
+test('getAlternative 0', t => t.is(app.getAlternative(0, exampleTree()), 'abc'));
+test('getAlternative 1', t => t.is(app.getAlternative(1, exampleTree()), 'abd'));
+test('getAlternative 2', t => t.is(app.getAlternative(2, exampleTree()), 'aefklm'));
+test('getAlternative 3', t => t.is(app.getAlternative(3, exampleTree()), 'aefklno'));
+test('getAlternative 4', t => t.is(app.getAlternative(4, exampleTree()), 'aefklnp'));
+test('getAlternative 5', t => t.is(app.getAlternative(5, exampleTree()), 'aefklqr'));
+test('getAlternative 6', t => t.is(app.getAlternative(6, exampleTree()), 'aefklqs'));
+test('getAlternative 7', t => t.is(app.getAlternative(7, exampleTree()), 'aefklt'));
+test('getAlternative 8', t => t.is(app.getAlternative(8, exampleTree()), 'aeghklm'));
+test('getAlternative 9', t => t.is(app.getAlternative(9, exampleTree()), 'aeghklno'));
+test('getAlternative 14', t => t.is(app.getAlternative(14, exampleTree()), 'aegiklm'));
+test('getAlternative 20', t => t.is(app.getAlternative(20, exampleTree()), 'aejklm'));
+test.skip('getAlternative 26', t => t.is(app.getAlternative(26, exampleTree()), 'aqr'));
+test('getAlternative 999 throw', t => t.throws(()=>app.getAlternative(999, exampleTree())));