Daily Challenge #58 - Smelting Iron Ingots

Minecraft has gotten to be a very popular game. No doubt many reading this have played it themselves or watched someone else. In Minecraft, collected ore must be smelted in a furnace to change the resource into a usable form.

Each ingot takes 11 seconds to produce. Steve has the following fuel options to add to the furnace:

Buckets of lava, each lasts 800 seconds
Blaze rod, each lasts 120 seconds
Coals, each lasts 80 seconds
Blocks of Wood, each lasts 15 seconds
Sticks, each lasts 1 second*

Write a function that calculates the minimum amount of fuel needed to produce a certain number of iron ingots.

Ruby: {:lava => 2, :blaze_rod => 1, :coal => 1, :wood => 0, :stick => 0}
JavaScript: {lava: 2, blazeRod: 1, coal: 1, wood: 0, stick: 0}

Good luck!~

Today's challenge comes from arwengu on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

dev.to staff

The hardworking team behind dev.to ❤️

Discussion

Time to Go smelting!

ingots.go

package ingots

const (
blazeRodDuration int = 120
coalDuration     int = 80
woodDuration     int = 15
)

// Requirements represents the differents types of fuel and in what amounts needed to complete the smelting job
type Requirements struct {
Lava     int
BlazeRod int
Coal     int
Wood     int
Stick    int
}

// Fuel determines the fuel requirements to smelt the given number of ingots
func Fuel(ingots int) Requirements {
if ingots <= 0 {
return Requirements{0, 0, 0, 0, 0}
}

duration := ingots * 11

return Requirements{
BlazeRod: duration/blazeRodDuration + 1,
Coal:     duration/coalDuration + 1,
Wood:     duration/woodDuration + 1,
Stick:    duration,
}
}



ingots_test.go

package ingots

import "testing"

func TestFuel(t *testing.T) {
testCases := []struct {
description string
input       int
expected    Requirements
}{
{
"a few ingots",
2,
Requirements{1, 1, 1, 2, 22},
},
{
"wow that is alot of ingots",
500,
Requirements{7, 46, 69, 367, 5500},
},
{
"negative amount of ingots",
-5,
Requirements{0, 0, 0, 0, 0},
},
{
"no ingots",
0,
Requirements{0, 0, 0, 0, 0},
},
}

for _, test := range testCases {
if result := Fuel(test.input); result != test.expected {
t.Fatalf("FAIL: %s - Fuel(%d): %+v - expected: %+v", test.description, test.input, result, test.expected)
}
t.Logf("PASS: %s", test.description)
}
}



My solution in JavaScript:

const calcFuel = (n) => {
const secsPerIngot = 11;
let time = n * secsPerIngot;

const lava = Math.floor(time / 800);
time = time - lava * 800;
const blazeRod = Math.floor(time / 120);
time = time - blazeRod * 120;
const coal = Math.floor(time / 80);
time = time - coal * 80;
const wood = Math.floor(time / 15);
time =  time - wood * 15;
const stick = Math.floor(time / 1);

return {lava, blazeRod, coal, wood, stick};
};


I think I interpreted this correctly (though "minimum number" could mean a few different things here...)

Here's my solution using javascript's reduce:

const fuel = ingots => {
let need = ingots * 11

const types = [
{name: 'lava', sec: 800},
{name: 'blazeRod', sec: 120},
{name: 'coal', sec: 80},
{name: 'wood', sec: 15},
{name: 'stick', sec: 1},
]

return types.reduce((r, v) => {
r[v.name] = Math.floor(need / v.sec)
need = need - (r[v.name] * v.sec)
return r
}, {})
}


And you can watch me solve it here! youtu.be/wtA4CKbZipA

Python

def fuel(a):
a = a * 11
i= 0
tab = []
t1 = [800,120,80,15,1]
t2 = ['lava','blazeRod','coal','wood','stick']
while a > 0:
if  a > t1[i]:
if a % t1[i] == 0:
tab.append([t2[i],  a // t1[i]])
a = 0
else:
tab.append([t2[i], a // t1[i]])
a = a % t1[i]
else:
tab.append([t2[i],  0])
i+=1
if i < 5:
while i <5:
tab.append([t2[i],  0])
i+=1
return tab


javascript:

const calcFuel = ingots => {
let totalTime = ingots*11;
duration = {lava: 800, blazeRod: 120, coal: 80, wood: 15, stick: 1};
fuel = {lava: 0, blazeRod: 0, coal: 0, wood: 0, stick: 0};
Object.keys(fuel).map( (kind, index) => {
fuel[kind] += Math.floor(totalTime/duration[kind]);
totalTime -= fuel[kind]*duration[kind];
});
return fuel;
};


The challenge was a little bit ambiguous about the requirement. If I understand correctly, is asking about at least how many resources of each fuel you require to try to smelt iron ingots.
With this, I wrote the following solution in JavaScript

const calculateFuelForIrons = ironCubesQty => {
const FUEL_DURATION = {
lava: 800,
blazeRod: 120,
coal: 80,
wood: 15,
stick: 1
};

const smeltingTime = ironCubesQty * 11;

return Object.keys(FUEL_DURATION).reduce((result, key) => {
const newResult = {
...result,
[key]: Math.floor(smeltingTime / FUEL_DURATION[key])
};

return { ...newResult };
}, {});
};

console.log(calculateFuelForIrons(10));
console.log(calculateFuelForIrons(110));
console.log(calculateFuelForIrons(11000));
console.log(calculateFuelForIrons(0));


I'm not sure if I'm correctly interpreting the problem, but:

data Fuels a = Fuels { lava :: a
, blazeRod :: a
, coal :: a
, wood :: a
, stick :: a
} deriving (Show, Eq)

defFuels :: (Integral a) => Fuels a
defFuels = Fuels 0 0 0 0 0

minFuel :: (Integral a) => a -> Fuels a
minFuel items = defFuels{lava = ceiling $fromIntegral items * 11 / 800}  The minimum amount of fuel to cook n items will always be only lava buckets... My other interpretation was the amount of fuel to get the exact correct smelting time. I did work on a solution for that, but it felt very verbose with a lot of repeated code to work with my Fuels type. I'm pretty new to Haskell, so I'm not sure if this is the best thing to use in this situation. I did think about using a map, but then I would have to deal with Maybes when looking up items from the map. Any advice or reccomendations would be appreciated. const furnace = (ingot = 0) => { var fuel = [ { type: "lava", duration: 800, count: 0 }, { type: "blazeRod", duration: 120, count: 0 }, { type: "coal", duration: 80, count: 0 }, { type: "wood", duration: 15, count: 0 }, { type: "stick", duration: 1, count: 0 } ]; let pTime = ingot * 11; if (pTime <= 0 || isNaN(pTime)) { console.log("No fuel consumption is necessary"); } else { fuel.map(item => { item.count = Math.floor(pTime / item.duration); pTime = pTime - item.count * item.duration; }); fuel.forEach(item => console.log(${item.type}: \${item.count}));
}
};