Skip to content

Instantly share code, notes, and snippets.

@danba340
Created November 14, 2020 09:22
Show Gist options
  • Save danba340/09b87459a56d81eb60f5eea8685d11e9 to your computer and use it in GitHub Desktop.
Save danba340/09b87459a56d81eb60f5eea8685d11e9 to your computer and use it in GitHub Desktop.
Codingame Fall Challenge 2020 Boilerplate
console.error('Debug messages...');
function canBrew(inventory, order) {
const canBrew = true
for(const [index, delta] of order.deltas.entries()) {
if(delta > inventory[index]){
canBrew = false
}
}
return canBrew
}
function orderByRupies(a,b) {
return b.rupies - a.rupies
}
while (true) {
const actionCount = parseInt(readline()); // the number of spells and recipes in play
const orders = []
const inventory = []
for (let i = 0; i < actionCount; i++) {
var inputs = readline().split(' ');
const actionId = parseInt(inputs[0]); // the unique ID of this spell or recipe
const actionType = inputs[1]; // in the first league: BREW; later: CAST, OPPONENT_CAST, LEARN, BREW
const delta0 = parseInt(inputs[2]); // tier-0 ingredient change
const delta1 = parseInt(inputs[3]); // tier-1 ingredient change
const delta2 = parseInt(inputs[4]); // tier-2 ingredient change
const delta3 = parseInt(inputs[5]); // tier-3 ingredient change
const price = parseInt(inputs[6]); // the price in rupees if this is a potion
const tomeIndex = parseInt(inputs[7]); // in the first two leagues: always 0; later: the index in the tome if this is a tome spell, equal to the read-ahead tax; For brews, this is the value of the current urgency bonus
const taxCount = parseInt(inputs[8]); // in the first two leagues: always 0; later: the amount of taxed tier-0 ingredients you gain from learning this spell; For brews, this is how many times you can still gain an urgency bonus
const castable = inputs[9] !== '0'; // in the first league: always 0; later: 1 if this is a castable player spell
const repeatable = inputs[10] !== '0'; // for the first two leagues: always 0; later: 1 if this is a repeatable player spell
orders.push({
id: actionId,
rupies: price,
deltas: [delta0,delta1,delta2,delta3]
})
}
for (let i = 0; i < 2; i++) {
var inputs = readline().split(' ');
const inv0 = parseInt(inputs[0]); // tier-0 ingredients in inventory
const inv1 = parseInt(inputs[1]);
const inv2 = parseInt(inputs[2]);
const inv3 = parseInt(inputs[3]);
const score = parseInt(inputs[4]); // amount of rupees
inventory.push(inv0, inv1, inv2, inv3)
}
const brewableOrders = orders.filter(order => canBrew(inventory, order))
const brewableOrdersByMostRupies = brewableOrders.sort(orderByRupies)
// in the first league: BREW <id> | WAIT; later: BREW <id> | CAST <id> [<times>] | LEARN <id> | REST | WAIT
if(brewableOrders.length){
console.log(`BREW ${brewableOrdersByMostRupies[0].id}`);
} else {
console.log(`WAIT`);
}
}
@Knogobert
Copy link

Fastnat på willHelpGoalSpell. Men hoppas du kan få nån inspiration från detta:

// Recipe Ex. { id: 55, price: 12, deltas: [ 0, -3, -2, 0 ] }
function canBrew(inventory, deltas) {
    return deltas.every((delta, index) => delta > inventory[index]);
}

// Spell Ex. { id: 79, castable: false, deltas: [ -1, 1, 0, 0 ] }
function canCast(inventory, deltas, castable) {
    if (!castable) return false
    return deltas.every((delta, index) => {
        // if not castable, but still needed for brewing something
        // if inventory has enough room
        if (delta > -1) return true
        if (delta < 0 && delta*-1 <= inventory[index]) return true
        return false
    });
}

function isGoalSpell(spell, recipe, inventory) {
    // if spell helps out on highest recipe tier, return true
    const spellDeltaHighestTier = spell.deltas.length - 1 - [...spell.deltas].reverse().findIndex((revDelta) => revDelta > 0);
    const recipeDeltaHighestTier = recipe.deltas.length - 1 - [...recipe.deltas].reverse().findIndex((revDelta) => revDelta < 0);
    // console.error('spellDeltaHighestTier:', spellDeltaHighestTier);
    // console.error('recipeDeltaHighestTier:', recipeDeltaHighestTier);
    // console.error('inventory[recipeDeltaHighestTier]', inventory[recipeDeltaHighestTier]);
    if (
        spellDeltaHighestTier === recipeDeltaHighestTier // spell helps out recipe on highest tier
        && inventory[recipeDeltaHighestTier] + recipe.deltas[recipeDeltaHighestTier] < 0 // and recipe is not yet fulfilled in highest inv tier (ex. 0 - 1 < 0)
    ) {
        // console.error('GOT GOALSPELL:', spell);
        return true
    }
    return false
}

