Created
August 8, 2014 07:49
Implementation of /r/DailyProgrammer Challenge #168 in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// [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