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