How to build a 2D board using Swift? - ios

I want to create a 2D game board (like a chess board) and each square has a value inside (Int = 1). This board has initially 9 squares (3x3).
Then I need a player that starts at the center of the bard and when I move the player to the edge of the board, it expands.
Example: The player reaches the [3,3] square and the board grows to a 4x4 board.
Also, when as the player moves it will change the value inside each square, from 0 to 1.
This is what I have so far
//Variables to get the player position and expand the board
let initialSize = 3
var newValueX = 0
var newValueY = 0
var newPlayerX = 0
var newPlayerY = 0
//Board
var board= [[Int]]()
struct Player {
var X = 0
var Y = 0
}
func expandBoard (){
for k in 0..<9{
for i in 0..<initialSize {
for j in 0..<initialSize {
array[k].append([i,j])
}
}
}
}
func movePlayer(){
var player = Player() //this goes to viewDidLoad
player.X = newPlayerX
player.Y = newPlayerY
}
An example of the pretended output:
Player moved to [0,3] and changed the square value from 1 to 0.
How can I do this correctly?
EDIT:
I have
class Array2D<T> {
var columns = 1//: Int
var rows = 1//: Int
var array: Array<T?>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array<T?>(repeating: nil, count:rows * columns)
}
subscript(column: Int, row: Int) -> T? {
get {
return array[(row * columns) + column]
}
set(newValue) {
array[(row * columns) + column] = newValue
}
}
}
func move(PX: Int, PY: Int){
if (board[PX, PY] == true){
moveCount += 1
board[PX, PY] = false
}
if (PX == board.rows.magnitude){
board.rows += 1
}
if (PY == board.columns.magnitude){
board.columns += 1
}
}
And when I run i get "Thread 1: Fatal error: Index out of range" on line (return array[(row * columns) + column]) from the subscript.
Any Idea how can I fix this?

UICollectionView would be another simple choice if you don't want use the SpriteKit.

I would recommend using SpriteKit, which have an element called 'Tile Map' which meets your requirements, here is a tutorial that can help.

Related

Merge overlapping CGRects

If I have a class Button:
class Button: Hashable {
private let id: String
var name: String
var rect: CGRect
}
I also have an array of Button: var buttons: [Button], how would I merge every overlapping button in the buttons array? CGRect has an intersects() -> Bool and union() -> CGRect functions.
I tried this and was getting index out of range errors:
for i in 0..<buttons.count {
for j in (i+1)..<buttons.count {
if buttons[i].rect.intersects(buttons[j].rect) {
let secondRect = buttons[j].rect
let union = buttons[i].rect.union(secondRect)
buttons[i].rect = union
buttons.remove(at: j)
}
}
}
Swift for loop is static, which means that range of the index determined at the start. While buttons.count keeps decreasing when you remove a next item, both i and j are counting til the start buttons.count, that's why you get a crash.
There's no dynamic for in swift (c-like), that's why you have to use while instead:
var i = 0
while i < buttons.count {
var j = i + 1
while j < buttons.count {
if buttons[i].rect.intersects(buttons[j].rect) {
let secondRect = buttons[j].rect
let union = buttons[i].rect.union(secondRect)
buttons[i].rect = union
buttons.remove(at: j)
} else {
j += 1
}
}
i += 1
}

Swift class containing another class as var

Consider the following code:
class A {
var x = 0;
var y = 0;
init(x vx: int, y vy: int){
x = vx
y = vy
}
}
class B {
var a_array: [A]
init(){
a_array = []
}
func append(_ a:A){
a_array.append(a)
}
func sum_all(){
var sum = 0
for a in a_array {
sum += (a.x + a.y)
}
print("sum all is",sum)
}
}
var a1 = A(1, 2)
var a2 = A(3, 4)
var b = B();
b.append(a1)
b.append(a2)
b.sum_all() //it prints out 10 correctly.
a1.x = 2
b.sum_all() //it still prints out 10
As I want it prints out 11, how can I modify these code?
In C, it can be done by using a pointer reference easily, how can it be done in Swift?
Thanks a lot in advance!
It is actually printing 11 in the line you said it still prints 10.
You can try it out by modifying a bit your code to look more like Swift syntax as this:
import Foundation
class A {
var x = 0
var y = 0
init(_ vx: Int, _ vy: Int){
x = vx
y = vy
}
}
class B {
var a_array: [A]
init(){
a_array = []
}
func append(_ a:A){
a_array.append(a)
}
func sum_all(){
var sum = 0
for a in a_array {
sum += (a.x + a.y)
}
print("sum all is",sum)
}
}
var a1 = A(1, 2)
var a2 = A(3, 4)
var b = B()
b.append(a1)
b.append(a2)
print("first")
b.sum_all() //it prints out 10 correctly.
a1.x = 2
print("last")
b.sum_all() //it actually prints 11.
You can try the snippet by copy pasting it in this playground online http://online.swiftplayground.run/ and run it.
This is the output:
first
sum all is 10
last
sum all is 11

