knucklebones/ai.lua
2023-08-12 11:36:14 +02:00

126 lines
3.8 KiB
Lua

--[[
List of actions, by order of priority:
- Complete a 3 dice combo 4-6
- Cancel a 3 dice combo 4-6
- Complete a 3 dice combo 1-3
- Complete a 2 dice combo 4-6
- Cancel a 3 dice combo 1-3
- Complete a 2 dice combo 1-3
- Cancel a 2 dice combo 4-6
- Cancel a 2 dice combo 1-3
- Look at the column's sum before removing a die.
It if is <=15, try to keep it as is, unless you're removing a 6 (or a 5)
]]
---Returns the column indexes (1-based) with completable combos
---@param dice table The 2d table with dice values
---@param value integer The dice value to place
---@param len 2|3 The possible combo length
---@return table The columns list (1-based)
function get_combos_to_complete(dice, value, len)
local ids = {}
for col = 1, 3 do
if table.count(dice[col], 0) >= 1
and table.count(dice[col], value) == len - 1 then
table.insert(ids, col)
end
end
return ids
end
---@param mine table "My" 2d table with dice values
---@param other table The "other" (opponent) 2d table with dice values
---@param value integer The dice value to place
---@param len 2|3 The possible combo length
---@return table The columns list (1-based)
function get_combos_to_cancel(mine, other, value, len)
local ids = {}
for col = 1, 3 do
if table.count(mine[col], 0) >= 1
and table.count(other[col], value) == len - 1 then
table.insert(ids, col)
end
end
return ids
end
function get_most_empty_cols(dice)
local ids = {}
for z = 3, 1, -1 do
for col = 1, 3 do
if table.count(dice[col], 0) == z then
table.insert(ids, col)
end
end
if #ids > 0 then return ids end
end
end
---Place the die in the best possible column
---@param mine table The 2d table of "my" dice
---@param other any The 2d table of the "other" dice
---@param die integer The die to place
---@return integer # The column where to place the die
function ai_pick_column(mine, other, die)
trace("--")
trace("AI")
trace("--")
if die >= 4 then
--#region Complete a 3 combo 4-5-6
local combos = get_combos_to_complete(mine, die, 3)
if #combos > 0 then
trace("Making a 3 combo with " .. die)
return math.randomitem(combos)
end
--#endregion Complete a 3 combo 4-5-6
-- #region Cancel a 3-dice combo 4-5-6
combos = get_combos_to_cancel(mine, other, die, 3)
if #combos > 0 then
trace("Cancelling a 3 combo with " .. die)
return math.randomitem(combos)
end
--#endregion Cancel a 3-dice combo 4-5-6
-- #region Complete a 2 combo 4-5-6
combos = get_combos_to_complete(mine, die, 2)
if #combos > 0 then
trace("Making a 2 combo with " .. die)
return math.randomitem(combos)
end
-- #endregion Complete a 2 combo 4-5-6
end
-- #region Complete a 3 combo 1-2-3
combos = get_combos_to_complete(mine, die, 3)
if #combos > 0 then
trace("Making a 3 combo with " .. die)
return math.randomitem(combos)
end
-- #endregion Complete a 3 combo 1-2-3
-- #region Complete a 2 combo 1-2-3
combos = get_combos_to_complete(mine, die, 2)
if #combos > 0 then
trace("Making a 2 combo with " .. die)
return math.randomitem(combos)
end
-- #endregion Complete a 2 combo 1-2-3
-- #region Random column
-- TODO: if 5-6, attack the opponent.
-- TODO: else, chose the column with the lowest sum
-- TODO: it's best to AVOID attacking the opponent when his sum is <= 15
-- TODO: it's best to avoid canceling 1-2 values
trace("Placing " .. die .. " at random")
return math.randomitem(get_most_empty_cols(mine))
-- #endregion Random column
end