diff --git a/contestants/iprug/anders_player.rb b/contestants/iprug/anders_player.rb new file mode 100755 index 0000000..4220d04 --- /dev/null +++ b/contestants/iprug/anders_player.rb @@ -0,0 +1,81 @@ +class AndersPlayer + def initialize + @aim = Aim.new() + end + + def name + "Anders Player" + end + + def new_game + randy = rand(2) + if(randy == 1) + layout = [ + [rand(5), rand(2), 5, :across], + [rand(6), rand(2) + 2, 4, :across], + [rand(7), rand(2) + 4, 3, :across], + [rand(7), rand(2) + 6, 3, :across], + [rand(8), rand(2) + 8, 2, :across] + ] + else + layout = [ + [rand(2), rand(5), 5, :down], + [rand(2)+2, rand(6), 4, :down], + [rand(2)+4, rand(7), 3, :down], + [rand(2)+6, rand(7), 3, :down], + [rand(2)+8, rand(8), 2, :down] + ] + end + end + + def take_turn(state, ships_remaining) + @aim.test(state) + end +end + +class Aim + attr_accessor :x, :y + + def initialize + @x = -1 + @x_speed = 1 + @y = 0 + @y_speed = 0 + @right_border = 9 + @left_border = 0 + @top_border = 0 + @bottom_border = 9 + + end + + def test(state) + if @x >= @right_border && @x_speed == 1 + @x = @right_border + @x_speed = 0 + @y_speed = 1 + @top_border += 1 + end + if @y >= @bottom_border && @y_speed == 1 + @y = @bottom_border + @x_speed = -1 + @y_speed = 0 + @right_border -= 1 + end + if @x <= @left_border && @x_speed == -1 + @x = @left_border + @x_speed = 0 + @y_speed = -1 + @bottom_border -= 1 + end + if @y <= @top_border && @y_speed == -1 + @y = @top_border + @x_speed = 1 + @y_speed = 0 + @left_border += 1 + end + + @x += @x_speed + @y += @y_speed + [@x,@y] + end +end \ No newline at end of file diff --git a/contestants/iprug/death_bones_dan_player.rb b/contestants/iprug/death_bones_dan_player.rb new file mode 100755 index 0000000..91966aa --- /dev/null +++ b/contestants/iprug/death_bones_dan_player.rb @@ -0,0 +1,182 @@ +class DeathBonesDanPlayer + + def initialize + @taken_positions = [] + @positions = [] + + @shots = [] + end + + def log(message) + File.open('debug.log', 'a') { |f| f.write("#{Time.now} - #{message}\n") } + end + + def init_taken + (0..9).each do |x| + @taken_positions[x] = [] + (0..9).each do |y| + @taken_positions[x][y] = 0 + end + end + end + + def print_grid + + end + + def reserve_position (x,y,length,orientation) + + if orientation == :across + (x..length).each do |p| + @taken_positions[p][y] = 1 + end + else + (y..length).each do |p| + @taken_positions[x][p] = 1 + end + end + + end + + def has_space (x,y,length,orientation) + + if orientation == :across + (x..length).each do |p| + return false if @taken_positions[p][y] == 1 + end + else + (y..length).each do |p| + return false if @taken_positions[x][p] = 1 + end + end + + true + + end + + def generate_player_positions + + # initialise taken grid + init_taken + + ship_lengths = [5,4,3,3,2] + + ship_lengths.each do |z| + + upperbound = (10 - z) + + # upperbound = (10 - z) + + x = rand(upperbound) + y = rand(upperbound) + + orientation = :across + + placed = false + + while !placed + + orientation = orientation == :across ? :down : :across + + x = rand(upperbound) + y = rand(upperbound) + + # check ship position + if has_space(x,y,z,orientation) + + @positions << [x,y,z,orientation] + reserve_position x,y,z,orientation + + placed = true + + end + + end + + end + + log @positions.inspect + + @positions + + end + + def generate_static_positions + + [ + [0, 0, 5, :across], + [0, 1, 4, :across], + [0, 2, 3, :across], + [0, 3, 3, :across], + [0, 4, 2, :across] + ] + + end + + # battleship methods + + def name + "Death Bones Dan" + end + + def new_game + generate_player_positions + #generate_static_positions + end + + def take_turn(state, ships_remaining) + + last_was_hit = false + last_shot = [] + + # check on last shot + if @shots.length > 0 + last_shot = @shots.last + log "last: #{last_shot.inspect}" + last_was_hit = state[last_shot[1]][last_shot[0]] == :hit + end + + if !last_was_hit + + shot_x = rand(10) + shot_y = rand(10) + + until state[shot_y][shot_x] == :unknown + shot_x = rand(10) + shot_y = rand(10) + end + + else + + shot_x = rand(10) + shot_y = rand(10) + + until state[shot_y][shot_x] == :unknown + shot_x = rand(10) + shot_y = rand(10) + end + + # last_x_u = last_shot[0] + 2 + # last_y_u = last_shot[1] + 2 + # + # last_x_l = last_shot[0] - 2 + # last_y_l = last_shot[1] - 2 + # + # shot_x = last_x_l + rand(last_x_u + 1 - last_x_l) + # shot_y = last_x_l + rand(last_y_u + 1 - last_y_l) + # + # until state[shot_y][shot_x] == :unknown + # shot_x = last_x_l + rand(last_x_u + 1 - last_x_l) + # shot_y = last_x_l + rand(last_y_u + 1 - last_y_l) + # end + + end + + log "Shooting at #{shot_x}, #{shot_y}" + + @shots << [shot_x, shot_y] + + [shot_x, shot_y] + end + +end diff --git a/contestants/iprug/graham_player.rb b/contestants/iprug/graham_player.rb new file mode 100755 index 0000000..ca60b42 --- /dev/null +++ b/contestants/iprug/graham_player.rb @@ -0,0 +1,80 @@ +class GrahamPlayer + def initialize + @x=0 + @y=0 + @advance = 3 + @last_turn = [] + @on_a_roll = false + @direction_forward = true + end + + def name + "Graham Hadgraft" + end + + def new_game + [ + [rand(5), 0, 5, :across], + [rand(6), 4, 4, :across], + [rand(7), 5, 3, :across], + [rand(7), 6, 3, :across], + [rand(8), 8, 2, :across] + ] + end + + def take_turn(state, ships_remaining) + if @last_turn[0] != nil && last_turn(state) == :hit + @x += 1 + @on_a_roll = true + elsif @last_turn[0] != nil && @on_a_roll == true && last_turn(state) == :miss + @x -= 2 + @on_a_roll = false + + else + @x += @advance + end + + check_valid_coords(@x, @y) + check_if_shot(@x,@y, state) + + @last_turn = [@x, @y] + + end + + private + def last_turn(state) + state[@last_turn[1]][@last_turn[0]] + end + + def check_valid_coords(x,y) + if @x > 9 + @x -= 10 + @y += 1 + end + + if @y > 9 + @y=0 + end + end + + def check_if_shot (x, y, state) + while state[y][x] == :miss || state[y][x] == :hit + if @direction_forward == true + x += 1 + else + x -= 1 + end + + if x > 9 + x -= 10 + y += 1 + end + + if y > 9 + y=0 + end + @x = x + @y = y + end + end +end diff --git a/contestants/iprug/kerry_player.rb b/contestants/iprug/kerry_player.rb new file mode 100755 index 0000000..3374ff3 --- /dev/null +++ b/contestants/iprug/kerry_player.rb @@ -0,0 +1,95 @@ +module Randomiser + class << self + def coordinate + rand 10 + end + + def start_of_ship_with_length length + rand(10 - length) + end + + def direction + [:across, :down][rand(2)] + end + end +end + +class ShipPlacer + def initialize + @taken = [] + end + + def carrier + ship_of_length 5 + end + + def battleship + ship_of_length 4 + end + + def sub + ship_of_length 3 + end + + def cruiser + ship_of_length 3 + end + + def destroyer + ship_of_length 2 + end + + private + + def ship_of_length length + direction = Randomiser.direction + across_coord = Randomiser.coordinate + along_coord = Randomiser.start_of_ship_with_length length + try_again = false + taken = @taken + if direction == :across + x, y = along_coord, across_coord + (y..y+length).each do |y| + try_again ||= @taken.include? [x, y] + @taken << [x, y] + end + else + x, y = across_coord, along_coord + (x..x+length).each do |x| + try_again ||= @taken.include? [x, y] + @taken << [x, y] + end + end + if try_again + ship_of_length(length) + else + @taken = taken + [x, y, length, direction] + end + end +end + +class KerryPlayer + def initialize + @tried = [] + end + + def name + "Kerry" + end + + def new_game + placer = ShipPlacer.new + [placer.carrier, placer.battleship, placer.sub, placer.cruiser, placer.destroyer] + end + + def take_turn state, ships_remaining + x, y = Randomiser.coordinate, Randomiser.coordinate + if @tried.include? [x, y] + take_turn state, ships_remaining + else + @tried << [x, y] + [x, y] + end + end +end diff --git a/contestants/iprug/matthewR.rb b/contestants/iprug/matthewR.rb new file mode 100755 index 0000000..daaa569 --- /dev/null +++ b/contestants/iprug/matthewR.rb @@ -0,0 +1,209 @@ +class MatthewRPlayer + def initialize + @state = Array.new(10) { Array.new(10,:unknown) } + @last_coords = nil + @hits_list = [] + @last_ships = [] + @unalloc_sunk_len = 0 + @last_deltas = nil + end + + def name + "Matthew Robinson" + end + + def new_game + # top secret info. Ideally replace with a random choice (and/or try and make use of the probabilities) + + #[ [0,4,5, :down], [2,9,4, :across], [9,7,3, :down], [5,6,3, :across], [5,7,2, :down]] + @state = Array.new(10) { Array.new(10,:unknown) } + ship_lengths = [5,4,3,3,2] + ship_lengths.map do |len| + x,y,orient = nil + loop do + x=rand(10) + y=rand(10) + orient = (rand(2) == 1) ? :down : :across + break if ship_fits?(x,y,len,orient) + end + record_ship(x,y,len,orient) + [x,y,len,orient] + end + end + + def state_at(coords) + # return the state at this co-ordinate + # if co-ordinates are outside the grid return a default value of :miss + + x=coords[0] + y=coords[1] + if (0..9) === x and (0..9) === y + return @state[y][x] + else + return :miss + end + end + + def apply_ship(len) + counts = Array.new(10) { Array.new(10,0) } + [:down, :across].each do |orient| + 0.upto(9) do |x| + 0.upto(9) do |y| + if ship_fits?(x,y,len,orient) + 0.upto(len-1) do |delta| + if orient == :down + counts[y+delta][x]+=1 + elsif orient == :across + counts[y][x+delta]+=1 + end + end + end + end + end + end + return counts + end + + def ship_fits?(x,y,len,orient) + fits=true + 0.upto(len-1) do |delta| + if orient == :down + fits &= state_at([x,y+delta])==:unknown + elsif orient == :across + fits &= state_at([x+delta,y])==:unknown + end + end + fits + end + + def record_ship(x,y,len,orient) + 0.upto(len-1) do |delta| + if orient == :down + @state[y+delta][x]= :ship + elsif orient == :across + @state[y][x+delta]= :ship + end + end + end + + def total_count(counts) + counts.inject(0) do |acc,row| + acc + row.inject { |a,b| a+b } + end + end + + def normalise(counts,len) + total = total_count(counts) + factor = (total>0) ? (len * 1.0 / total) : 0 + + counts.map do |row| + row.map do |value| + value * factor + end + end + end + + def sum_counts(counts_arrays) + results = Array.new(10) { Array.new(10,0) } + + counts_arrays.each do |counts| + + 0.upto(9) do |x| + 0.upto(9) do |y| + results[y][x] = (results[y][x]) + (counts[y][x]) + end + end + end + return results + end + + def try_coords(coords) + #either return the co-ordinates if a valid move or else nil + state_at(coords) == :unknown ? coords : nil + end + + def sum_coords(a,b) + # return sum of two co-ordinates + x = a[0] + b[0] + y = a[1] + b[1] + [x,y] + end + + def coords_of_max(grid) + #return the [x,y] coords of the square with highest value + + m =-1 + x_of_max =-1 + y_of_max =-1 + + 0.upto(9) do |x| + 0.upto(9) do |y| + if grid[y][x] > m + m=grid[y][x] + x_of_max = x + y_of_max = y + end + end + end + + [x_of_max, y_of_max] + end + + + def find_ships(ships_remaining) + # return the square with the highest probability of hitting a ship + + probabilities_per_ship = ships_remaining.map do |ship_len| + normalise(apply_ship(ship_len), ship_len) + end + + coords_of_max(sum_counts(probabilities_per_ship)) + end + + def take_turn(state, ships_remaining) + @state = state + + shot=nil + + unless @last_coords.nil? + #see what happened with our previous shot + if state_at(@last_coords) == :hit + @hits_list << @last_coords + if @last_ships.length > ships_remaining.length + #we sunk a ship so work out which one + sunk_len = (@last_ships - ships_remaining).last + sunk_len ||= 3 # fix for length 3 ships (as we may have sunk first one and still have a len 3 ship in both lists) + @unalloc_sunk_len += sunk_len + if @hits_list.length == @unalloc_sunk_len + #all hits are due to these ship(s), so no need to search further + @hits_list = [] + @unalloc_sunk_len =0 + end + else + if @hits_list.length > 1 + #try carrying on in same direction + shot = try_coords(sum_coords(@last_coords, @last_deltas)) + end + end + end + + #if we haven't yet found a square, try searching around existing hits + if shot.nil? + @hits_list.each do |hit| + [[1,0], [-1,0], [0,1], [0,-1]].each do |deltas| + @last_deltas = deltas if shot.nil? + shot ||= try_coords(sum_coords(hit, deltas)) + end + end + end + end + + shot ||= find_ships(ships_remaining) #if nothing better to do, then open up a new area of the board + + #store relevant state + @last_coords= shot + @last_ships=ships_remaining.dup + shot # return the shot we want to take + end + +end #end of class diff --git a/contestants/iprug/matthew_bennett.rb b/contestants/iprug/matthew_bennett.rb new file mode 100755 index 0000000..c489228 --- /dev/null +++ b/contestants/iprug/matthew_bennett.rb @@ -0,0 +1,114 @@ +def out(*args) + puts *args +end + +class Array + def delta(arr) + [self[0] + arr[0], self[1] + arr[1]] + end + + def outside(lower, upper) + self[0] < lower[0] || self[1] < lower[1] || self[0] > upper[0] || self[1] > upper[1] + end +end + +class UndecisivePlayer + def name + "@undecisive (Matthew Bennett)" + end + + def new_game + @previous_moves = [] + random_starting_positions + end + + def take_turn(state, ships_remaining) + out "Taking turn..." + begin + if @real_shot && hit?(@latest_attempt, state) + out "HIT! #{@latest_attempt.inspect}" + @surroundings = false + @first_hit ||= @latest_attempt + @latest_good_attempt = @latest_attempt + @latest_attempt = try_a_surrounder + elsif(@latest_good_attempt) + out "Found a good shot...." + @latest_attempt = try_a_surrounder + else + @latest_attempt = random_shot + end + @real_shot = false + @real_shot = true unless @previous_moves.include? @latest_attempt + end until @real_shot + @previous_moves << @latest_attempt + @latest_attempt + end + + private + def hit?(attempt, state) + return false if attempt.nil? + state[ attempt[1] ][ attempt[0] ] == :hit + end + + def reset + out "resetting..." + @latest_attempt = nil + @latest_good_attempt = nil + @surroundings = [] + end + + def try_a_surrounder + out "Surrounding... #{@surroundings.inspect}" + @surroundings ||= [] + if @surroundings.length >= 4 + reset + if(@first_hit) + @latest_good_attempt = @first_hit + @first_hit = nil + #return random_shot + return try_a_surrounder + else + return random_shot + end + return random_shot + end + + begin + @surroundings << @latest_good_attempt.delta(surround_addition(@surroundings.length)) + end until within_bounds?(@surroundings.last) + + @surroundings.last + end + + def within_bounds?(shot) + !shot.outside([0,0], [9,9]) + end + + def random_shot + @first_hit = nil + [rand(10), rand(10)] + end + + def surround_addition(num) + case num % 4 + when 0 + [-1,0] + when 1 + [0,-1] + when 2 + [1,0] + when 3 + [0,1] + end + end + + def random_starting_positions + [ + [0, 0, 5, :across], + [2, 2, 4, :across], + [4, 3, 3, :across], + [5, 5, 3, :across], + [8, 7, 2, :across] + ] + end +end diff --git a/contestants/iprug/mega_ship_fucker.rb b/contestants/iprug/mega_ship_fucker.rb new file mode 100755 index 0000000..c552dad --- /dev/null +++ b/contestants/iprug/mega_ship_fucker.rb @@ -0,0 +1,112 @@ +module MSF + class Board + + NEIGHBOURS = [[0, -1], [1, 0], [0, 1], [-1, 0]] + + Point = Struct.new(:row, :column, :probability) + + def initialize + @sunk_ships = [] + @last_ships_remaining = [5, 4, 3, 3, 2] + @saved_move = nil + end + + def update(state, ships_remaining) + if @last_ships_remaining != ships_remaining + @sunk_ships << ship_sunk((@last_ships_remaining - ships_remaining).first) + end + @state = state + @ships_remaining = ships_remaining + end + + def make_move + squares = free_squares + squares = set_probabilities(squares) + squares = top_probs(squares) + #if squares.first.probability == 0 + #squares.each { |s| s.probability = ((s.row) % 2) * (s.column % 2) } + #squares = top_probs(squares) + #end + @saved_move = squares[rand(squares.size)] + [@saved_move.row, @saved_move.column] + end + + private + + def ship_sunk(size) + + end + + def free_squares + squares = [] + puts @state.inspect + @state.each_with_index do |row, column_index| + row.each_with_index do |value, row_index| + squares << Point.new(row_index, column_index, 0) if value == :unknown + end + end + squares + end + + def set_probabilities(squares) + squares.each do |square| + square.probability = neighbour_hit_count(square) + end + squares + end + + def neighbour_hit_count(square) + count = 0 + NEIGHBOURS.each do |dy, dx| + if value_at(square.row + dx, square.column + dy) == :hit + if value_at(square.row + (dx * 2), square.column + (dy * 2)) == :hit + count += 5 + else + if value_at(square.row + (dx * 3), square.column + (dy * 3)) == :hit + count += 3 + else + count += 1 + end + end + end + #count += 1 if value_at(square.row + dx, square.column + dy) == :hit + end + count + end + + def top_probs(squares) + sorted = squares.sort { |a, b| b.probability <=> a.probability } + top = sorted.first + sorted.reject { |s| s.probability < top.probability } + end + + def value_at(row, column) + return :unknown unless @state[column] + @state[column][row] + end + end +end + +class MeggaShipFuckerPlayer + + START_BOARDS = [ + [[4, 1, 5, :down], [2, 9, 4, :across], [6, 2, 3, :down], [0, 1, 3, :down], [9, 7, 2, :down]], + [[1, 4, 5, :across], [9, 2, 4, :down], [2, 6, 3, :across], [1, 0, 3, :across], [7, 9, 2, :across]], + [[1, 1, 5, :down], [6, 3, 4, :across], [4, 2, 3, :down], [5, 7, 3, :across], [3, 6, 2, :down]], + ] + + def name + "Megga Ship Fucker - ve eatz your shipz" + end + + def new_game + @board = MSF::Board.new + START_BOARDS[rand(START_BOARDS.size)] + end + + def take_turn(state, ships_remaining) + @board.update(state, ships_remaining) + @board.make_move + end +end + diff --git a/contestants/iprug/mrjaba_player.rb b/contestants/iprug/mrjaba_player.rb new file mode 100644 index 0000000..1aed5b2 --- /dev/null +++ b/contestants/iprug/mrjaba_player.rb @@ -0,0 +1,154 @@ +class Cluster + def initialize(on) + @x, @y = on + end + + def neighbours + [[1,0],[0,-1],[-1,0],[0,1]].collect do |dx, dy| + [@x + dx, @y+dy] + end.select{ |x,y| x >= 0 && y >= 0 && x < 10 && y < 10 } + end +end + +class ClusterFire + def initialize(cluster, shots) + @cluster = cluster + @shots = shots + @queue = @cluster.neighbours.select{|shot| !@shots.include?(shot)} + end + + def all + @queue + end +end + +class RandomFire + + def next(shots) + loop do + tmp_shot = [rand(10), rand(10)] + return tmp_shot if !shots.include?(tmp_shot) + end + end + +end + +class PatternFire + def initialize + @x, @y = 9, 4 + @mode = :horizontal + @pattern_shots = [] + @random_fire = RandomFire.new + end + + def next(shots) + if @mode == :horizontal + @pattern_shots << [@x, @y] + @x -= 1 + @y = @y == 4 ? 6 : 4 + end + if @mode == :vertical + @pattern_shots << [@x, @y] + @y += 1 + @x = @x == 4 ? 6 : 4 + end + if @mode == :horizontal && @x == -1 + @mode = :vertical + @x = 4 + @y = 0 + end + if @mode == :fill + @pattern_shots << [@x, @y] + @x += 2 + if @x >= 9 + @x = @y % 2 == 0 ? 1 : 0 + @y += 1 + end + end + if @mode == :vertical && @y == 9 + @mode = :fill + @x = 0 + @y = 1 + end + if shots.include? @pattern_shots.last + @random_fire.next(shots) + else + @pattern_shots.last + end + end + +end + +class FiringSquad + def initialize + @random_fire = RandomFire.new + @pattern_fire = PatternFire.new + @cluster_shots = [] + @shots = [] + end + + def shoot(board) + if should_pattern_fire?(board) + @shots << @pattern_fire.next(@shots) + elsif hit?(@shots.last, board) + @cluster_shots += ClusterFire.new(Cluster.new(@shots.last), @shots).all + @shots << @cluster_shots.pop + else + @shots << @cluster_shots.pop + end + if @shots.last.nil? + @shots << @random_fire.next(@shots) + @shots.last + else + @shots.last + end + end + + def should_pattern_fire?(board) + @shots.empty? || miss?(@shots.last, board) && @cluster_shots.empty? + end + + def miss?(shot, board) + board[shot[1]][shot[0]] != :hit + end + + def hit?(shot, board) + if shot + board[shot[1]][shot[0]] == :hit + end + end + +end + +class MrjabaPlayer + + def name + "Mrjaba Player" + end + + def initialize + @ships = [5,4,3,3,2] + @firing_squad = FiringSquad.new + end + + def new_game + position_ships + end + + def take_turn(board, remaining_ships) + @firing_squad.shoot(board) + end + + def position_ships + x = -1 + + @ships.collect do |ship| + x +=2 + top = rand(100) <= 50 + y = top ? 1 : 10 - ship + [x, y, ship, :down] + end + end + +end +