Gradually and randomly visualize string

I am currently working on a simple program to gradually and randomly visualize a string in two iteration. Right now I have managed to get the first iteration but I'm not sure how to do the second one. If someone could give any example or advice I would be very grateful. My code looks like this:
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
var m = lrint(factor * Double(n)) // # of characters to display
let t = String(s.map { c -> Character in
if c == " " {
// Preserve space
return " "
} else if Int.random(in: 0..<n) < m {
// Replace
m -= 1
n -= 1
return c
} else {
// Keep
n -= 1
return "_"
}
})
print(t) // h_l__ _l_______d
To clarify, I want to use factor2 in the second iteration to print something that randomly add letters on top of t that looks something like this h_l_o pl_g_____d.
Replacing Characters
Starting from #MartinR's code, you should remember the indices that have been replaced. So, I am going to slightly change the code that replaces characters :
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
let nonSpaces = n
var m = lrint(factor * Double(n)) // # of characters to display
var indices = Array(s.indices)
var t = ""
for i in s.indices {
let c = s[i]
if c == " " {
// Preserve space
t.append(" ")
indices.removeAll(where: { $0 == i })
} else if Int.random(in: 0..<n) < m {
// Keep
m -= 1
n -= 1
t.append(c)
indices.removeAll(where: { $0 == i })
} else {
// Replace
n -= 1
t.append("_")
}
}
print(t) //For example: _e___ ______ou_d
Revealing Characters
In order to do that, we should calculate the number of characters that we want to reveal:
m = lrint((factor2 - factor) * Double(nonSpaces))
To pick three indices to reveal randomly, we shuffle indices and then replace the m first indices :
indices.shuffle()
var u = t
for i in 0..<m {
let index = indices[i]
u.replaceSubrange(index..<u.index(after: index), with: String(s[index]))
}
indices.removeSubrange(0..<m)
print(u) //For example: _e__o _l__g_ou_d
I wrote StringRevealer struct, that handle all revealing logic for you:
/// Hide all unicode letter characters as `_` symbol.
struct StringRevealer {
/// We need mapping between index of string character and his position in state array.
/// This struct represent one such record
private struct Symbol: Hashable {
let index: String.Index
let position: Int
}
private let originalString: String
private var currentState: [Character]
private let charactersCount: Int
private var revealed: Int
var revealedPercent: Double {
return Double(revealed) / Double(charactersCount)
}
private var unrevealedSymbols: Set<Symbol>
init(_ text: String) {
originalString = text
var state: [Character] = []
var symbols: [Symbol] = []
var count = 0
var index = originalString.startIndex
var i = 0
while index != originalString.endIndex {
let char = originalString[index]
if CharacterSet.letters.contains(char.unicodeScalars.first!) {
state.append("_")
symbols.append(Symbol(index: index, position: i))
count += 1
} else {
state.append(char)
}
index = originalString.index(after: index)
i += 1
}
currentState = state
charactersCount = count
revealed = 0
unrevealedSymbols = Set(symbols)
}
/// Current state of text. O(n) conplexity
func text() -> String {
return currentState.reduce(into: "") { $0.append($1) }
}
/// Reveal one random symbol in string
mutating func reveal() {
guard let symbol = unrevealedSymbols.randomElement() else { return }
unrevealedSymbols.remove(symbol)
currentState[symbol.position] = originalString[symbol.index]
revealed += 1
}
/// Reveal random symbols on string until `revealedPercent` > `percent`
mutating func reveal(until percent: Double) {
guard percent <= 1 else { return }
while revealedPercent < percent {
reveal()
}
}
}
var revealer = StringRevealer("Hello товарищ! 👋")
print(revealer.text())
print(revealer.revealedPercent)
for percent in [0.25, 0.45, 0.8] {
revealer.reveal(until: percent)
print(revealer.text())
print(revealer.revealedPercent)
}
It use CharacterSet.letters inside, so most of languages should be supported, emoji ignored and not-alphabetic characters as well.

