I was playing a game called Alchemy Merge, where you have to combine different elements to create a new one. It starts with 4 basic elements i.e., Air, Fire, Soil and Water and combining this we get new elements. Now, I have completed the game and simultaneously noted each entry as following
Air
Fire
Soil
Water
Heat = Air + Fire
Plant = Soil + Water
Tree = Plant + Plant
Forest = Tree + Tree
... and the list continues for roughly 400 elements. Now, I have two questions regarding this.
What is the fastest algorithm to complete the game with minimum steps?
What is the best approach to determine the depth of an element in minimum time? By the term "depth", I am referring to the number of combinations required to get the element...
depth(Water) = 0 #primary element
depth(Plant) = 1 #(soil + water)
#calculation for depth is stopped as it reaches the primary elements
As #trincot points out, here are a few more examples to clarify the "depth"
Algae = Plant + Water.
Now, to get Algae, we need 2 combinations,
1. Plant = Soil + Water
2. Algae = Plant + Water
So the depth(Algae) will be 2.
Taking another example, consider the following combinations...
Stone = Soil + Soil
Sand = Stone + Water
Glass = Sand + Fire
Time = Glass + Sand
Now, calculating depth(Time), but in reverse order...
1. Time = Sand + Glass
2. = (Stone+Water) + Glass
3. = ((Soil + Soil) + Water) + Glass
4. = ((Soil + Soil) + Water) + (Sand + Fire)
5. = ((Soil + Soil) + Water) + ((Stone+Water) + Fire)
6. = ((Soil + Soil) + Water) + (((Soil + Soil)+Water) + Fire)
So, depth(Time) = 6
Thank you.
This is a graph problem, more specifically the graph is a directed, acyclic graph (DAG),
where each node is an element, and outgoing edges go to the element(s) that are needed
to build that element. If the same element is needed multiple times, that just means there
are two edges connecting the two nodes. The "initial" four elements are represented by leaf-nodes,
as they don't have outgoing edges.
Once you have this DAG available in a practical data structure, the problem of creating a target element
comes down to traversing the dependent nodes in bottom-up fashion.
The notion of "depth" you present is actually not the term that would be used in the graph problem. You want to actually count the number of visited internal nodes in a traversal that can be executed from the target node to reach the leaves (note some nodes can be visited multiple times, and leaves don't count).
To implement an algorithm, first choose a graph data structure that is convenient to quickly find a node, so a hash table (hash map, dictionary) would be a good choice.
For each entry you could then have an array of references to child nodes, that reference the components that are needed.
We can represent such a structure in JSON format:
{
"Air": [],
"Fire": [],
"Soil": [],
"Water": [],
"Heat": ["Air", "Fire"],
"Plant": ["Soil", "Water"],
"Tree": ["Plant", "Plant"],
"Forest": ["Tree", "Tree"],
"Algae": ["Plant", "Water"],
"Stone": ["Soil", "Soil"],
"Sand": ["Stone", "Water"],
"Glass": ["Sand", "Fire"],
"Time": ["Glass", "Sand"]
}
The traversal of all paths that lead to the leaves can be done with a depth-first traversal, more specifically, with a post-order traversal.
That way the traversal will list the edges (i.e. the actions to take) in a chronological (topological) order.
Here is an implementation in JavaScript, with a run for the "Time" element:
const graph = {
"Air": [],
"Fire": [],
"Soil": [],
"Water": [],
"Heat": ["Air", "Fire"],
"Plant": ["Soil", "Water"],
"Tree": ["Plant", "Plant"],
"Forest": ["Tree", "Tree"],
"Algae": ["Plant", "Water"],
"Stone": ["Soil", "Soil"],
"Sand": ["Stone", "Water"],
"Glass": ["Sand", "Fire"],
"Time": ["Glass", "Sand"]
};
function build(target) {
if (graph[target].length == 0) { // It is a leaf
return []; // No action needed
}
let actions = [];
for (let child of graph[target]) {
actions.push(...build(child));
}
actions.push("Use " + graph[target] + " to create " + target);
return actions;
}
let actions = build("Time");
console.log(actions);
The size of the returned array of steps is what you called "depth" (6 in the example of "Time").
If you're only interested in the size and not the steps themselves, it is easy to simplify the above code to just return a step counter.
It would also be appropriate to use memoization, i.e. store calculated "depths" with each node so you would not do the calculation a second time.
Here is a version that only returns the step-count and uses memoization:
const graph = {
"Air": [],
"Fire": [],
"Soil": [],
"Water": [],
"Heat": ["Air", "Fire"],
"Plant": ["Soil", "Water"],
"Tree": ["Plant", "Plant"],
"Forest": ["Tree", "Tree"],
"Algae": ["Plant", "Water"],
"Stone": ["Soil", "Soil"],
"Sand": ["Stone", "Water"],
"Glass": ["Sand", "Fire"],
"Time": ["Glass", "Sand"]
};
const steps = {}; // Memoization of the number of steps needed for a component
function build(target) {
if (graph[target].length == 0) { // It is a leaf
return 0; // No action needed
}
if (target in steps) { // We have calculated this before
return steps[target];
}
let actionCount = 1;
for (let child of graph[target]) {
actionCount += build(child);
}
// Store for later reuse
steps[target] = actionCount;
return actionCount;
}
let actionCount = build("Time");
console.log(actionCount);
For "discovering" (i.e. building) all nodes, and to minimise the number of steps for it, we should find the "roots" of the graph, the nodes that have no parent (i.e. elements which are not used as component for another). When we have built those, we know we will have built all.
As we need to know the children, the build count, the parents for each node, it is time to create a Node class, and have these as instance properties.
Here it is an implementation and run on the larger JSON you provided:
class Node {
constructor(element) {
this.element = element;
this.children = [];
this.parents = [];
this.buildCount = 0; // Default
}
build() {
if (this.children.length > 0 && this.buildCount == 0) { // Not yet calculated
this.buildCount = 1; // Count the last step of combining the children
for (let child of this.children) {
this.buildCount += child.build();
}
}
return this.buildCount;
}
}
function solve(adjacency) {
const graph = {};
// Create a node instance for each element
for (const element in adjacency) {
graph[element] = new Node(element);
}
// Populate children & parents lists of each node
for (const element in adjacency) {
for (const child of adjacency[element]) {
graph[element].children.push(graph[child]);
graph[child].parents.push(graph[element]);
}
}
let buildCount = 0;
// Explicitly build all nodes that have no parent (are not used for another element)
for (const node of Object.values(graph)) {
if (node.parents.length == 0) {
buildCount += node.build();
}
}
return buildCount;
}
// Run on the larger JSON:
const adjacency = {"Air": [],"Fire": [],"Soil": [],"Water": [],"Acorn" : ["Time" , "Tree"],"Adhesive tape" : ["Glue" , "Ribbon"],"Aircraft" : ["Air" , "Metal"],"Airship" : ["Balloon" , "Metal" , "Rope"],"Algae" : ["Plant" , "Water"],"Anchor" : ["Chain" , "Metal" , "Water"],"Angel" : ["Bird" , "Human"],"Anvil" : ["Hammer" , "Human"],"Apple" : ["Gravity" , "Tree"],"Aquarium" : ["Fish" , "Glass" , "Water"],"Armor" : ["Clothes" , "Metal"],"Arrow" : ["Blade" , "Feather" , "Stick"],"Ash" : ["Bonfire" , "Water"],"Asteroid" : ["Space" , "Stone"],"Atom" : ["Electron" , "Neutron" , "Proton"],"Axe" : ["Blade" , "Stick" , "Wood"],"Baby" : ["Human" , "Human" , "Love"],"Bacteria" : ["Life" , "Ocean"],"Ball" : ["Air" , "Rubber"],"Balloon" : ["Air" , "Rope" , "Rubber"],"Bandage" : ["Cloth" , "Ribbon"],"Bank" : ["House" , "Money"],"Baobab" : ["Savannah" , "Tree"],"Barrel" : ["Board" , "Circle" , "Metal"],"Bat" : ["Air" , "Blood"],"Battery" : ["Electricity" , "Energy" , "Metal"],"Beach" : ["Ocean" , "Sand"],"Bear" : ["Cave" , "Claw"],"Bed" : ["Pillow" , "Wood"],"Bee" : ["Flower" , "Insect"],"Beer" : ["Water" , "Wheat"],"Binoculars" : ["Telescope" , "Telescope"],"Bird" : ["Air" , "Life"],"Birdhouse" : ["Bird" , "House"],"Bitcoin" : ["Coin" , "Electricity"],"Black hole" : ["Gravity" , "Gravity" , "Gravity"],"Blade" : ["Metal" , "Tool"],"Blood" : ["Blade" , "Human"],"Boar" : ["Forest" , "Pig"],"Board" : ["Tool" , "Wood" , "Wood"],"Boat" : ["Paddle" , "Raft"],"Bone" : ["Sword" , "Zombie"],"Bonfire" : ["Fire" , "Stick" , "Stick"],"Book" : ["Cardboard" , "Ink" , "Paper"],"Bottle" : ["Plastic" , "Water"],"Bow" : ["Rope" , "Stick"],"Box" : ["Cardboard" , "Cardboard"],"Brain" : ["Neuron" , "Neuron" , "Neuron"],"Bread" : ["Dough" , "Fire"],"Brick" : ["Clay" , "Fire"],"Brush" : ["Paper" , "Tool"],"Bubble" : ["Air" , "Soap"],"Bucket" : ["Metal" , "Plastic" , "Water"],"Bug" : ["Insect" , "Tree"],"Bulb" : ["Electricity" , "Glass"],"Butterfly" : ["Caterpillar" , "Time"],"Cacao" : ["Sun" , "Tree"],"Cactus" : ["Needle" , "Plant"],"Cake" : ["Dough" , "Ice cream"],"Calendar" : ["Paper" , "Time"],"Camel" : ["Desert" , "Horse"],"Camouflage" : ["Chameleon" , "Cloth"],"Candle" : ["Fire" , "Wax"],"Candy" : ["Chocolate" , "Paper"],"Canon" : ["Gunpowder" , "Pipe"],"Car" : ["Road" , "Wheel"],"Cardboard" : ["Paper" , "Paper"],"Castle" : ["Tower" , "Wall"],"Cat" : ["Human" , "Tiger"],"Caterpillar" : ["Earthworm" , "Plant"],"Cave" : ["Mountain" , "Time"],"Centaur" : ["Horse" , "Human"],"Ceramic" : ["Clay" , "Heat"],"Cerberus" : ["Dog" , "Dog" , "Dog"],"Chain" : ["Metal" , "Rope"],"Chalk" : ["Limestone" , "Pencil"],"Chameleon" : ["Lizard" , "Rainbow"],"Cheese" : ["Milk" , "Time"],"Cheetah" : ["Cat" , "Savannah" , "Wind"],"Chest" : ["Box" , "Wood"],"Chocolate" : ["Cacao" , "Sugar"],"Christmas tree" : ["Garland" , "Spruce" , "Star"],"Circle" : ["Dividers" , "Paper"],"Circus" : ["Clown" , "House"],"Claw" : ["Blade" , "Bone"],"Clay" : ["River" , "Shovel"],"Clock" : ["Battery" , "Time"],"Cloth" : ["Thread" , "Thread"],"Clothes" : ["Cloth" , "Needle"],"Cloud" : ["Air" , "Water"],"Clown" : ["Holiday" , "Human"],"Coal" : ["Fire" , "Plant"],"Cobweb" : ["Fly" , "Spider"],"Coffee" : ["Cacao" , "Heat" , "Water"],"Coin" : ["Circle" , "Gold"],"Comb" : ["Hair" , "Plastic"],"Compass" : ["Electricity" , "Magnet"],"Concrete" : ["Sand" , "Water"],"Cookie" : ["Cacao" , "Dough" , "Milk"],"Cotton" : ["Cloud" , "Grass"],"Cow" : ["Life" , "Meadow"],"Crab" : ["Fish" , "Scissors"],"Crocodile" : ["Lizard" , "Swamp"],"Crossbow" : ["Bow" , "Metal"],"Crown" : ["Gem" , "Gold"],"Death" : ["Life" , "Time"],"Deer" : ["Forest" , "Horse"],"Desert" : ["Sand" , "Sun"],"Diamond" : ["Coal" , "Pressure"],"Dinosaur" : ["Fossil" , "Life"],"Dirt" : ["Ash" , "Water"],"Dividers" : ["Needle" , "Pencil"],"Doctor" : ["Human" , "Medicine"],"Dog" : ["Human" , "Wolf"],"Door" : ["Board" , "Wall"],"Dough" : ["Flour" , "Water"],"Dragon" : ["Fire" , "Lizard"],"Drum" : ["Barrel" , "Leather"],"Duck" : ["Bird" , "Lake"],"Dynamite" : ["Gunpowder" , "Rope"],"Eagle" : ["Bird" , "Mountain"],"Earthworm" : ["Life" , "Soil"],"Eclipse" : ["Moon" , "Sun"],"Eel" : ["Earthworm" , "Electricity"],"Egg" : ["Bird" , "Bird"],"Electricity" : ["Metal" , "Thunderbolt"],"Electron" : ["Electricity" , "Electricity"],"Energy" : ["Thunderbolt" , "Thunderbolt"],"Engine" : ["Metal" , "Steam"],"Explosion" : ["Fire" , "Gunpowder"],"Eye" : ["Lens" , "Life"],"Fangs" : ["Blade" , "Tooth"],"Fat" : ["Blade" , "Pig"],"Feather" : ["Bird" , "Hammer"],"Firefly" : ["Bulb" , "Insect"],"Fireworks" : ["Explosion" , "Rocket"],"Fish" : ["Life" , "Water"],"Fishing rod" : ["Earthworm" , "Rope" , "Stick"],"Flag" : ["Cloth" , "Stick"],"Flashlight" : ["Battery" , "Light"],"Flask" : ["Glass" , "Water"],"Flour" : ["Wheat" , "Windmill"],"Flower" : ["Life" , "Plant"],"Flute" : ["Pipe" , "Wind"],"Fly" : ["Air" , "Insect"],"Footwear" : ["Cloth" , "Soil"],"Forest" : ["Tree" , "Tree"],"Fork" : ["Pitchfork" , "Steak"],"Fossil" : ["Brush" , "Shovel" , "Soil"],"Fountain" : ["Pressure" , "Water"],"Fridge" : ["Electricity" , "Frost"],"Fried egg" : ["Egg" , "Fire"],"Frog" : ["Life" , "Swamp"],"Frost" : ["Air" , "Wind"],"Furnace" : ["Coal" , "Fire" , "Stone"],"Garland" : ["Bulb" , "Bulb" , "Bulb"],"Gasoline" : ["Petroleum" , "Steam"],"Gear" : ["Metal" , "Wheel"],"Gem" : ["Mountain" , "Pickaxe"],"Ghost" : ["Death" , "Human"],"Gift" : ["Box" , "Ribbon"],"Glass" : ["Fire" , "Sand"],"Glasses" : ["Eye" , "Lens" , "Plastic"],"Glue" : ["Flour" , "Heat" , "Water"],"Gold" : ["Gem" , "Metal"],"Golem" : ["Life" , "Stone"],"Grapes" : ["Plant" , "Stick" , "Sun"],"Grass" : ["Plant" , "Soil"],"Grasshopper" : ["Grass" , "Insect"],"Gravity" : ["Soil" , "Soil" , "Soil"],"Greenhouse" : ["Glass" , "Plant"],"Guitar" : ["String" , "String" , "Wood"],"Gunpowder" : ["Coal" , "Saltpeter"],"Hair" : ["Human" , "Wax"],"Hammer" : ["Stick" , "Stone"],"Hammerhead shark" : ["Fish" , "Hammer"],"Hamster" : ["Mouse" , "Wheat"],"Hand fan" : ["Paper" , "Wind"],"Harp" : ["Bow" , "String"],"Hay" : ["Grass" , "Heat"],"Healing potion" : ["Flask" , "Life"],"Health" : ["Apple" , "Human"],"Heart" : ["Blood" , "Engine"],"Heat" : ["Air" , "Fire"],"Hedgehog" : ["Mouse" , "Needle"],"Hen" : ["Bird" , "Wheat"],"Hippo" : ["Cow" , "River"],"Holiday" : ["Balloon" , "Cake" , "Fireworks"],"Honey" : ["Bee" , "Flower"],"Hookah" : ["Flask" , "Steam" , "Tobacco"],"Horns" : ["Blade" , "Bone" , "Bone"],"Horse" : ["Hay" , "Life"],"Hospital" : ["Health" , "House"],"House" : ["Concrete" , "Glass" , "Wood"],"Human" : ["Cave" , "Life"],"Hydrogen" : ["Sun" , "Time"],"Hyena" : ["Dog" , "Savannah"],"Ice" : ["Frost" , "Water"],"Ice cream" : ["Ice" , "Sugar"],"Iceberg" : ["Ice" , "Water"],"Ink" : ["Octopus" , "Pressure"],"Insect" : ["Earthworm" , "Soil"],"Island" : ["Ocean" , "Soil"],"Jungle" : ["Forest" , "Rain"],"Kettlebell" : ["Gravity" , "Metal"],"Key" : ["Lock" , "Tool"],"King" : ["Crown" , "Human"],"Kite" : ["Air" , "Cloth" , "Rope"],"Knight" : ["Armor" , "Human" , "Sword"],"Lake" : ["Water" , "Water"],"Lava" : ["Fire" , "Soil"],"Leaf" : ["Tree" , "Wind"],"Leather" : ["Hammer" , "Pig"],"Leech" : ["Blood" , "Earthworm"],"Lens" : ["Glass" , "Light"],"Lever" : ["Gear" , "Stick"],"Life" : ["Energy" , "Water"],"Light" : ["Sky" , "Sun"],"Lighthouse" : ["Light" , "Tower"],"Limestone" : ["River" , "Stone"],"Lion" : ["Cat" , "Savannah"],"Lizard" : ["Grass" , "Life"],"Lock" : ["Chest" , "Gear"],"Locomotive" : ["Car" , "Railway"],"Lollipop" : ["Candy" , "Stick"],"Love" : ["Human" , "Human"],"Magic wand" : ["Star" , "Stick"],"Magnet" : ["Electricity" , "Metal"],"Mana potion" : ["Flask" , "Star"],"Mantis" : ["Insect" , "Leaf"],"Map" : ["Compass" , "Paper"],"Mask" : ["Cloth" , "Rope"],"Match" : ["Coal" , "Stick"],"Meadow" : ["Grass" , "Soil"],"Meat" : ["Blade" , "Cow"],"Medicine" : ["Bacteria" , "Health"],"Mercury" : ["Silver" , "Water"],"Mermaid" : ["Fish" , "Human"],"Metal" : ["Fire" , "Stone"],"Meteor" : ["Asteroid" , "Fire"],"Microphone" : ["Sound" , "Stick"],"Milk" : ["Bucket" , "Cow"],"Mine" : ["Cave" , "Pickaxe"],"Minotaur" : ["Cow" , "Human"],"Mirror" : ["Glass" , "Light" , "Water"],"Moat" : ["Castle" , "River"],"Mole" : ["Mouse" , "Soil"],"Molecule" : ["Atom" , "Atom"],"Money" : ["Gold" , "Paper"],"Monkey" : ["Life" , "Tree"],"Moon" : ["Sky" , "Stone"],"Mosquito" : ["Blood" , "Fly"],"Mountain" : ["Soil" , "Stone"],"Mouse" : ["Life" , "Wheat"],"Mummy" : ["Bandage" , "Human"],"Mushroom" : ["Grass" , "Rain"],"Music" : ["Needle" , "Vinyl disk"],"Nail" : ["Hammer" , "Metal" , "Stick"],"Needle" : ["Metal" , "Thread"],"Nest" : ["Bird" , "Egg" , "Tree"],"Net" : ["Cobweb" , "Water"],"Neuron" : ["Electricity" , "Life"],"Neutron" : ["Electron" , "Proton"],"Nunchaku" : ["Chain" , "Stick" , "Stick"],"Obsidian" : ["Lava" , "Water"],"Ocean" : ["Water" , "Water" , "Water"],"Octopus" : ["Fish" , "Vacuum"],"Orca" : ["Ice" , "Whale"],"Ore" : ["Mine" , "Pickaxe"],"Ostrich" : ["Bird" , "Sand"],"Owl" : ["Bird" , "Claw"],"Oxygen" : ["Plant" , "Sun"],"Ozone" : ["Oxygen" , "Sun"],"Paddle" : ["Stick" , "Water"],"Paints" : ["Board" , "Rainbow"],"Panda" : ["Bear" , "Jungle"],"Paper" : ["Tool" , "Wood"],"Parrot" : ["Bird" , "Jungle"],"Pearl" : ["Gem" , "Water"],"Pegasus" : ["Bird" , "Horse"],"Pen" : ["Ink" , "Plastic"],"Pencil" : ["Coal" , "Wood"],"Penguin" : ["Bird" , "Frost"],"Petroleum" : ["Fossil" , "Plant" , "Soil"],"Phoenix" : ["Bird" , "Fire"],"Photo camera" : ["Light" , "Metal" , "Paper"],"Pickaxe" : ["Mountain" , "Tool"],"Picture" : ["Brush" , "Paints" , "Paper"],"Pie" : ["Apple" , "Flour"],"Pig" : ["Dirt" , "Life"],"Pigeon" : ["Bird" , "Bread"],"Pillow" : ["Cloth" , "Feather"],"Pipe" : ["Air" , "Metal" , "Stick"],"Pitchfork" : ["Hay" , "Tool"],"Plant" : ["Soil" , "Water"],"Plastic" : ["Coal" , "Petroleum"],"Plunger" : ["Rubber" , "Stick" , "Vacuum"],"Poison" : ["Flask" , "Snake"],"Polar bear" : ["Bear" , "Snow"],"Potion of Speed" : ["Flask" , "Wind"],"Potion of Strength" : ["Flask" , "Mountain"],"Potion of Wisdom" : ["Flask" , "Owl"],"Pressure" : ["Air" , "Heat"],"Propane" : ["Fire" , "Petroleum"],"Proton" : ["Electron" , "Gravity"],"Puddle" : ["Road" , "Water"],"Pyramid" : ["Mountain" , "Sand"],"Radio" : ["Metal" , "Sound"],"Raft" : ["Water" , "Wood"],"Railway" : ["Metal" , "Road"],"Rain" : ["Cloud" , "Water"],"Rainbow" : ["Rain" , "Sun"],"Raincoat" : ["Clothes" , "Rain"],"Rake" : ["Comb" , "Stick"],"Rhinoceros" : ["Horns" , "Savannah"],"Ribbon" : ["Cloth" , "Scissors"],"Ring" : ["Circle" , "Metal"],"River" : ["Soil" , "Water" , "Water"],"Road" : ["Concrete" , "Soil"],"Robot" : ["Battery" , "Human"],"Rocket" : ["Fire" , "Pipe"],"Rope" : ["Thread" , "Thread" , "Thread"],"Rose" : ["Flower" , "Love"],"Rubber" : ["Petroleum" , "Water"],"Ruler" : ["Board" , "Pencil"],"Safe" : ["Lock" , "Money"],"Salt" : ["Heat" , "Ocean"],"Saltpeter" : ["Limestone" , "Plant"],"Sand" : ["Stone" , "Water"],"Savannah" : ["Grass" , "Soil" , "Sun"],"Scalpel" : ["Blade" , "Health"],"Scissors" : ["Blade" , "Blade"],"Scoop-net" : ["Net" , "Stick"],"Scooter" : ["Wheel" , "Wheel"],"Scorpion" : ["Crab" , "Desert"],"Sculpture" : ["Human" , "Stone"],"Sea cow" : ["Cow" , "Water"],"Seagull" : ["Bird" , "Ocean"],"Seahorse" : ["Fish" , "Horse"],"Sewing machine" : ["Electricity" , "Needle"],"Shark" : ["Fish" , "Tooth"],"Sheep" : ["Cloud" , "Life"],"Shield" : ["Board" , "Metal"],"Ship" : ["Cloth" , "Water" , "Wood"],"Shovel" : ["Soil" , "Tool"],"Silver" : ["Coin" , "Furnace"],"Skateboard" : ["Board" , "Wheel"],"Skates" : ["Blade" , "Footwear" , "Ice"],"Skull" : ["Bone" , "Brain"],"Sky" : ["Air" , "Air" , "Air"],"Slingshot" : ["Rubber" , "Stick"],"Smartphone" : ["Microphone" , "Radio"],"Snail" : ["Caterpillar" , "Glue"],"Snake" : ["Earthworm" , "Fangs"],"Snow" : ["Frost" , "Rain"],"Snowman" : ["Human" , "Snow"],"Soap" : ["Ash" , "Fat"],"Soda" : ["Air" , "Sugar" , "Water"],"Solar panel" : ["Energy" , "Sun"],"Sound" : ["Air" , "Explosion"],"Space" : ["Sky" , "Star"],"Spear" : ["Blade" , "Stick" , "Stick"],"Sphinx" : ["Human" , "Lion"],"Spider" : ["Insect" , "Insect"],"Spine" : ["Bone" , "Neuron"],"Sport" : ["Human" , "Kettlebell"],"Spruce" : ["Needle" , "Tree"],"Spyglass" : ["Lens" , "Pipe"],"Squirrel" : ["Acorn" , "Mouse"],"Star" : ["Sky" , "Telescope"],"Starfish" : ["Ocean" , "Star"],"Steak" : ["Fire" , "Meat"],"Steam" : ["Fire" , "Water"],"Stick" : ["Blade" , "Plant"],"Stone" : ["Soil" , "Soil"],"Stopwatch" : ["Ruler" , "Time"],"String" : ["Sound" , "Thread"],"Stump" : ["Axe" , "Tree"],"Sugar" : ["Sugar cane" , "Windmill"],"Sugar cane" : ["Plant" , "Stick" , "Water"],"Sulfur" : ["Ash" , "Lava"],"Sulfuric acid" : ["Hydrogen" , "Oxygen" , "Sulfur"],"Sun" : ["Fire" , "Sky"],"Sunflower" : ["Flower" , "Sun"],"Surfboard" : ["Board" , "Wave"],"Sushi" : ["Algae" , "Fish"],"Swamp" : ["Grass" , "Lake"],"Sword" : ["Blade" , "Stick"],"Swordfish" : ["Fish" , "Sword"],"Syringe" : ["Health" , "Needle"],"Tank" : ["Metal" , "Turtle"],"Tape measure" : ["Ribbon" , "Ruler"],"Tea" : ["Heat" , "Plant" , "Water"],"Tear" : ["Eye" , "Water"],"Telescope" : ["Lens" , "Sky"],"Tent" : ["Cloth" , "House" , "Stick"],"Thermometer" : ["Heat" , "Mercury"],"Thread" : ["Cobweb" , "Cobweb"],"Thunderbolt" : ["Cloud" , "Cloud" , "Cloud"],"Tide" : ["Moon" , "Ocean"],"Tiger" : ["Jungle" , "Life"],"Time" : ["Glass" , "Sand"],"Tobacco" : ["Plant" , "Steam"],"Tool" : ["Human" , "Metal" , "Wood"],"Tooth" : ["Bone" , "Pressure"],"Toothbrush" : ["Tool" , "Tooth"],"Toothpaste" : ["Health" , "Tooth"],"Toothpick" : ["Stick" , "Tooth"],"Torch" : ["Fire" , "Stick"],"Tornado" : ["Energy" , "Wind"],"Tower" : ["House" , "House"],"Traffic light" : ["Garland" , "Road"],"Treasure" : ["Chest" , "Island"],"Tree" : ["Plant" , "Plant"],"Trojan horse" : ["Horse" , "Wood"],"Turtle" : ["Egg" , "Sand"],"Umbrella" : ["Cloth" , "Rain"],"Unicorn" : ["Horse" , "Magic wand"],"Vacuum" : ["Glass" , "Space"],"Vampire" : ["Blood" , "Human"],"Vinyl disk" : ["Plastic" , "Wax"],"Violin" : ["String" , "Wood"],"Volcano" : ["Lava" , "Mountain"],"Wall" : ["Brick" , "Concrete"],"Wallpaper" : ["Glue" , "Paper" , "Wall"],"Walrus" : ["Fangs" , "Sea cow"],"Waterfall" : ["Mountain" , "Water"],"Wave" : ["Energy" , "Ocean"],"Wax" : ["Bee" , "Bee"],"Well" : ["Bucket" , "Shovel" , "Soil"],"Werewolf" : ["Human" , "Moon" , "Wolf"],"Whale" : ["Fish" , "Fountain"],"Wheat" : ["Shovel" , "Soil" , "Water"],"Wheel" : ["Air" , "Pressure" , "Rubber"],"Wig" : ["Hair" , "Hair"],"Wind" : ["Air" , "Air"],"Windmill" : ["Stone" , "Wind"],"Window" : ["Glass" , "Wood"],"Wine" : ["Grapes" , "Water"],"Wire" : ["Electricity" , "Metal" , "Plastic"],"Wolf" : ["Forest" , "Life"],"Wood" : ["Forest" , "Human"],"Woodpecker" : ["Bird" , "Wood"],"Wool" : ["Scissors" , "Sheep"],"Zebra" : ["Horse" , "Savannah"],"Zombie" :["Death", "Life"]};
const buildCount = solve(adjacency);
console.log("Total number of steps to discover all elements:", buildCount);
The output is 27435.
As the previous answer pointed out, this is a directed acyclic graph problem.
The nodes are composed elements, the leafs are basic elements.
In order to calculate the depth, you just traverse the tree to find out.
In Haskell, this looks rather neat (while at first thought I considered Prolog for that, I settled with Haskell as it is really pretty in this case).
-- The base elements are simply numbers
-- (could be strings as well - but that would just be eye candy).
data Element =
Basic(Integer)
| Composed(Element,Element)
deriving (Show,Eq)
depth:: Element -> Integer
depth (Basic _) = 0
depth (Composed(a, b)) =
1 + max (depth a) (depth b)
air = Basic 1
fire = Basic 2
soil = Basic 3
water = Basic 4
heat = Composed(air,fire)
plant = Composed(soil,water)
algae = Composed(plant,water)
If loaded into the REPL and executing the function, we get the correct result.
*Main> depth algae
2
For just 400 elements, at this point you would be done as it is still a "small" problem and the run time should be below noticeable.
In order to speed it up, one idea could be to add data automatically to Composed elements (such as the depth) so you can prune the tree.
The same idea at search time could be a form of memoization.
I need to convert Arabic text from windows-1256 to utf-8 how can I do that? any help?
thanks
Try lua-iconv, which binds iconv to Lua.
local win2utf_list = [[
0x00 0x0000 #NULL
0x01 0x0001 #START OF HEADING
0x02 0x0002 #START OF TEXT
-- Download full text from
-- http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1256.TXT
0xFD 0x200E #LEFT-TO-RIGHT MARK
0xFE 0x200F #RIGHT-TO-LEFT MARK
0xFF 0x06D2 #ARABIC LETTER YEH BARREE
]]
local win2utf = {}
for w, u in win2utf_list:gmatch'0x(%x%x)%s+0x(%x+)' do
local c, t, h = tonumber(u,16), {}, 128
while c >= h do
t[#t+1] = 128 + c%64
c = math.floor(c/64)
h = h > 32 and 32 or h/2
end
t[#t+1] = 256 - 2*h + c
win2utf[w.char(tonumber(w,16))] =
w.char((table.unpack or unpack)(t)):reverse()
end
local function convert_to_utf8(win_string)
return win_string:gsub('.', win2utf)
end
Windows-1256 is one of the character-sets designed as an 8-bit overlay of ASCII. It therefore has 256 characters, each encoded as one byte.
UTF-8 is an encoding of the Unicode character-set. Being "universal", it works out that it is a superset of the Windows-1256 character-set. So, there is no loss of information by having to use "substitution characters" in place of ones that aren't members of the character-set.
Conversion is a simple matter of transforming the Windows-1256 byte for each character to the corresponding UTF-8 bytes. A lookup table is an easy way to do it.
local encoding = {
-- table maps the one byte Windows-1256 encoding for a character to a Lua string with the UTF-8 encoding for the character
"\000" , "\001" , "\002" , "\003" , "\004" , "\005" , "\006" , "\007" ,
"\008" , "\009" , "\010" , "\011" , "\012" , "\013" , "\014" , "\015" ,
"\016" , "\017" , "\018" , "\019" , "\020" , "\021" , "\022" , "\023" ,
"\024" , "\025" , "\026" , "\027" , "\028" , "\029" , "\030" , "\031" ,
"\032" , "\033" , "\034" , "\035" , "\036" , "\037" , "\038" , "\039" ,
"\040" , "\041" , "\042" , "\043" , "\044" , "\045" , "\046" , "\047" ,
"\048" , "\049" , "\050" , "\051" , "\052" , "\053" , "\054" , "\055" ,
"\056" , "\057" , "\058" , "\059" , "\060" , "\061" , "\062" , "\063" ,
"\064" , "\065" , "\066" , "\067" , "\068" , "\069" , "\070" , "\071" ,
"\072" , "\073" , "\074" , "\075" , "\076" , "\077" , "\078" , "\079" ,
"\080" , "\081" , "\082" , "\083" , "\084" , "\085" , "\086" , "\087" ,
"\088" , "\089" , "\090" , "\091" , "\092" , "\093" , "\094" , "\095" ,
"\096" , "\097" , "\098" , "\099" , "\100" , "\101" , "\102" , "\103" ,
"\104" , "\105" , "\106" , "\107" , "\108" , "\109" , "\110" , "\111" ,
"\112" , "\113" , "\114" , "\115" , "\116" , "\117" , "\118" , "\119" ,
"\120" , "\121" , "\122" , "\123" , "\124" , "\125" , "\126" , "\127" ,
"\226\130\172", "\217\190" , "\226\128\154", "\198\146" , "\226\128\158", "\226\128\166", "\226\128\160", "\226\128\161",
"\203\134" , "\226\128\176", "\217\185" , "\226\128\185", "\197\146" , "\218\134" , "\218\152" , "\218\136" ,
"\218\175" , "\226\128\152", "\226\128\153", "\226\128\156", "\226\128\157", "\226\128\162", "\226\128\147", "\226\128\148",
"\218\169" , "\226\132\162", "\218\145" , "\226\128\186", "\197\147" , "\226\128\140", "\226\128\141", "\218\186" ,
"\194\160" , "\216\140" , "\194\162" , "\194\163" , "\194\164" , "\194\165" , "\194\166" , "\194\167" ,
"\194\168" , "\194\169" , "\218\190" , "\194\171" , "\194\172" , "\194\173" , "\194\174" , "\194\175" ,
"\194\176" , "\194\177" , "\194\178" , "\194\179" , "\194\180" , "\194\181" , "\194\182" , "\194\183" ,
"\194\184" , "\194\185" , "\216\155" , "\194\187" , "\194\188" , "\194\189" , "\194\190" , "\216\159" ,
"\219\129" , "\216\161" , "\216\162" , "\216\163" , "\216\164" , "\216\165" , "\216\166" , "\216\167" ,
"\216\168" , "\216\169" , "\216\170" , "\216\171" , "\216\172" , "\216\173" , "\216\174" , "\216\175" ,
"\216\176" , "\216\177" , "\216\178" , "\216\179" , "\216\180" , "\216\181" , "\216\182" , "\195\151" ,
"\216\183" , "\216\184" , "\216\185" , "\216\186" , "\217\128" , "\217\129" , "\217\130" , "\217\131" ,
"\195\160" , "\217\132" , "\195\162" , "\217\133" , "\217\134" , "\217\135" , "\217\136" , "\195\167" ,
"\195\168" , "\195\169" , "\195\170" , "\195\171" , "\217\137" , "\217\138" , "\195\174" , "\195\175" ,
"\217\139" , "\217\140" , "\217\141" , "\217\142" , "\195\180" , "\217\143" , "\217\144" , "\195\183" ,
"\217\145" , "\195\185" , "\217\146" , "\195\187" , "\195\188" , "\226\128\142", "\226\128\143", "\219\146"
}
--
encoding.convert = function(str)
assert(type(str) == "string", "Parameter 1 must be a string")
local result = {}
for i = 1, string.len(str) do
table.insert(result, encoding[string.byte(str,i)+1])
end
return table.concat(result)
end
assert(encoding.convert("test1") == "test1", "test1 failed")
Refs:
Joel Spolsky, The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
Roberto Ierusalimschy, Creating Strings Piece by Piece
Generally, convert from a code page (character set) to another. Must use a map table.
Which like: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1256.TXT, from CP1256 to Unicode.
Then convert from Unicode to Utf8 (encode/decode method works between Unicode & UTF-8 , without a big map).