Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Dan Ballard | d08af5722c | |
Dan Ballard | 96b3abbfa1 | |
Dan Ballard | da4ca314b8 | |
Dan Ballard | 78afdda3f0 | |
Dan Ballard | 34bccf463f |
8
README
8
README
|
@ -1,17 +1,13 @@
|
||||||
Checkers AI engine
|
Checkers AI engine
|
||||||
|
|
||||||
For Ruby 1.9.1
|
|
||||||
|
|
||||||
Right now I'm working on the search.
|
Right now I'm working on the search.
|
||||||
|
|
||||||
To test
|
To test
|
||||||
|
|
||||||
% load "checkers.rb"
|
% load "checkers.rb"
|
||||||
% b = Board.new
|
% b = Board.new
|
||||||
% b.play
|
% b.setup
|
||||||
|
|
||||||
also look at
|
and then to look
|
||||||
|
|
||||||
% b.search(TEAM_1)
|
% b.search(TEAM_1)
|
||||||
|
|
||||||
Right now entering jump moves or the AI playing jumps in the .play() interface may not work
|
|
||||||
|
|
105
checkers.rb
105
checkers.rb
|
@ -19,6 +19,7 @@ class Board
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup()
|
def setup()
|
||||||
|
initialize()
|
||||||
0.step(BOARD_SIZE) {|i|
|
0.step(BOARD_SIZE) {|i|
|
||||||
peice = (i < 3 ? TEAM_1_MAN : TEAM_2_MAN)
|
peice = (i < 3 ? TEAM_1_MAN : TEAM_2_MAN)
|
||||||
if [0,2,6].include? i
|
if [0,2,6].include? i
|
||||||
|
@ -226,7 +227,8 @@ class Board
|
||||||
moves.each { |move|
|
moves.each { |move|
|
||||||
board = dup()
|
board = dup()
|
||||||
board.do_move(x, y, move, team(x, y))
|
board.do_move(x, y, move, team(x, y))
|
||||||
boards.push(board)
|
boards.push( { "board" => board, "move" =>
|
||||||
|
{'from' => [x,y], 'to' => move}})
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -234,7 +236,9 @@ class Board
|
||||||
return boards
|
return boards
|
||||||
end
|
end
|
||||||
|
|
||||||
def score(team)
|
def score()
|
||||||
|
scores = {}
|
||||||
|
[TEAM_1, TEAM_2].each {|team|
|
||||||
score = 0
|
score = 0
|
||||||
score += @stats[team]['count']
|
score += @stats[team]['count']
|
||||||
score += 12 - @stats[opposite_team(team)]['count']
|
score += 12 - @stats[opposite_team(team)]['count']
|
||||||
|
@ -243,57 +247,80 @@ class Board
|
||||||
elsif @stats[team]['count'] == 0
|
elsif @stats[team]['count'] == 0
|
||||||
score -= 12
|
score -= 12
|
||||||
end
|
end
|
||||||
return score
|
scores[team] = score
|
||||||
|
}
|
||||||
|
return scores
|
||||||
end
|
end
|
||||||
|
|
||||||
def search(team)
|
def search(team)
|
||||||
@top_depth = 10
|
return search_do(team, team, 0, 4, 100.0, 0.0, @stats.dup, [])
|
||||||
search_do(team, @top_depth, 100.0, 0.0, "R")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_do(team, depth, percent, last_percent, location)
|
# the owner of the search: affects pruning bonuses
|
||||||
#puts location
|
# team - current player this turn
|
||||||
if depth == 0
|
# current depth - counting up to max_depth
|
||||||
#puts "DONE"
|
# max_depth - when we should stop our search
|
||||||
return score(team)
|
# my_percent - the percent range this work covers
|
||||||
end
|
# done_percent - the percent of work already done
|
||||||
max = -100
|
# stats - stats from 2 turns ago, ie before most recent opponent turn
|
||||||
|
# maxs - depth indexed array of max scores
|
||||||
|
def search_do(owner, team, current_depth, max_depth, my_percent, done_percent, stats, maxs)
|
||||||
|
#puts current_depth.to_s + '/' + max_depth.to_s + ' ' + done_percent.to_s + "%"
|
||||||
|
|
||||||
|
if current_depth < maxs.length and score()[team] < maxs[current_depth][team]
|
||||||
|
return score()
|
||||||
|
end
|
||||||
|
if current_depth >= maxs.length or score()[team] > maxs[current_depth][team]
|
||||||
|
maxs[current_depth] = score()
|
||||||
|
end
|
||||||
|
|
||||||
|
if current_depth >= max_depth
|
||||||
|
return score()
|
||||||
|
end
|
||||||
|
|
||||||
#if team == TEAM_1
|
|
||||||
# puts depth.to_s + ": TEAM_1's turn:"
|
|
||||||
#else
|
|
||||||
# puts depth.to_s + ": TEAM_2's turn:"
|
|
||||||
#end
|
|
||||||
#puts to_s #moves[0].to_s
|
|
||||||
if @stats[TEAM_1]['count'] == 0
|
if @stats[TEAM_1]['count'] == 0
|
||||||
puts "TEAM_2 WON!"
|
puts "TEAM_2 WON!"
|
||||||
return score(team)
|
return score()
|
||||||
elsif @stats[TEAM_2]['count'] == 0
|
elsif @stats[TEAM_2]['count'] == 0
|
||||||
puts "TEAM_1 WON!"
|
puts "TEAM_1 WON!"
|
||||||
return score(team)
|
puts to_s
|
||||||
|
return score()
|
||||||
else
|
else
|
||||||
moves = gen_next_move_boards(team)
|
moves = gen_next_move_boards(team)
|
||||||
if moves == []
|
if moves == []
|
||||||
puts "NO MOVES AVAILABLE?"
|
puts "NO MOVES AVAILABLE?"
|
||||||
return score(team)
|
return score()
|
||||||
else
|
else
|
||||||
|
jumps = moves.find_all { |item| item['move'][0].is_a?(Array)}
|
||||||
|
if jumps.length > 0
|
||||||
|
moves = jumps
|
||||||
|
end
|
||||||
done = 0.0
|
done = 0.0
|
||||||
item_percent = percent/moves.length
|
item_percent = my_percent/moves.length
|
||||||
|
max = nil
|
||||||
for i in 0..moves.length-1 do
|
for i in 0..moves.length-1 do
|
||||||
#moves.each { |move|
|
depth_mod = 0
|
||||||
move = moves[i]
|
move = moves[i]['board']
|
||||||
#puts "SEARCH"
|
# modify depth on piece loss
|
||||||
sub_score = move.search_do(opposite_team(team), depth -1, item_percent, last_percent+done, location + "." +i.to_s )
|
if stats[team]['count'] > move.stats[team]['count']
|
||||||
|
# search less is search owner lost peices
|
||||||
|
#if owner == team
|
||||||
|
# depth_mod = -4
|
||||||
|
#else
|
||||||
|
# depth_mod = 4
|
||||||
|
#end
|
||||||
|
end
|
||||||
|
sub_score = move.search_do(owner, opposite_team(team), current_depth + 1, max_depth + depth_mod, item_percent, done_percent+done, @stats.dup, maxs)
|
||||||
done += item_percent
|
done += item_percent
|
||||||
if done >= 0.0001
|
if done >= 10.0
|
||||||
last_percent += done;
|
done_percent += done;
|
||||||
puts "%.5f" % last_percent + "% depth: " + depth.to_s + " max: " + max.to_s
|
puts "%.2f" % done_percent + "% depth: " + current_depth.to_s + "/" + max_depth.to_s + " max: " + maxs.to_s
|
||||||
done = 0.0
|
done = 0.0
|
||||||
end
|
end
|
||||||
#puts "Score: " + sub_score.to_s
|
#puts "Score: " + sub_score.to_s
|
||||||
if sub_score > max
|
if max == nil or sub_score[team] > max[team]
|
||||||
max = sub_score
|
max = sub_score
|
||||||
|
max['move'] = moves[i]['move']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return max
|
return max
|
||||||
|
@ -325,7 +352,7 @@ class Board
|
||||||
|
|
||||||
# todo: deal with loss when no move avail
|
# todo: deal with loss when no move avail
|
||||||
def play()
|
def play()
|
||||||
setup()
|
#setup()
|
||||||
color = ''
|
color = ''
|
||||||
while color != 'w' and color != 'b'
|
while color != 'w' and color != 'b'
|
||||||
print "Choose color ([W]hite or [B]lack): "
|
print "Choose color ([W]hite or [B]lack): "
|
||||||
|
@ -363,8 +390,11 @@ class Board
|
||||||
print "to: "
|
print "to: "
|
||||||
to = gets().strip!
|
to = gets().strip!
|
||||||
from = parse_coords(from)
|
from = parse_coords(from)
|
||||||
to = parse_coords(to)
|
to = to.split(",").map {|c| parse_coords(c.strip)}
|
||||||
puts to.to_s + " or " + from.to_s
|
if to.length == 1
|
||||||
|
to = to[0]
|
||||||
|
end
|
||||||
|
puts "from "+ from.to_s + " to " + to.to_s
|
||||||
if !to or !from
|
if !to or !from
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
@ -379,6 +409,13 @@ class Board
|
||||||
do_move(from[0], from[1], to, team)
|
do_move(from[0], from[1], to, team)
|
||||||
else
|
else
|
||||||
puts "AI MOVE"
|
puts "AI MOVE"
|
||||||
|
info = search(team)
|
||||||
|
move = info['move']
|
||||||
|
if move == nil
|
||||||
|
puts "NO MOVE!!!"
|
||||||
|
else
|
||||||
|
do_move(move['from'][0], move['from'][1], move['to'], team(move['from'][0], move['from'][1]))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if @stats[TEAM_1]['count'] == 0
|
if @stats[TEAM_1]['count'] == 0
|
||||||
|
|
Loading…
Reference in New Issue