Comparing two images and finding the percent difference

I've been trying to make an animal recognition app by image. My method is to compare the selected image by other images in an image array and list any comparisons that yield in a 90%+ similarity. Is there any other ways to compare two images that are similar, yet not alike? Any suggestions would be appreciated. These calculations must also run for many iterations, so a non-time consuming method would be much appreciated.
Please try to provide some code with the answer, as I am not very experienced in Swift.
you can do something like I did by analyzing one frame to the next and thresholding the difference (I didn't scale the image down yet, and probably should)
// called everytime a frame is captured
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let imageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer) else {
return
}
CVPixelBufferLockBaseAddress(imageBufferRef, []);
// set up for comparisons between prev and next images
if prevPB == nil {
prevPB = imageBufferRef
}
if (!isPlaying && motionIsDetected(prevPB, imageBufferRef) == 1) {
isPlaying = true
print("play video")
}
CVPixelBufferUnlockBaseAddress(imageBufferRef,[]);
// if true, play the video
prevPB = imageBufferRef
}
func pixelFrom(x: Int, y: Int, current: CVPixelBuffer) -> (UInt8, UInt8, UInt8) {
let baseAddress = CVPixelBufferGetBaseAddress(current)
let bytesPerRow = CVPixelBufferGetBytesPerRow(current)
let buffer = baseAddress!.assumingMemoryBound(to: UInt8.self)
let index = x*bytesPerRow+y
let b = buffer[index]
let g = buffer[index+1]
let r = buffer[index+2]
return (r, g, b)
}
func motionIsDetected(_ prev:CVPixelBuffer, _ current:CVPixelBuffer) -> Int {
var differences = 0
let baseAddress = CVPixelBufferGetBaseAddress(current)
let width = CVPixelBufferGetWidth(current)
let height = CVPixelBufferGetHeight(current)
// THRESHOLDING: clamp by abs(aa-bb) for tuple of r,b,g if 150 difference and at least 10 different pixels
var MAGIC_THRESHOLD = 120
var ENOUGH_DIFFERENCES = 10
if (current != nil && prev != nil) {
for x in 0..<height { //rows
for y in 0..<width { //cols
var setA = pixelFrom(x: x, y: y, current: prev)
var setB = pixelFrom(x: x, y: y, current: current)
if abs(Int(setA.0) - Int(setB.0)) > MAGIC_THRESHOLD && abs(Int(setA.1) - Int(setB.1)) > MAGIC_THRESHOLD && abs(Int(setA.2) - Int(setB.2)) > MAGIC_THRESHOLD {
differences = differences + 1
}
}
}
}
print(" difference" )
print(differences)
if differences > ENOUGH_DIFFERENCES {
return 1
}
return 0
}

I want multiple non-random numbers in swift

