Skip to content

Instantly share code, notes, and snippets.

@gravicle
Created August 8, 2014 07:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gravicle/5e5dd12da5ac7b425ab1 to your computer and use it in GitHub Desktop.
Save gravicle/5e5dd12da5ac7b425ab1 to your computer and use it in GitHub Desktop.
Implementation of /r/DailyProgrammer Challenge #168 in Swift
// [6/25/2014] Challenge #168 [Intermediate] Block Count, Length & Area : dailyprogrammer http://www.reddit.com/r/dailyprogrammer/comments/291x9h/6252014_challenge_168_intermediate_block_count/
// Author: Amit Jain
// Date: 08/08/2014
import Cocoa
struct Tile {
let char: Character // char represented
let x: Int // x position
let y: Int // y position
var cScore = 4 // number of sides to be counted in circumference calculation. Strats with 4, reduced by 2 on every successful match
var blockIndex: Int // index of representative block
}
struct Block {
var index: Int // index of the block
let char: Character // representating char
var rank: Int // number of elements
var count: Int // number of blocks of this type
var cScore = 0 // cScore of the whole block
var circumference: Int = 0
var area: Int = 0
}
class Surveyor {
var rowSize = 0
func earmarkMap(map: String) -> [Tile] {
var earmarkedMap: [Tile] = []
let rows = map.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet())
rowSize = rows[0].lengthOfBytesUsingEncoding(NSUTF8StringEncoding) // number of tiles in a row
for y in 0 ..< rows.count {
var row = rows[y]
var x = 0
for char in row {
let tile = Tile(char: char, x: x, y: y, cScore: 4, blockIndex: -1)
earmarkedMap += [tile]
++x
}
}
return earmarkedMap
}
func blocksFromMapTiles(tiles: [Tile]) -> [Block]{
var earmarkedTiles = tiles
var blocks = [Int: Block]()
for index in 0 ..< earmarkedTiles.count {
var tile = earmarkedTiles[index]
let x = tile.x
let y = tile.y
if x == 0 || y == 0 { // account for tiles on the top and left edges
if x == 0 && y == 0 { // first tile
// create a new block with tile
var block = Block(index: blocks.count + 1, char: tile.char, rank: 1, count: 1, cScore: tile.cScore, circumference: 0, area: 0)
blocks[blocks.count + 1] = block
// update the tile with its index
tile.blockIndex = block.index
// add the tile back to the earmarked map
earmarkedTiles[index] = tile
} else if x == 0 && y != 0 { // left edge
let topTile = earmarkedTiles[index - rowSize]
if tile.char == topTile.char {
// update the tile with its index and put it back into the map
tile.cScore -= 2
tile.blockIndex = topTile.blockIndex
earmarkedTiles[index] = tile
// add the tile to the top tile's block
blocks[topTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[topTile.blockIndex]?.cScore += tile.cScore
} else {
// create a new block with tile
var block = Block(index: blocks.count + 1, char: tile.char, rank: 1, count: 1, cScore: tile.cScore, circumference: 0, area: 0)
blocks[blocks.count + 1] = block
// update the tile with its index
tile.blockIndex = block.index
// add the tile back to the earmarked map
earmarkedTiles[index] = tile
}
} else if x != 0 && y == 0 { // top edge
let leftTile = earmarkedTiles[index - 1]
if tile.char == leftTile.char {
// update the tile with its index and put it back into the map
tile.cScore -= 2
tile.blockIndex = leftTile.blockIndex
earmarkedTiles[index] = tile
// add the tile to the left tile's block
blocks[leftTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[leftTile.blockIndex]?.cScore += tile.cScore
} else {
// create a new block with tile
var block = Block(index: blocks.count + 1, char: tile.char, rank: 1, count: 1, cScore: tile.cScore, circumference: 0, area: 0)
blocks[blocks.count + 1] = block
// update the tile with its index
tile.blockIndex = block.index
// add the tile back to the earmarked map
earmarkedTiles[index] = tile
}
}
} else {
// tile to the left will have the index 1 less than current tile
let leftTile = earmarkedTiles[index - 1]
// tile to the top will have index sum of x and y
let topTile = earmarkedTiles[index - rowSize]
if (tile.char != leftTile.char) && (tile.char != topTile.char) {
// create a new block with tile
var block = Block(index: blocks.count + 1, char: tile.char, rank: 1, count: 1, cScore: tile.cScore, circumference: 0, area: 0)
blocks[blocks.count + 1] = block
// update the tile with its index
tile.blockIndex = block.index
// add the tile back to the earmarked map
earmarkedTiles[index] = tile
} else if (tile.char == leftTile.char) && (tile.char != topTile.char) {
// update the tile with its index and put it back into the map
tile.cScore -= 2
tile.blockIndex = leftTile.blockIndex
earmarkedTiles[index] = tile
// add the tile to the left tile's block
blocks[leftTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[leftTile.blockIndex]?.cScore += tile.cScore
} else if (tile.char != leftTile.char) && (tile.char == topTile.char) {
// update the tile with its index and put it back into the map
tile.cScore -= 2
tile.blockIndex = topTile.blockIndex
earmarkedTiles[index] = tile
// add the tile to the top tile's block
blocks[topTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[topTile.blockIndex]?.cScore += tile.cScore
} else if (tile.char == leftTile.char) && (tile.char == topTile.char) {
let topTileBlockIndex = topTile.blockIndex
let leftTileBlockIndex = leftTile.blockIndex
let topBlockRank = blocks[topTileBlockIndex]!.rank
let leftBlockRank = blocks[leftTileBlockIndex]!.rank
if topBlockRank > leftBlockRank {
// merge left tile's parent block into top tile's block
blocks[topTileBlockIndex]?.rank += leftBlockRank
blocks[topTileBlockIndex]?.cScore += blocks[leftTileBlockIndex]!.cScore
// get rid of the extra block
blocks[leftTileBlockIndex] = nil
// update the tile with its index and put it back into the map
tile.cScore -= 4
tile.blockIndex = topTile.blockIndex
earmarkedTiles[index] = tile
// add the main tile to the top tile's block
blocks[topTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[topTile.blockIndex]?.cScore += tile.cScore
} else if topBlockRank > leftBlockRank {
// merge left tile's parent block into top tile's block
blocks[leftTileBlockIndex]?.rank += topBlockRank
blocks[leftTileBlockIndex]?.cScore += blocks[topTileBlockIndex]!.cScore
// get rid of the extra block
blocks[topTileBlockIndex] = nil
// update the tile with its index and put it back into the map
tile.cScore -= 4
tile.blockIndex = leftTile.blockIndex
earmarkedTiles[index] = tile
// add the main tile to the left tile's block
blocks[leftTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[leftTile.blockIndex]?.cScore += tile.cScore
} else { // when both, top and left, tiles belong to the same block
// update the tile with its index and put it back into the map
tile.cScore -= 4
tile.blockIndex = leftTile.blockIndex
earmarkedTiles[index] = tile
// add the main tile to the left tile's block
blocks[leftTile.blockIndex]?.rank += 1
// update the block's cScore
blocks[leftTile.blockIndex]?.cScore += tile.cScore
}
}
}
}
var allBlocks = [Block]()
for (index, block) in blocks {
allBlocks += [block]
}
for outerIndex in 0 ..< allBlocks.count {
var referenceBlock = allBlocks[outerIndex]
for innerIndex in outerIndex+1 ..< allBlocks.count {
var block = allBlocks[innerIndex]
if referenceBlock.char == block.char && block.count > 0{
++referenceBlock.count //increase the count on the reference block
referenceBlock.rank += block.rank
referenceBlock.cScore += block.cScore
block.count = 0 //discount the matched block
// put blocks back into the array
allBlocks[outerIndex] = referenceBlock
allBlocks[innerIndex] = block
}
}
}
let flattenedBlocks = allBlocks.filter{ $0.count > 0 }
return flattenedBlocks
}
func metricsForBlocks(b: [Block]) -> [Block] {
var blocks = b
var circumference = 0
var area = 0
for i in 0 ..< blocks.count {
var block = blocks[i]
block.circumference = block.cScore * 10
block.area = block.rank * 100
blocks[i] = block
}
return blocks
}
func surveyMap(map: String) {
let startTime = NSDate.date()
var blocks = metricsForBlocks(blocksFromMapTiles(earmarkMap(map)))
println("\n----Survey Data----\n")
for block in blocks {
println("\(block.char) | x\(block.count) | \(block.circumference) ft, \(block.area) sqft")
}
let endTime = NSDate.date()
let duration = endTime.timeIntervalSinceDate(startTime)
println("\nRuntime: \(duration)")
}
}
let map = "ooooooooooooooooooooooDDDDDooooooooooooooooooooooooooooo\nooooooooooooooooooooooDDDDDooooooooooooooooooooooooooooo\nooo##################o#####o#########################ooo\no@o##################o#####o#########################ooo\nooo##################o#####o#########################oTo\no@o##################################################ooo\nooo##################################################oTo\no@o############ccccccccccccccccccccccc###############ooo\npppppppppppppppcOOOOOOOOOOOOOOOOOOOOOc###############oTo\no@o############cOBBBBBBBBBBBBBBBBBBBOc###############ooo\nooo####V#######cOBBBBBBBBBBBBBBBBBBBOc###############oTo\no@o####V#######cOBBBBBBBBBBBBBBBBBBBOc###############ooo\nooo####V#######cOBBBBBBBBBBBBBBBBBBBOcpppppppppppppppppp\no@o####V#######cOBBBBBBBBBBBBBBBBBBBOc###############ooo\nooo####V#######cOBBBBBBBBBBBBBBBBBBBOc######v########oTo\no@o####V#######cOBBBBBBBBBBBBBBBBBBBOc######v########ooo\nooo####V#######cOOOOOOOOOOOOOOOOOOOOOc######v########oTo\no@o####V#######ccccccccccccccccccccccc######v########ooo\nooo####V#######ppppppppppppppppppppppp######v########oTo\no@o############ppppppppppppppppppppppp###############ooo\noooooooooooooooooooooooooooooooooooooooooooooooooooooooo\noooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
let surveyor = Surveyor()
surveyor.surveyMap(map)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment