Skip to content

Commit 1436d75

Browse files
committed
Added Negamax
1 parent 8453ac0 commit 1436d75

5 files changed

Lines changed: 143 additions & 0 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
-- Search tree class handler implementation
2+
3+
local PATH = (...):gsub('handlers.tree_handler$','')
4+
local class = require (PATH .. '.utils.class')
5+
6+
7+
local tree = class ()
8+
9+
-- Tree initialization
10+
function tree:initialize()
11+
self.nodes = {}
12+
end
13+
14+
-- Adds a node in the tree
15+
function tree:addNode(name, parent, value)
16+
assert(not self.nodes[name], 'node already exist')
17+
local node = {
18+
name = name, value = value,
19+
parent = parent, children = {}
20+
}
21+
if parent then
22+
parent = self:getNode(parent)
23+
assert(parent, 'parent not found')
24+
table.insert(parent.children, node)
25+
end
26+
if not self.head then self.head = node end
27+
table.insert(self.nodes, node)
28+
end
29+
30+
-- Get the node by its name
31+
function tree:getNode(name)
32+
for i, node in ipairs(self.nodes) do
33+
if node.name == name then return node end
34+
end
35+
end
36+
37+
-- Checks if a given node is terminal (leaf) in the search tree
38+
function tree:isLeaf(node)
39+
return #node.children == 0
40+
end
41+
42+
-- Returns the node value
43+
function tree:heuristic(node)
44+
return node.value
45+
end
46+
47+
-- Returns the node's children
48+
function tree:children(node)
49+
return node.children
50+
end
51+
52+
return tree

Negamax/Lua/Yonaba/negamax.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-- Negamax search implementation
2+
-- See: http://en.wikipedia.org/wiki/Negamax
3+
4+
-- Internal recursive Minimax search
5+
local function negamax(tree, node, depth, flag)
6+
if depth == 0 or tree:isLeaf(node) then
7+
return tree:heuristic(node) * flag
8+
end
9+
local children = tree:children(node)
10+
local bestScore = -math.huge
11+
for i, child in ipairs(children) do
12+
bestScore = math.max(bestScore, -negamax(tree, child, depth - 1, -flag))
13+
end
14+
return bestScore
15+
end
16+
17+
-- Performs Negamax search
18+
-- node : the node from where to start the search, usually the head node
19+
-- tree : the search tree
20+
-- depth : the maximum depth of search
21+
-- flag : the player (+1) or the opponent (-1)
22+
return function(node, tree, depth, flag)
23+
flag = (flag / math.abs(flag)) -- Gets the sign (either +1 or -1)
24+
return negamax(tree, node, depth, flag)
25+
end
26+
27+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
-- Tests for alpha_beta_pruning.lua
2+
local negamax = require 'negamax'
3+
4+
local total, pass = 0, 0
5+
6+
local function dec(str, len)
7+
return #str < len
8+
and str .. (('.'):rep(len-#str))
9+
or str:sub(1,len)
10+
end
11+
12+
local function run(message, f)
13+
total = total + 1
14+
local ok, err = pcall(f)
15+
if ok then pass = pass + 1 end
16+
local status = ok and 'PASSED' or 'FAILED'
17+
print(('%02d. %68s: %s'):format(total, dec(message,68), status))
18+
end
19+
20+
run('Testing Negamax', function()
21+
local tree = require 'handlers.tree_handler'
22+
23+
local t = tree()
24+
t:addNode('A',nil,0)
25+
t:addNode('B1','A',0)
26+
t:addNode('B2','A',0)
27+
t:addNode('B3','A',0)
28+
29+
t:addNode('C1','B1',4)
30+
t:addNode('C2','B1',12)
31+
t:addNode('C3','B1',7)
32+
33+
t:addNode('C4','B2',10)
34+
t:addNode('C5','B2',5)
35+
t:addNode('C6','B2',6)
36+
37+
t:addNode('C7','B3',1)
38+
t:addNode('C8','B3',2)
39+
t:addNode('C9','B3',3)
40+
41+
local head = t:getNode('A')
42+
assert(negamax(head, t, 3, 1) == 5)
43+
assert(negamax(head, t, 3, -1) == -3)
44+
end)
45+
46+
print(('-'):rep(80))
47+
print(('Total : %02d: Pass: %02d - Failed : %02d - Success: %.2f %%')
48+
:format(total, pass, total-pass, (pass*100/total)))

Negamax/Lua/Yonaba/utils/class.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- Minimalistic class implementation
2+
3+
local class = function(attr)
4+
local klass = attr or {}
5+
klass.__index = klass
6+
klass.__call = function(_,...) return klass:new(...) end
7+
function klass:new(...)
8+
local instance = setmetatable({}, klass)
9+
if klass.initialize then klass.initialize(instance, ...) end
10+
return instance
11+
end
12+
return setmetatable(klass,{__call = klass.__call})
13+
end
14+
15+
return class

Negamax/tags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Search,Graphs,Minimax

0 commit comments

Comments
 (0)