I am using swift and want to have a number of duplicatable patterns throughout my game.
Ideally I would have some sort of shared class that worked sort of like this (this is sort of pseudo-Swift code):
class RandomNumberUtility {
static var sharedInstance = RandomNumberUtility()
var random1 : Random()
var random2 : Random()
func seedRandom1(seed : Int){
random1 = Random(seed)
}
func seedRandom2(seed : Int){
random2 = Random(seed)
}
func getRandom1() -> Int {
return random1.next(1,10)
}
func getRandom2() -> Int {
return random2.next(1,100)
}
}
Then, to begin the series, anywhere in my program I could go like this:
RandomNumberUtility.sharedInstance.seedNumber1(7)
RandomNumberUtility.sharedInstance.seedNumber2(12)
And then I would know that (for example) the first 4 times I called
RandomNumberUtility.sharedInstance.getRandom1()
I would always get the same values (for example: 6, 1, 2, 6)
This would continue until at some point I seeded the number again, and then I would either get the exact same series back (if I used the same seed), or a different series (if I used a different seed).
And I want to have multiple series of numbers (random1 & random2) at the same time.
I am not sure how to begin to turn this into an actual Swift class.
Here is a possible implementation. It uses the jrand48 pseudo random number generator,
which produces 32-bit numbers.
This PRNG is not as good as arc4random(), but has the advantage
that all its state is stored in a user-supplied array, so that multiple
instances can run independently.
struct RandomNumberGenerator {
// 48 bit internal state for jrand48()
private var state : [UInt16] = [0, 0, 0]
// Return pseudo-random number in the range 0 ... upper_bound-1:
mutating func next(upper_bound: UInt32) -> UInt32 {
// Implementation avoiding the "module bias" problem,
// taken from: http://stackoverflow.com/a/10989061/1187415,
// Swift translation here: http://stackoverflow.com/a/26550169/1187415
let range = UInt32.max - UInt32.max % upper_bound
var rnd : UInt32
do {
rnd = UInt32(truncatingBitPattern: jrand48(&state))
} while rnd >= range
return rnd % upper_bound
}
mutating func seed(newSeed : Int) {
state[0] = UInt16(truncatingBitPattern: newSeed)
state[1] = UInt16(truncatingBitPattern: (newSeed >> 16))
state[2] = UInt16(truncatingBitPattern: (newSeed >> 32))
}
}
Example:
var rnd1 = RandomNumberGenerator()
rnd1.seed(7)
var rnd2 = RandomNumberGenerator()
rnd2.seed(12)
println(rnd1.next(10)) // 2
println(rnd1.next(10)) // 8
println(rnd1.next(10)) // 1
println(rnd2.next(10)) // 6
println(rnd2.next(10)) // 0
println(rnd2.next(10)) // 5
If rnd1 is seeded with the same value as above then it
produces the same numbers again:
rnd1.seed(7)
println(rnd1.next(10)) // 2
println(rnd1.next(10)) // 8
println(rnd1.next(10)) // 1
What you need is a singleton that generates pseudo-random numbers and make sure all your code that need a random number call via this class. The trick is to reset the seed for each run of your code. Here is a simple RandomGenerator class that will do the trick for you (it's optimized for speed which is a good thing when writing games):
import Foundation
// This random number generator comes from: Klimov, A. and Shamir, A.,
// "A New Class of Invertible Mappings", Cryptographic Hardware and Embedded
// Systems 2002, http://dl.acm.org/citation.cfm?id=752741
//
// Very fast, very simple, and passes Diehard and other good statistical
// tests as strongly as cryptographically-secure random number generators (but
// is not itself cryptographically-secure).
class RandomNumberGenerator {
static let sharedInstance = RandomNumberGenerator()
private init(seed: UInt64 = 12347) {
self.seed = seed
}
func nextInt() -> Int {
return next(32)
}
private func isPowerOfTwo(x: Int) -> Bool { return x != 0 && ((x & (x - 1)) == 0) }
func nextInt(max: Int) -> Int {
assert(!(max < 0))
// Fast path if max is a power of 2.
if isPowerOfTwo(max) {
return Int((Int64(max) * Int64(next(31))) >> 31)
}
while (true) {
var rnd = next(31)
var val = rnd % max
if rnd - val + (max - 1) >= 0 {
return val
}
}
}
func nextBool() -> Bool {
return next(1) != 0
}
func nextDouble() -> Double {
return Double((Int64(next(26)) << 27) + Int64(next(27))) /
Double(Int64(1) << 53)
}
func nextInt64() -> Int64 {
let lo = UInt(next(32))
let hi = UInt(next(32))
return Int64(UInt64(lo) | UInt64(hi << 32))
}
func nextBytes(inout buffer: [UInt8]) {
for n in 0..<buffer.count {
buffer[n] = UInt8(next(8))
}
}
var seed: UInt64 {
get {
return _seed
}
set(seed) {
_initialSeed = seed
_seed = seed
}
}
var initialSeed: UInt64 {
return _initialSeed!
}
private func randomNumber() -> UInt32 {
_seed = _seed &+ ((_seed &* _seed) | 5)
return UInt32(_seed >> 32)
}
private func next(bits: Int) -> Int {
assert(bits > 0)
assert(!(bits > 32))
return Int(randomNumber() >> UInt32(32 - bits))
}
private var _initialSeed: UInt64?
private var _seed: UInt64 = 0
}

Resources