function willHelpGoalSpell(spell, goalSpell, inventory) {
    if (spell.isGoalSpell) return true
    console.error('HELP - goalSpell', goalSpell);
    console.error('HELP - inventory', inventory);
    console.error('HELP - spell', spell);
    // if goalSpell has minus on something in inventory that this spell can help out with, return true
    if (
        goalSpell.deltas.some((gDelta, i) => {
            console.error('HELP - gDelta', gDelta);
            console.error('HELP - inventory[i]', inventory[i]);
            console.error('HELP - spell.deltas[i]', spell.deltas[i]);
            console.error('HELP - gDelta + inventory[i] >= 0', gDelta + inventory[i] >= 0);
            console.error('HELP - gDelta + spell.deltas[i] >= 0', gDelta + spell.deltas[i] >= 0);
            if (
                gDelta + inventory[i] >= 0
                && gDelta + spell.deltas[i] >= 0
            ) {
                return true
            }
            return false
        })
    ) {
        console.error('GOT HELPFUL GOALSPELL:', spell);
        return true
    }
    return false
}
// function getGoalSpell(spell, recipe, inventory) {
//     // if spell helps out on highest recipe tier, return spell
//     console.error('spellDeltas:', spell.deltas);
//     console.error('recipeDeltas:', recipe.deltas);
//     const spellDeltaHighestTier = spell.deltas.length - 1 - [...spell.deltas].reverse().findIndex((rDelta) => rDelta > 0);
//     const recipeDeltaHighestTier = recipe.deltas.length - 1 - [...recipe.deltas].reverse().findIndex((rDelta) => rDelta < 0);
//     console.error('spellDeltaHighestTier:', spellDeltaHighestTier);
//     console.error('recipeDeltaHighestTier:', recipeDeltaHighestTier);
//     console.error('inventory[recipeDeltaHighestTier]', inventory[recipeDeltaHighestTier]);
//     console.error('inventory[recipeDeltaHighestTier] + recipe.deltas[recipeDeltaHighestTier] < 0:', inventory[recipeDeltaHighestTier] + recipe.deltas[recipeDeltaHighestTier] < 0);
//     if (
//         spellDeltaHighestTier === recipeDeltaHighestTier // spell helps out recipe on highest tier
//         && inventory[recipeDeltaHighestTier] + recipe.deltas[recipeDeltaHighestTier] < 0 // and recipe is not yet fulfilled in highest inv tier (ex. 0 - 1 < 0)
//     ) {
//         // if (!castable) return 'REST'
//         // if () { }
//         console.error('GOT GOALSPELL:', spell);
//         return true; // spell;
//     }
//     // if spell helps out the higher spell (which in turn helps better) return that lower spell
//     // else return getGoalSpell(spell, recipe);
//     // if spell is repeatable...
//     // if spell isn't castable, return empty, so that rest would be triggered
//     console.error('not goalspell:', spell);
//     return false;
// }

// BREW <id> | CAST <id> [<times>] | LEARN <id> | REST | WAIT
function getAction({
    goalRecipe,
    goalSpell,
    brewableRecipes,
    castableSpells,
}) {
    // console.error('goalRecipe', goalRecipe);
    // console.error('brewableRecipes', brewableRecipes);

    // // if goalSpell available in castableSpells, cast
    // // if goalSpell available and is repeatable, cast
    // // if goalSpell isn't available in castableSpells, rest
    // console.error('goalSpell', goalSpell);
    // console.error('castableSpells', castableSpells);

    // RETURN ACTION
    if (brewableRecipes.length){
        return `BREW ${brewableRecipes[0].id}`
    } else if (castableSpells.length){
        return `CAST ${castableSpells[0].id}`
    } else {
        return `REST`
        // return `WAIT`
    }
}
/* function getAction({
    inventory,
    allRecipes,
    allSpells,
    brewableRecipes,
    castableSpells,
}) {
    // find out goal recipe and cast spells to brew that recipe
    const goalRecipe = allRecipes[0] // TODO: calculate lowest moves compared to price
    console.error('goalRecipe', goalRecipe);

    // check what spell in allSpells is needed, then look for it in castableSpells
    // or perhaps the spell is too expensive for inventory, by many tiers
    // if castableSpell is repeatable and should be, cast
    // if castableSpell isn't available in allSpells, rest
    const goalSpell = allSpells.find((spell) => {
        console.error('spell', spell);
        // Check backwards 
        // const spellWillHelpGoal = spell.deltas.findIndex((delta, index) => {
        //     // WIP
        //     // Need a recursive function here that checks from delta4 to 1 on if a spell can help it out or not. If the first delta cant help, the one after that may etc.
        //     // For getting inv4, spell4 with inv4>0 is needed, but that in turn might need spell3 where it enables spell4's inv3-1 to be able to be run.


        //     if (delta > -1 && delta <= goalRecipe.deltas[index]) return true
        //     if (delta < 0 && delta*-1 <= goalRecipe.deltas[index]) return true
        //     console.error('Cant cast:', spell, index, delta, goalRecipe.deltas[index]);
        //     return false
        // });
        // if (spellWillHelpGoal > -1) return true
        if (getGoalSpell(spell, goalRecipe, inventory)) return true
        return false
    });
    console.error('goalSpell', goalSpell);

    // RETURN ACTION
    if (brewableRecipes.length){
        return `BREW ${brewableRecipes[0].id}`
    } else if (castableSpells.length){
        return `CAST ${castableSpells[0].id}`
    } else {
        return `REST`
        // return `WAIT`
    }
} */

