Logo for Tick5 Game

What's new
About
Download
License
Screenshots
Manual
Tutorial
sf.net page
Contact


SourceForge.net Logo

Image of Lua Logo

Image for wxWidgets Logo

7. Make it less deterministic

Now, our program is able to attack and defend itself as well. However, the moves are deterministic, which makes it less fun to play with. In this section, we'll make the program less deterministic.

Let's open boora-0.6.wz with a text editor and save it as boora-0.7.wz.

Modify function makemove() of AI class to accommodate the newly-added function exploringmove(). (Listing 7-1)

   -- a method that makes a move
local function makemove( ai, board )
if board:isempty() then
return fixedmove()
end

local x, y, color = board:lastmove()
hotspots:log( x, y )

evalmoves( board )
if winning() then
x, y = greedymove()
elseif threatening( board, x, y ) then
x, y = defend( board, x, y )
else
x, y = exploringmove() greedymove()
end

hotspots:log( x, y )

return x, y
 end

Listing 7-1

Instead of always choosing the move that has the biggest value, function
exploringmove() randomly picks up a move among those that have top values. (Listing 7-2) The for-loop counts the number of moves which have top values. It compares the values of moves with the biggest, and chooses these whose the relative difference is less than delta.  Variable delta takes values between 0 and 1 and determines the randomness of the program: the bigger the value, the less deterministic and the weaker the program.

   -- randomly pick up a move among those that have top values 
local function exploringmove()
assert( table.getn( movelist ) >= 1 )

local total = table.getn( movelist )
local valmax = movelist[1].val

-- count moves that have top values
local topmoves = 0
for i = 2, total, 1 do
if (valmax - movelist[i].val)/valmax > delta then
break;
end
topmoves = i
end

-- randomly pick up one
local index = 1
if topmoves >= 2 then
index = math.random( 1, topmoves )
end

return hotspots:get( movelist[index].idx )
end

Listing 7-2

Add
delta  as a data member and initialize it in initDelta(). (Listing 7-3)  Function initDelta() guarantees that delta gets a valid value.

-- AI class
-----------------------
do
local bound = nil
local hotspots = nil
local mystone = nil
local movelist = nil
local delta = nil

local function initDelta( delta )
local default = 0.5

if delta == nil then
return default
elseif delta < 0 or delta > 1 then
return default
else
return delta
end
end

Listing 7-3

Accordingly, modify initAI()to invoke initDelta() and set random number seed.

   local function initAI( board, d )
if bound == nil then
bound = board:dimension() - 1
hotspots = newHotspots( bound, 2 )
mystone = mycolor()
delta = initDelta( d )
math.randomseed( os.time() )
end
end

Listing 7-4

Modify function
newAI() in order to pass in a value to delta. (Listing 7-5)

   function newAI( board, delta )
initAI( board, delta )
return setmetatable( {}, metatbl )
end

Listing 7-5

Modify function
tick5think(). (Listing 7-5) We choose 0.15 for delta, because we want randomness but don't want the program too weak.

function tick5think( board )
AI = newAI( board, 0.15 )
return AI:makemove( board )
end

Listing 7-5

Play against the program. We notice that its moves are less deterministic. Let it play against predecessor boora-0.6.wz, it roughly has the same chance to win, no matter whether it plays black or white stone.