diff --git a/.gitignore b/.gitignore index 51e6d0ca5..9961c1b05 100644 --- a/.gitignore +++ b/.gitignore @@ -421,6 +421,8 @@ git_pull.php airesources/C++/MyBot airesources/C++/BasicBot +airesources/Swift/MyBot +airesources/Swift/RandomBot airesources/*/halite leaderboard.png diff --git a/airesources/Swift/LANGUAGE b/airesources/Swift/LANGUAGE new file mode 100644 index 000000000..c1390abfe --- /dev/null +++ b/airesources/Swift/LANGUAGE @@ -0,0 +1 @@ +Swift diff --git a/airesources/Swift/Sources/Halite/Model.swift b/airesources/Swift/Sources/Halite/Model.swift new file mode 100644 index 000000000..afa68763d --- /dev/null +++ b/airesources/Swift/Sources/Halite/Model.swift @@ -0,0 +1,121 @@ +import Foundation + +public enum Direction: UInt8 { + case still = 0, north, east, south, west +} + +public struct Location { + let x: Int + let y: Int +} + +public struct Move { + public let location: Location + public let direction: Direction +} + +public struct Site { + public var owner: UInt8 + public var strength: UInt8 + public var production: UInt8 +} + +public class GameMap { + public let width: Int + public let height: Int + public var contents: [[Site]] + + public init(width: Int = 0, height: Int = 0) { + self.width = width + self.height = height + self.contents = [[Site]](repeating: [Site](repeating: Site(owner: 0, strength: 0, production: 0), count: width), count: height) + } + + public func isInBounds(location: Location) -> Bool { + return location.x < width && location.y < height + } + + public func getDistance(from location1: Location, to location2: Location) -> Int { + var dx = abs(location1.x - location2.x) + var dy = abs(location1.y - location2.y) + + if dx > width / 2 { + dx = width - dx + } + + if dy > height / 2 { + dy = height - dy + } + + return dx + dy; + } + + public func getAngle(from location1: Location, to location2: Location) -> Float { + var dx = location1.x - location2.x; + var dy = location2.y - location1.y; // reverse the y-axis. + + if dx > width - dx { + dx -= width + } + + if -dx > width + dx { + dx += width + } + + if dy > height - dy { + dy -= height + } + + if -dy > height + dy { + dy += height + } + + return atan2(Float(dy), Float(dx)) + } + + // TODO: implement with modulo + public func getLocation(location: Location, direction: Direction) -> Location { + var y = location.y + var x = location.x + + switch direction { + case .still: + break; + + case .north: + y = location.y == 0 ? height - 1 : location.y - 1 + + case .east: + x = location.x == width - 1 ? 0 : location.y + 1 + + case .south: + y = location.y == height - 1 ? 0 : location.y + 1 + + case .west: + x = location.x == 0 ? width - 1 : location.x - 1 + } + + return Location(x: x, y: y) + } + + public func getSite(location: Location, direction: Direction) -> Site { + let l = getLocation(location: location, direction: direction) + return contents[l.y][l.x] + } + + public func getSite(location: Location) -> Site { + return contents[location.y][location.x] + } + + public subscript(location: Location) -> Site { + get { + return contents[location.y][location.x] + } + } + + public subscript(y: Int, x: Int) -> Site { + get { + return contents[y][x] + } + } +} diff --git a/airesources/Swift/Sources/Halite/Networking.swift b/airesources/Swift/Sources/Halite/Networking.swift new file mode 100644 index 000000000..6431951d9 --- /dev/null +++ b/airesources/Swift/Sources/Halite/Networking.swift @@ -0,0 +1,87 @@ +import Foundation + +fileprivate var gameMap: GameMap! + +@discardableResult +func deserializeGameMap(input: String) -> GameMap { + let inputComponents = input.components(separatedBy: " ") + + var y = 0 + var x = 0 + + var index = 0 + + while y != gameMap.height { + let counter = UInt(inputComponents[index])! + let owner = UInt8(inputComponents[index + 1])! + + for _ in 1...counter { + gameMap.contents[y][x].owner = owner; + x += 1 + + if x == gameMap.width { + x = 0 + y += 1 + } + } + + index += 2 + } + + for y in 0.. String { + return readLine()! +} + +func sendString(_ string: String) { + FileHandle.standardOutput.write("\(string)\n".data(using: .utf8)!) +} + +public func getInit() -> UInt8 { + let tag = UInt8(getString())! + + var inputComponents = getString().components(separatedBy: " ") + let width = Int(inputComponents[0])! + let height = Int(inputComponents[1])! + + gameMap = GameMap(width: width, height: height) + + inputComponents = getString().components(separatedBy: " ") + var index = 0 + for y in 0.. GameMap { + deserializeGameMap(input: getString()) + return gameMap +} + +public func sendFrame(moves: [Move]) { + let serialized = moves.map({ "\($0.location.x) \($0.location.y) \($0.direction.rawValue) " }) + .joined() + + sendString(serialized) +} diff --git a/airesources/Swift/Sources/MyBot/main.swift b/airesources/Swift/Sources/MyBot/main.swift new file mode 100644 index 000000000..e4068b0e5 --- /dev/null +++ b/airesources/Swift/Sources/MyBot/main.swift @@ -0,0 +1,24 @@ +import Foundation + +let tag = getInit() + +sendInit(name: "MyBot-Swift") + +while true { + let gameMap = getFrame() + + var moves = [Move]() + + for y in 0.. 4 ? 0 : random)! + moves.append(Move(location: location, direction: direction)) + } + } + } + + sendFrame(moves: moves) +} diff --git a/airesources/Swift/Sources/RandomBot/main.swift b/airesources/Swift/Sources/RandomBot/main.swift new file mode 100644 index 000000000..bf97e6dd3 --- /dev/null +++ b/airesources/Swift/Sources/RandomBot/main.swift @@ -0,0 +1,23 @@ +import Foundation + +let tag = getInit() + +sendInit(name: "RandomBot-Swift") + +while true { + let gameMap = getFrame() + + var moves = [Move]() + + for y in 0..