while (true) {
    const actionCount = parseInt(readline()); // the number of spells and recipes in play
    const inventory = []
    let recipes = []
    let spells = []
    for (let i = 0; i < actionCount; i++) {
        var inputs = readline().split(' ');
        const actionId = parseInt(inputs[0]); // the unique ID of this spell or recipe
        const actionType = inputs[1]; // CAST, OPPONENT_CAST, LEARN, BREW
        const [ delta0, delta1, delta2, delta3 ] = [parseInt(inputs[2]), parseInt(inputs[3]), parseInt(inputs[4]), parseInt(inputs[5])]; // tier-0,1,2,3 ingredient change
        const price = parseInt(inputs[6]); // the price in rupees if this is a potion
        const tomeIndex = parseInt(inputs[7]); // in the first two leagues: always 0; later: the index in the tome if this is a tome spell, equal to the read-ahead tax; …: always 0; later: the amount of taxed tier-0 ingredients you gain from learning this spell; For brews, this is how many times you can still gain an urgency bonus
        const castable = inputs[9] !== '0'; // 1 if this is a castable player spell
        const repeatable = inputs[10] !== '0'; // for the first two leagues: always 0; later: 1 if this is a repeatable player spell
        if (actionType === 'CAST') {
            const deltas = [delta0,delta1,delta2,delta3]
            spells.push({
                id: actionId,
                deltas,
                canCast: canCast(inventory, deltas, castable),
                isGoalSpell: false,
                castable,
                // repeatable,
            })
        } else if (actionType === 'BREW') {
            const deltas = [delta0,delta1,delta2,delta3]
            recipes.push({
                id: actionId,
                deltas,
                canBrew: canBrew(inventory, deltas),
                isGoalRecipe: false,
                price,
            })
        }
    }
    for (let i = 0; i < 2; i++) {
        var inputs = readline().split(' ');
        const [ inv0, inv1, inv2, inv3 ] = [parseInt(inputs[0]), parseInt(inputs[1]), parseInt(inputs[2]), parseInt(inputs[3])]; // tier-0,1,2,3 ingredients in inventory
        const score = parseInt(inputs[4]); // amount of rupees
        inventory.push(inv0, inv1, inv2, inv3)
    }

    // Set goals
    recipes = recipes.map((recipe, index) => ({
        ...recipe,
        isGoalRecipe: index === 0, // isGoalRecipe(),
    }));
    const goalRecipe = recipes.find((recipe) => recipe.isGoalRecipe);
    spells = spells.map((spell, index) => ({
        ...spell,
        isGoalSpell: isGoalSpell(spell, goalRecipe, inventory),
    }));
    const goalSpell = spells.find((spell) => spell.isGoalSpell);
    spells = spells.map((spell) => ({
        ...spell,
        willHelpGoalSpell: willHelpGoalSpell(spell, goalSpell, inventory),
    }));

    console.error('inventory [my, their]:', inventory);
    const brewableRecipes = recipes
        // .filter(recipe => canBrew(inventory, recipe))
        .filter(recipe => recipe.canBrew)
        .sort((a,b) => b.price - a.price)
    console.error('All recipes:', recipes);
    // console.error('Brewable recipes (sorted):', brewableRecipes);

    const castableSpells = spells
        .filter(spell => spell.canCast)
        // .filter(spell => spell.isGoalSpell)
        .sort((a,b) => b.id - a.id)
    console.error('All spells:', spells);
    // console.error('Castable spells (sorted):', castableSpells);

    // BREW <id> | CAST <id> [<times>] | LEARN <id> | REST | WAIT
    console.log(getAction({
        allRecipes: recipes,
        allSpells: spells,
        brewableRecipes,
        castableSpells,
    }));
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment