login

<     >

2023-11-22 11:03:01 (UTC-03:00)

Marcel Rodrigues <marcelgmr@gmail.com>

rewrite bot

diff --git a/yacht.lua b/yacht.lua
index 731037d..c0a5432 100644
--- a/yacht.lua
+++ b/yacht.lua
@@ -5,6 +5,14 @@ local cats = {
     "choice", "yacht", "1s", "2s", "3s", "4s", "5s", "6s"
 }
 
+local function cat_index(cat)
+    for i, c in ipairs(cats) do
+        if c == cat then
+            return i
+        end
+    end
+end
+
 local function calc_total(sheet)
     local total = 0
     for _, cat in ipairs(cats) do
@@ -121,28 +129,28 @@ function Yacht:run_round()
         local sheet = self.sheets[i]
         local is_bot = p:sub(1, 1) == "C"
         local dice = self:do_rolls(is_bot)
-        local sel
+        local cat
         if is_bot then
-            sel = self.bot:pick(sheet, dice)
+            cat = self.bot:pick(sheet, dice)
+            assert(sheet[cat] == nil and cat_index(cat) ~= nil)
             self.term:delay(1)
-            for cur, cat in ipairs(cats) do
-                if sheet[cat] == nil then
+            for cur, curcat in ipairs(cats) do
+                if sheet[curcat] == nil then
                     self:putsel(cur)
                     self.term:delay(2)
                     self:remsel(cur)
-                    if cur == sel then
+                    if curcat == cat then
                         break
                     end
                 end
             end
             self.term:delay(2)
         else
-            sel = self:pick()
+            cat = cats[self:pick()]
         end
-        local cat = cats[sel]
         local points = calc_points(dice, cat)
         sheet[cat] = points
-        self:putpoints(sel, points)
+        self:putpoints(cat_index(cat), points)
         self.term:goto(2+7*(i-1), 2)
         io.write(("%3d"):format(calc_total(sheet)))
         self.term:get_key()
@@ -386,44 +394,155 @@ end
 local Bob = {}
 Bob.__index = Bob
 
+local function log(msg)
+    --~ io.write("\x1B7")       -- save cursor position
+    --~ io.write("\x1B[15;1H")  -- goto row 15, col 1
+    --~ io.write("\x1B[2K")     -- clear line
+    --~ io.write(msg)           -- print msg
+    --~ io.write("\x1B8")       -- restore cursor position
+end
+
 function Bob:select(sheet, dice, roll)
     local sum, hist, min_count, max_count = calc_data(dice)
     local sel = {}
-    if max_count > 1 then
+    if sheet["full-house"] == nil then
+        local rep = {}
+        for i = 3, 6 do
+            if hist[i] >= 2 then
+                table.insert(rep, i)
+            end
+        end
+        if #rep == 2 then
+            for i = 1, 5 do
+                sel[i] = hist[dice[i]] >= 2
+            end
+            log("full-house")
+            return sel
+        end
+    end
+    if sheet["yacht"] == nil and max_count >= 4 then
         for i = 1, 5 do
-            sel[i] = hist[dice[i]] == max_count
+            sel[i] = hist[dice[i]] >= 4
         end
+        log("yacht")
+        return sel
     end
-    return sel
+    if sheet["little-straight"] == nil or sheet["big-straight"] == nil then
+        local little_match, big_match
+        little_match = (hist[1] > 0) and 1 or 0
+        big_match = (hist[6] > 0) and 1 or 0
+        for i = 2, 5 do
+            if hist[i] > 0 then
+                little_match = little_match + 1
+                big_match = big_match + 1
+            end
+        end
+        local cat
+        if sheet["little-straight"] ~= nil then
+            if big_match >= 4 then
+                cat = "big-straight"
+            end
+        elseif sheet["big-straight"] ~= nil then
+            if little_match >= 4 then
+                cat = "little-straight"
+            end
+        elseif math.max(big_match, little_match) >= 4 then
+            if big_match > little_match then
+                cat = "big-straight"
+            else
+                cat = "little-straight"
+            end
+        end
+        local tosel
+        if cat == "little-straight" then
+            tosel = {1, 1, 1, 1, 1, 0}
+        elseif cat == "big-straight" then
+            tosel = {0, 1, 1, 1, 1, 1}
+        end
+        if cat ~= nil then
+            for i = 1, 5 do
+                local d = dice[i]
+                if tosel[d] > 0 then
+                    sel[i] = true
+                    tosel[d] = tosel[d] - 1
+                end
+            end
+            log(cat)
+            return sel
+        end
+    end
+    if max_count >= 3 or sheet["choice"] ~= nil or sum < 12 then
+        local d
+        for i = 1, 6 do
+            if hist[i] == max_count then
+                d = i
+                break
+            end
+        end
+        local cat = cats[d+6]
+        if sheet[cat] == nil or (sheet["four-of-a-kind"] == nil and d > 3) then
+            for i = 1, 5 do
+                sel[i] = dice[i] == d
+            end
+            log("repeat "..d)
+            return sel
+        end
+    end
+    if sheet["choice"] == nil then
+        for i = 1, 5 do
+            sel[i] = dice[i] > 3
+        end
+        log("choice")
+        return sel
+    end
+    log("discard roll")
+    return {}
 end
 
 function Bob:pick(sheet, dice, roll)
-    local min_points, max_points = 99, 0
-    local sel, sel_min, sel_max
-    for cur, cat in ipairs(cats) do
-        if sheet[cat] == nil then
-            local points = calc_points(dice, cat)
-            if points > max_points then
-                sel_max = cur
-                max_points = points
-            end
-            if points > 0 and points < min_points then
-                sel_min = cur
-                min_points = points
-            end
+    local sum, hist, min_count, max_count = calc_data(dice)
+    local good_cats = {"yacht", "four-of-a-kind", "full-house", "little-straight", "big-straight"}
+    local good_mins = {1, 16, 17, 1, 1}
+    for i, cat in ipairs(good_cats) do
+        local thresh = good_mins[i]
+        if sheet[cat] == nil and calc_points(dice, cat) >= thresh then
+            log("good match: "..cat)
+            return cat
         end
     end
-    if max_points > 20 or (sel_max ~= nil and sel_max > 6) then
-        sel = sel_max
-    else
-        sel = sel_min
+    if sheet["choice"] == nil and sum >= 20 then
+        log("ok match: choice")
+        return "choice"
     end
-    if sel == nil then
-        repeat
-            sel = self.prng:randint(1, #cats)
-        until sheet[cats[sel]] == nil
+    for i = 1, 6 do
+        local cat = i.."s"
+        if sheet[cat] == nil and hist[i] >= 2 then
+            log("ok match: "..cat)
+            return cat
+        end
     end
-    return sel
+    -- no good pick, discard a sane item
+    local bad_cats = {"1s", "2s", "3s", "little-straight", "big-straight"}
+    for _, cat in ipairs(bad_cats) do
+        if sheet[cat] == nil then
+            log("discard bad")
+            return cat
+        end
+    end
+    -- discard anything with points (useful on last few rounds)
+    for _, cat in ipairs(bad_cats) do
+        if sheet[cat] == nil  and calc_points(dice, cat) > 0 then
+            log("discard with points")
+            return cat
+        end
+    end
+    -- no sane discard possible, discard anything
+    log("insane discard")
+    local cat
+    repeat
+        cat = cats[self.prng:randint(1, 12)]
+    until sheet[cat] == nil
+    return cat
 end
 
 local yacht = new_yacht(Bob)