Skip to content

Instantly share code, notes, and snippets.

@vexorian
Created June 1, 2015 20:37
Show Gist options
  • Save vexorian/06c237f22d5a4befafa5 to your computer and use it in GitHub Desktop.
Save vexorian/06c237f22d5a4befafa5 to your computer and use it in GitHub Desktop.
A ruby class that parses a @massconnect4 tweet and tries to return a reply as a string
# encoding: UTF-8
# A ruby class that parses a @massconnect4 tweet and tries to return a reply as
# a string. Your bot should handle the tweet detecting and reading.
#
# connect4 = MassConnect4Player.new( team, unclever)
# team is your team either :sun or :moon
# unclever is a float from 0.0 to 1.0 , the higher this is the worse it will play
#
# connect4.play(tweet_text) , take a tweet text from @massconnect4, return a reply
# or nil if something went wrong.
#
# The current game logic is very bareboned, at least it doesn't fall to straight
# obvious traps (even with 1.0 uncleverness), however. I guess you could build
# a real AI from this. I guess.
#
# zlib licence, vexorian 2015
#
class MassConnect4Player
def initialize(team, unclever)
@unclever = unclever
if team == :sun
@team = :sun
@enemy = :moon
else
@team = :moon
@enemy = :sun
end
end
def get_cell(board, x,y)
return board[ 7*(5-y) + x ]
end
def set_cell(board, x,y, c)
board[ 7*(5-y) + x ] = c
end
def count_bad_traps(board)
traps = 0
for x in 0..6
for y in 0..5
for mov_y in [ [y,y+1,y+2,y+3], [y,y-1,y-2,y-3], [y,y,y,y] ]
for mov_x in [ [x,x+1,x+2,x+3], [x,x-1,x-2,x-3], [x,x,x,x] ]
x3 = mov_x[3]
y3 = mov_y[3]
if ( (x3 != x) || (y3 != y) ) && (0 <= x3 && x3 <= 6) && (0 <= y3 && y3 <= 5)
count_sun = 0
count_moon = 0
for i in 0..3
c = get_cell(board, mov_x[i], mov_y[i])
if c == @team
count_moon = count_moon + 1
end
if c == @enemy
count_sun = count_sun + 1
end
end
if (count_sun == 2) && (count_moon == 0)
traps = traps + 1
end
end
end
end
end
end
return traps
end
def count_traps(board)
traps = 0
for x in 0..6
for y in 0..5
for mov_y in [ [y,y+1,y+2,y+3], [y,y-1,y-2,y-3], [y,y,y,y] ]
for mov_x in [ [x,x+1,x+2,x+3], [x,x-1,x-2,x-3], [x,x,x,x] ]
x3 = mov_x[3]
y3 = mov_y[3]
if ( (x3 != x) || (y3 != y) ) && (0 <= x3 && x3 <= 6) && (0 <= y3 && y3 <= 5)
count_moon = 0
good_empty = false
for i in 0..3
c = get_cell(board, mov_x[i], mov_y[i])
if c == @team
count_moon = count_moon + 1
end
if c == :empty
if (mov_y[i] > 0) && (get_cell(board, mov_x[i], mov_y[i]-1) == :empty)
good_empty = true
end
end
end
if (count_moon == 3) && good_empty
traps = traps + 1
end
end
end
end
end
end
return traps
end
def who_wins(board)
for x in 0..6
for y in 0..5
for mov_y in [ [y,y+1,y+2,y+3], [y,y-1,y-2,y-3], [y,y,y,y] ]
for mov_x in [ [x,x+1,x+2,x+3], [x,x-1,x-2,x-3], [x,x,x,x] ]
x3 = mov_x[3]
y3 = mov_y[3]
if ( (x3 != x) || (y3 != y) ) && (0 <= x3 && x3 <= 6) && (0 <= y3 && y3 <= 5)
# valid line
all_sun = true
all_moon = true
for i in 0..3
c = get_cell(board, mov_x[i], mov_y[i])
if c != :sun
all_sun = false
end
if c != :moon
all_moon = false
end
end
if all_sun
return :sun
end
if all_moon
return :moon
end
end
end
end
end
end
return :none
end
def play(tweet_text)
empty = "⬜"
sun = "🌞"
moon = "🌚"
board = []
tweet_text.split("").each do |s|
t = :none
if s.eql?(empty)
t = :empty
elsif s.eql?(sun)
t = :sun
elsif s.eql?(moon)
t = :moon
end
if t != :none
board = board + [t]
end
end
if board.size != 42
puts "massconnect wrong board size"
return nil
end
total_empty = board.count(:empty)
if total_empty == 42
return "4"
end
if total_empty == 41
if get_cell(board, 3,0) == :empty
return "4"
else
return ["3","5"].sample
end
end
win = []
available = []
#for y in [5,4,3,2,1,0]
# for x in 0..6
# if get_cell(board,x,y) == :empty
# print "."
# elsif get_cell(board,x,y) == :sun
# print "*"
# elsif get_cell(board,x,y) == :moon
# print "o"
# else
# print "?"
# end
# end
# puts ""
#end
#puts ""
best = nil
for x in 0..6
y = 0
while (get_cell(board, x,y) != :empty) && (y <= 5)
y = y + 1
end
if y <= 5
# can make the move by placing moon in x,y
set_cell(board, x,y, @team)
if who_wins(board) == @team
win = win + [x]
else
valid = true
for x2 in 0..6
y2 = 0
while (get_cell(board, x2,y2) != :empty) && (y2 <= 5)
y2 = y2 + 1
end
if y2 <= 5
set_cell(board, x2,y2, @enemy)
if who_wins(board) == @enemy
valid = false
end
set_cell(board, x2,y2, :empty)
end
end
if valid
available = available + [x]
traps = count_traps(board)
bad_traps = count_bad_traps(board)
if (best == nil) || (best[:traps] < traps) || ( (best[:traps] == traps) && (best[:bad_traps] > bad_traps) )
if best == nil
best = Hash.new
end
best[:move] = x
best[:traps] = traps
best[:bad_traps] = bad_traps
best[:count] = 1
elsif (best[:traps] == traps) && (best[:bad_traps] == bad_traps)
best[:count] = best[:count] + 1
if rand( 1 .. best[:count] ) == 1
best[:move] = x
end
end
end
end
set_cell(board, x,y, :empty)
end
end
puts "best = " + best.to_s
puts "win = " + win.to_s
puts "available = " + available.to_s
if win.size > 0
return (win.sample + 1).to_s
end
if available.size > 0
if (best != nil) && (rand > @unclever)
return (best[:move] + 1).to_s
end
return (available.sample + 1).to_s
end
return nil # we lose
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment