Fastest algorithm to win a combination game - algorithm

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.

Related

FTP UPLOAD FILE Laravel

I try to send an excel file who was created when i refresh the page. I used the package https://github.com/harishanchu/Laravel-FTP
When i run the code bellow i get an exception like :
pathinfo() expects parameter 1 to be string, array given
I don't want to pick up a file in the storage because the system that i made will run the daily query everyday and send the file via FTP ! so i can't know the path before the file was created.
Hope someone could help me on this ! thanks a lot in advance
here the full code :
$licencies = Licencies::where('lb_assurance' , '=' , 'Lafont')
->leftJoin('activite_licencie' , 'activite_licencie.id' , '=' , 'licencies.activite_licencie_id')
->leftJoin('saisons' , 'saisons.id' , '=' , 'licencies.saison_id')
->leftJoin('pays' , 'pays.id' , '=' , 'licencies.pays_naissance_id')
->leftJoin('type_licence' , 'type_licence.id' , '=' , 'licencies.type_licence_id')
->leftJoin('structures' , 'structures.id' , '=' , 'licencies.structure_id')
->leftJoin('civilite' , 'civilite.id' , '=' , 'licencies.civilite_id')
->leftJoin('catg_licence' , 'catg_licence.id' , '=' , 'licencies.catg_licence_id')
->select('num_licence' , 'civilite.lb_civilite' , 'lb_nom' , 'lb_prenom' , 'dt_naissance' , 'pays.fr' ,'activite_licencie.lb_activite' , 'catg_licence.lb_catg_lic' , 'type_licence.lb_type' ,'saisons.lb_saison', 'lb_surclassement' , 'structures.nom_structure' , 'lb_assurance' , 'cd_dept_naissance' , 'lb_adresse' , 'tel_fix_licencie' , 'tel_port_licencie' , 'adresse_email')
->whereRaw('DATE(licencies.created_at) = CURRENT_DATE')
->get();
$licencies->map(function($licencie) {
$licencie['dt_naissance'] = \Carbon\Carbon::parse($licencie['dt_naissance'])->format('d/m/Y');
//$licencie['created_at'] = \Carbon\Carbon::parse($licencie['created_at'])->format('d/m/Y H:i:s');
return $licencie;
});
$date = Carbon::now('Europe/Paris')->format('d-m-Y H:i:s');
$file = Excel::create('Assurance Lafont - Saisie des Licences FFRXIII le : ' . $date . '' , function($excel) use ($licencies) {
$excel->sheet('Excel', function($sheet) use ($licencies)
{
$sheet->fromArray($licencies);
});
});
$directory = 'mydirectory' ;
$ftp = FTP::connection()->uploadFile($file, $directory);
dd($ftp);

Emails sent from Server1 reaches the destination from Server 2

Question
Outbound emails sent through EXCH-S01 or EXCH-S02 are always routed to EXCH-S02 before leaving the organization network in Exchange 2010 DAG. Why?
Configuration
This is a simple DAG with two exchange servers and a fileshare witness (not included in the figure). S1 and S2 are the exchange servers hosting OWA1 and OWA2 respectively.
System Information
Send Connector: Internet
AddressSpaces : {SMTP:*;1}
AuthenticationCredential :
Comment :
ConnectedDomains : {}
ConnectionInactivityTimeOut : 00:10:00
DNSRoutingEnabled : True
DomainSecureEnabled : False
Enabled : True
ErrorPolicies : Default
ForceHELO : False
Fqdn : email.fabrikam.ca
HomeMTA : Microsoft MTA
HomeMtaServerId : EXCH-S02
Identity : Internet
IgnoreSTARTTLS : False
IsScopedConnector : False
IsSmtpConnector : True
LinkedReceiveConnector :
MaxMessageSize : unlimited
Name : Internet
Port : 25
ProtocolLoggingLevel : None
RequireOorg : False
RequireTLS : False
SmartHostAuthMechanism : None
SmartHosts : {}
SmartHostsString :
SmtpMaxMessagesPerConnection : 20
SourceIPAddress : 0.0.0.0
SourceRoutingGroup : Exchange Routing Group (DWBGZMFD01QNBJR)
SourceTransportServers : {EXCH-S02, EXCH-S01}
TlsAuthLevel :
TlsDomain :
UseExternalDNSServersEnabled : True
Receive Connector "EXCH-S02\From EXCH-S01"
RunspaceId : c5d80334-209b-4974-b6ef-105e3db469b4
AuthMechanism : Tls, Integrated, BasicAuth, BasicAuthRequireTLS, ExchangeServer
Banner :
BinaryMimeEnabled : True
Bindings : {0.0.0.0:25}
ChunkingEnabled : True
DefaultDomain :
DeliveryStatusNotificationEnabled : True
EightBitMimeEnabled : True
BareLinefeedRejectionEnabled : False
DomainSecureEnabled : False
EnhancedStatusCodesEnabled : True
LongAddressesEnabled : False
OrarEnabled : False
SuppressXAnonymousTls : False
AdvertiseClientSettings : False
Fqdn : EXCH-S02.fabrikam.ca
Comment :
Enabled : True
ConnectionTimeout : 00:10:00
ConnectionInactivityTimeout : 00:05:00
MessageRateLimit : unlimited
MessageRateSource : IPAddress
MaxInboundConnection : 5000
MaxInboundConnectionPerSource : 20
MaxInboundConnectionPercentagePerSource : 100
MaxHeaderSize : 64 KB (65,536 bytes)
MaxHopCount : 60
MaxLocalHopCount : 8
MaxLogonFailures : 3
MaxMessageSize : 10 MB (10,485,760 bytes)
MaxProtocolErrors : 5
MaxRecipientsPerMessage : 200
PermissionGroups : ExchangeUsers, ExchangeServers, ExchangeLegacyServers
PipeliningEnabled : True
ProtocolLoggingLevel : None
RemoteIPRanges : {10.1.0.3, 10.1.0.1}
RequireEHLODomain : False
RequireTLS : False
EnableAuthGSSAPI : False
ExtendedProtectionPolicy : None
LiveCredentialEnabled : False
TlsDomainCapabilities : {}
Server : EXCH-S02
SizeEnabled : EnabledWithoutValue
TarpitInterval : 00:00:05
MaxAcknowledgementDelay : 00:00:30
AdminDisplayName :
ExchangeVersion : 0.1 (8.0.535.0)
Name : From EXCH-S01
DistinguishedName : CN=From EXCH-S01,CN=SMTP Receive Connectors,CN=Protocols,CN=EXCH-S02,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=fabrikam,CN=
Microsoft Exchange,CN=Services,CN=Configuration,DC=fabrikam,DC=ca
Identity : EXCH-S02\From EXCH-S01
Guid : a040ff87-900f-4a21-ad68-c9c095940686
ObjectCategory : fabrikam.ca/Configuration/Schema/ms-Exch-Smtp-Receive-Connector
ObjectClass : {top, msExchSmtpReceiveConnector}
WhenChanged : 4/8/2017 9:10:54 AM
WhenCreated : 1/21/2012 10:15:06 PM
WhenChangedUTC : 4/8/2017 1:10:54 PM
WhenCreatedUTC : 1/22/2012 3:15:06 AM
OrganizationId :
OriginatingServer : DC01.fabrikam.ca
IsValid : True
Exchange Server EXCH-S01
RunspaceId : c5d80334-209b-4974-b6ef-105e3db469b4
Name : EXCH-S01
DataPath : D:\Exchange Server\V14\Mailbox
Domain : fabrikam.ca
Edition : Enterprise
ExchangeLegacyDN : /o=fabrikam/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=EXCH-S01
ExchangeLegacyServerRole : 0
Fqdn : EXCH-S01.fabrikam.ca
CustomerFeedbackEnabled :
InternetWebProxy :
IsHubTransportServer : True
IsClientAccessServer : True
IsExchange2007OrLater : True
IsEdgeServer : False
IsMailboxServer : True
IsE14OrLater : True
IsProvisionedServer : False
IsUnifiedMessagingServer : False
NetworkAddress : {ncacn_vns_spp:EXCH-S01, netbios:EXCH-S01, ncacn_np:EXCH-S01, ncacn_spx:EXCH-S01, ncacn_ip_tcp:EXCH-S01.fabrikam.ca, ncalrpc:EXCH-S01}
OrganizationalUnit : fabrikam.ca/EXCH-S01
AdminDisplayVersion : Version 14.3 (Build 123.4)
Site : fabrikam.ca/Configuration/Sites/fabrikam
ServerRole : Mailbox, ClientAccess, HubTransport
ErrorReportingEnabled :
StaticDomainControllers : {}
StaticGlobalCatalogs : {}
StaticConfigDomainController :
StaticExcludedDomainControllers : {}
CurrentDomainControllers : {}
CurrentGlobalCatalogs : {}
CurrentConfigDomainController :
ProductID : 02064-110-8022196-75615
IsExchange2007TrialEdition : False
IsExpiredExchange2007TrialEdition : False
RemainingTrialPeriod : 00:00:00
IsValid : True
ExchangeVersion : 0.1 (8.0.535.0)
DistinguishedName : CN=EXCH-S01,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=fabrikam,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=fabrikam,DC=
ca
Identity : EXCH-S01
Guid : 72736c62-2931-4128-bca5-73b233142f3b
ObjectCategory : fabrikam.ca/Configuration/Schema/ms-Exch-Exchange-Server
ObjectClass : {top, server, msExchExchangeServer}
WhenChanged : 4/8/2017 5:23:00 PM
WhenCreated : 5/21/2011 8:29:21 PM
WhenChangedUTC : 4/8/2017 9:23:00 PM
WhenCreatedUTC : 5/22/2011 12:29:21 AM
OrganizationId :
OriginatingServer : DC01.fabrikam.ca
Exchange Server EXCH-S02
RunspaceId : c5d80334-209b-4974-b6ef-105e3db469b4
Name : EXCH-S02
DataPath : D:\Exchange Server\V14\Mailbox
Domain : fabrikam.ca
Edition : Enterprise
ExchangeLegacyDN : /o=fabrikam/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=EXCH-S02
ExchangeLegacyServerRole : 0
Fqdn : EXCH-S02.fabrikam.ca
CustomerFeedbackEnabled :
InternetWebProxy :
IsHubTransportServer : True
IsClientAccessServer : True
IsExchange2007OrLater : True
IsEdgeServer : False
IsMailboxServer : True
IsE14OrLater : True
IsProvisionedServer : False
IsUnifiedMessagingServer : False
NetworkAddress : {ncacn_vns_spp:EXCH-S02, netbios:EXCH-S02, ncacn_np:EXCH-S02, ncacn_spx:EXCH-S02, ncacn_ip_tcp:EXCH-S02.fabrikam.ca, ncalrpc:EXCH-S02}
OrganizationalUnit : fabrikam.ca/EXCH-S02
AdminDisplayVersion : Version 14.3 (Build 123.4)
Site : fabrikam.ca/Configuration/Sites/fabrikam
ServerRole : Mailbox, ClientAccess, HubTransport
ErrorReportingEnabled :
StaticDomainControllers : {}
StaticGlobalCatalogs : {}
StaticConfigDomainController :
StaticExcludedDomainControllers : {}
CurrentDomainControllers : {}
CurrentGlobalCatalogs : {}
CurrentConfigDomainController :
ProductID : 02064-110-8022196-75900
IsExchange2007TrialEdition : False
IsExpiredExchange2007TrialEdition : False
RemainingTrialPeriod : 00:00:00
IsValid : True
ExchangeVersion : 0.1 (8.0.535.0)
DistinguishedName : CN=EXCH-S02,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=fabrikam,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=fabrikam,DC=
ca
Identity : EXCH-S02
Guid : 0f25a4ee-2e54-4c9c-840d-a1ab5f107cfa
ObjectCategory : fabrikam.ca/Configuration/Schema/ms-Exch-Exchange-Server
ObjectClass : {top, server, msExchExchangeServer}
WhenChanged : 9/20/2014 10:20:32 AM
WhenCreated : 1/21/2012 5:58:57 PM
WhenChangedUTC : 9/20/2014 2:20:32 PM
WhenCreatedUTC : 1/21/2012 10:58:57 PM
OrganizationId :
OriginatingServer : DC01.fabrikam.ca
I will be happy to provide more information if required.
What I've done so far
Reset the activation preference.
Noticed HomeMtaServerId set to EXCH-S02 in the send connector. But realized Exchnage Server 2010 does not use that parameter anymore.
I am very eager to find out what is causing this.

Pig CLI getting stuck with ">>" symbol prompting for input

I'd like to understand what is wrong with below Pig code. The last time of below code cause Pig CLI getting stuck with ">>" prompting for input but regardless of what I enter, it continued to prompt.
newServiceIdMapping = load '/idn/home/data/new/ServiceIdMapping_test.csv' USING PigStorage(',') AS (market : chararray , serviceId : chararray , rm : chararray , serviceChannel : chararray , team : chararray , pm : chararray , tl : chararray , gh : chararray );
newServiceIdMappingUpd = FOREACH newServiceIdMapping GENERATE (serviceId,rm , (pm == '' ? tl : pm) As pm1 );
Exclude the brackets after GENERATE.
newServiceIdMapping = load '/idn/home/data/new/ServiceIdMapping_test.csv' USING PigStorage(',') AS (market : chararray , serviceId : chararray , rm : chararray , serviceChannel : chararray , team : chararray , pm : chararray , tl : chararray , gh : chararray );
newServiceIdMappingUpd = FOREACH newServiceIdMapping GENERATE serviceId,rm , (pm == '' ? tl : pm) as pm1 ;

stuck making simple grammar for filter language

I have tried and get close but keep getting stuck. Input language is like this
('aaa' eq '42') and ('bbb' gt 'zzz') or (....) and (....)
ie a set of clauses of the form left op right joined by 'and' or 'or'. THere can be 1 or more clauses
This seemed simple to me but I am sure I have started getting too complicated
grammar filter;
options {
language=CSharp2;
output=AST;
}
tokens {
ROOT;
}
OPEN_PAREN
: '(';
CLOSE_PAREN
: ')';
SINGLE_QUOTE
: '\'' ;
AND : 'and';
OR : 'or';
GT : 'gt';
GE : 'ge';
EQ : 'eq';
LT : 'lt';
LE : 'le';
fragment
ID : ('a'..'z' | 'A'..'Z' )+;
STRING : SINGLE_QUOTE ID SINGLE_QUOTE;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { $channel = Hidden; } ;
//public root : filter -> ^(ROOT filter);
public filter
: clause^
| lc=clause join rc=clause ->^(join $lc $rc)
;
left : STRING;
right : STRING;
clause
: OPEN_PAREN left op right CLOSE_PAREN //-> ^(op left right)
;
join : AND
| OR
;
op : GT|GE|LT|LE|EQ;
when I run this in C# I get 'more than one node as root'
Also I am not sure how I can do the N joins

How to convert windows-1256 to utf-8 in lua?

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).

Resources