How to change property value with static method? - ios

In this simple game there is a class Fighter whose purpose is to make two fighters fight. The one who looses health below 0, it looses the game.
In order to fight there is a static method fight (..) which iterates till one fighter wins the game, supported by another non static method attack (..)
object Fighter health should change as two objects fight during the game using the methods fight(...) and attack (...). The problem is it always prints the same Fighter health, and the game never ends. I don´t see where the issue is
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let david = Fighter(name: "David", health: 100, damage: 30, defense: 10, initiative: 80)
let goliath = Fighter(name: "Goliath", health: 300, damage: 60, defense: 14, initiative: 90)
let myFight1 = Fighter.fight(fighter1: david, fighter2: goliath) // always executing same Fighters
print(myFight1)
}
}
import Foundation
struct Fighter {
var name: String
var health: Double
var damage: Int
var defense: Int
var initiative: Int
init (name: String, health: Double, damage: Int, defense: Int, initiative: Int) {
self.name = name
self.health = health
self.damage = damage
self.defense = defense
self.initiative = initiative
}
init (name: String, health: Double, damage: Int, defense: Int) {
self.name = name
self.health = health
self.damage = damage
self.defense = defense
self.initiative = 0
}
static func fight(fighter1: Fighter, fighter2: Fighter) -> Fighter {
let f1 = fighter1
let f2 = fighter2
if f1.health == f2.health {
return f1
}
if f2.initiative > f1.initiative {
f2.attack(f: f1)
}
var i = 0
while f1.health > 0 {
i += 1
print("--> i: \(i)")
f1.attack(f: f2 )
if f2.health <= 0 {
return f1
}
f2.attack(f: f1)
}
return f2
}
func attack(f: Fighter) -> Void {
var g = f
g.health = g.health - Double(g.damage * (1 - g.defense / 100))
print(g)
}
}

You are using a struct for Fighter which is a value type in Swift.
The most basic distinguishing feature of a value type is that copying — the effect of assignment, initialization, and argument passing —
creates an independent instance with its own unique copy of its data
Solution: Change Fighter to a class and you are good to go.
Output of the print statements: (Second print statement changed to print(g.name, g.health))
David 70.0
--> i: 1
Goliath 240.0
David 40.0
--> i: 2
Goliath 180.0
David 10.0
--> i: 3
Goliath 120.0
David -20.0
For more reading: Value and Reference Types

After calling the method func attack(f: Fighter) -> Void every time, the properties of the Fighter who is being attacked are not getting updated. So while loop is not going to break at any point.
Please replace the code below.
static func fight(fighter1: Fighter, fighter2: Fighter) -> Fighter {
var f1 = fighter1
var f2 = fighter2
if f1.health == f2.health {
return f1
}
if f2.initiative > f1.initiative {
f1 = f2.attack(f: f1)
}
var i = 0
while f1.health > 0 {
i += 1
print("--> i: \(i)")
f2 = f1.attack(f: f2 )
if f2.health <= 0 {
return f1
}
f1 = f2.attack(f: f1)
}
return f2
}
func attack( f: Fighter) -> Fighter {
var g = f
g.health = g.health - Double(g.damage * (1 - g.defense / 100))
print(g)
return g
}

When you're saying...
var g = f
...you're actually creating a copy of that object, not a reference. So, when you're changing 'health' property, you changing it in the copy.
There are 2 simple solutions:
1) Change struct to class, 'cause classes are being referenced, unlike structs, which is just copying.
2) Replace original object with its modified copy (g)

As Rakesha notes, structs are value types, so your attack code doesn't actually modify anything:
func attack(f: Fighter) -> Void {
var g = f // Make a mutable copy of `f` called `g`
g.health = g.health - Double(g.damage * (1 - g.defense / 100)) // Modify g
print(g) // Print g
// Throw g away
}
(Side note: I think g.damage is incorrect here; I think you probably meant self.damage.)
Nothing there actually modifies f. There are several ways to address this. One is to use classes, which introduces subtle mutable state. I don't think I'd do that here. By "subtle mutable state" I mean that you expect attack to modify f, but nothing in the signature says that it does that, so the caller may be surprised.
Instead, you have several ways to implement this that make your mutations explicit on structs. You can make attack explicitly modify f:
func attack(f: inout Fighter) {
f.health = f.health - Double(damage * (1 - f.defense / 100))
}
Or you could turn it around and modify yourself when attacked by someone else:
mutating func attackedBy(f: Fighter) {
health = health - Double(f.damage * (1 - defense / 100)
}

Related

Generate number in certain range from current date of device in Swift 3 [duplicate]

I need to start the same random number list over every execution of my app.
srand/rand do not exist anymore. What should I do then?
private extension Array {
private func randomValues(_ seed: UInt32, num: Int) -> [Element] {
srand (seed)
var indices = [Int]()
indices.reserveCapacity(num)
let range = 0..<self.count
for _ in 0..<num {
var random = 0
repeat {
random = randomNumberInRange(range)
} while indices.contains(random)
indices.append(random)
}
return indices.map { self[$0] }
}
You can use
srand48(seed) and drand48() in Swift3.
Unless you're developing with Swift for non-Apple platforms, you can get a much better randomization API in GameplayKit: several algorithms (trade randomness vs speed), seedable, distribution control, etc.
I can't find a way to use seeded random in Swift 3 Beta 1. Had to write a silly wrapper function in C:
// ----------------------------------------------
// my_random.h
// ----------------------------------------------
#ifndef my_random_h
#define my_random_h
#include <stdio.h>
#endif /* my_random_h */
long next_random();
// ----------------------------------------------
// my_random.c
// ----------------------------------------------
#include <stdlib.h>
#include "my_random.h"
long next_random() {
return random();
}
You can use the bridging header to import it into Swift. Then you can call it in Swift like this:
srandom(42)
for _ in 0..<10 {
let x = next_random()
print(x)
}
random is better than rand. Read the man pages for discussion on these 2 functions.
Edit:
A workaround, as #riskter suggested, is to use GameKit:
import GameKit
let seed = Data(bytes: [42]) // Use any array of [UInt8]
let source = GKARC4RandomSource(seed: seed)
for _ in 0..<10 {
let x = source.nextInt()
print(x)
}
For a simple repeatable random list try using a Linear Congruential Generator:
import Foundation
class LinearCongruntialGenerator
{
var state = 0 //seed of 0 by default
let a, c, m, shift: Int
//we will use microsoft random by default
init() {
self.a = 214013
self.c = 2531011
self.m = Int(pow(2.0, 31.0)) //2^31 or 2147483648
self.shift = 16
}
init(a: Int, c: Int, m: Int, shift: Int) {
self.a = a
self.c = c
self.m = m //2^31 or 2147483648
self.shift = shift
}
func seed(seed: Int) -> Void {
state = seed;
}
func random() -> Int {
state = (a * state + c) % m
return state >> shift
}
}
let microsoftLinearCongruntialGenerator = LinearCongruntialGenerator()
print("Microsft Rand:")
for i in 0...10
{
print(microsoftLinearCongruntialGenerator.random())
}
More info here:
https://rosettacode.org/wiki/Linear_congruential_generator
I just happened to put this together for Swift 4. I am aware Swift 4.2 has new random extensions that are different from this, but like the OP, I needed them to be seedable during testing. Maybe someone will find it helpful. If you don't seed it, it will use arc4random, otherwise it will use drand48. It avoids mod bias both ways.
import Foundation
class Random {
static var number = unseededGenerator // the current generator
/**
* returns a random Int 0..<n
**/
func get(anIntLessThan n: Int) -> Int {
return generatingFunction(n)
}
class func set(seed: Int) {
number = seedableGenerator
srand48(seed)
}
// Don't normally need to call the rest
typealias GeneratingFunction = (Int) -> Int
static let unseededGenerator = Random(){
Int(arc4random_uniform(UInt32($0)))
}
static let seedableGenerator = Random(){
Int(drand48() * Double($0))
}
init(_ gf: #escaping GeneratingFunction) {
self.generatingFunction = gf
}
private let generatingFunction: GeneratingFunction
}
func randomTest() {
Random.set(seed: 65) // comment this line out for unseeded
for _ in 0..<10 {
print(
Random.number.get(anIntLessThan: 2),
terminator: " "
)
}
}
// Run
randomTest()

Getting "Argument passed to call that takes no arguments" when trying to use arc4random [duplicate]

I need to generate a random number.
It appears the arc4random function no longer exists as well as the arc4random_uniform function.
The options I have are arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int), and arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).
I can't find any docs on the functions and no comments in the header files give hints.
let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)
// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()
You could try as well:
let diceRoll = Int(arc4random_uniform(UInt32(6)))
I had to add "UInt32" to make it work.
Just call this function and provide minimum and maximum range of number and you will get a random number.
eg.like randomNumber(MIN: 0, MAX: 10) and You will get number between 0 to 9.
func randomNumber(MIN: Int, MAX: Int)-> Int{
return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}
Note:- You will always get output an Integer number.
After some investigation I wrote this:
import Foundation
struct Math {
private static var seeded = false
static func randomFractional() -> CGFloat {
if !Math.seeded {
let time = Int(NSDate().timeIntervalSinceReferenceDate)
srand48(time)
Math.seeded = true
}
return CGFloat(drand48())
}
}
Now you can just do Math.randomFraction() to get random numbers [0..1[ without having to remember seeding first. Hope this helps someone :o)
Update with swift 4.2 :
let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
Another option is to use the xorshift128plus algorithm:
func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
var state0 : UInt64 = seed0
var state1 : UInt64 = seed1
if state0 == 0 && state1 == 0 {
state0 = 1 // both state variables cannot be 0
}
func rand() -> UInt64 {
var s1 : UInt64 = state0
let s0 : UInt64 = state1
state0 = s0
s1 ^= s1 << 23
s1 ^= s1 >> 17
s1 ^= s0
s1 ^= s0 >> 26
state1 = s1
return UInt64.addWithOverflow(state0, state1).0
}
return rand
}
This algorithm has a period of 2^128 - 1 and passes all the tests of the BigCrush test suite. Note that while this is a high-quality pseudo-random number generator with a long period, it is not a cryptographically secure random number generator.
You could seed it from the current time or any other random source of entropy. For example, if you had a function called urand64() that read a UInt64 from /dev/urandom, you could use it like this:
let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
print(rand())
}
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
In Swift 3 :
It will generate random number between 0 to limit
let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")
My implementation as an Int extension. Will generate random numbers in range from..<to
public extension Int {
static func random(from: Int, to: Int) -> Int {
guard to > from else {
assertionFailure("Can not generate negative random numbers")
return 0
}
return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
}
}
This is how I get a random number between 2 int's!
func randomNumber(MIN: Int, MAX: Int)-> Int{
var list : [Int] = []
for i in MIN...MAX {
list.append(i)
}
return list[Int(arc4random_uniform(UInt32(list.count)))]
}
usage:
print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")
Another option is to use GKMersenneTwisterRandomSource from GameKit. The docs say:
A deterministic pseudo-random source that generates random numbers
based on a mersenne twister algorithm. This is a deterministic random
source suitable for creating reliable gameplay mechanics. It is
slightly slower than an Arc4 source, but more random, in that it has a
longer period until repeating sequences. While deterministic, this is
not a cryptographic random source. It is however suitable for
obfuscation of gameplay data.
import GameKit
let minValue = 0
let maxValue = 100
var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)
Example taken from Apple's sample code: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift
I'm late to the party 🤩🎉
Using a function that allows you to change the size of the array and the range selection on the fly is the most versatile method. You can also use map so it's very concise. I use it in all of my performance testing/bench marking.
elements is the number of items in the array
only including numbers from 0...max
func randArr(_ elements: Int, _ max: Int) -> [Int] {
return (0..<elements).map{ _ in Int.random(in: 0...max) }
}
Code Sense / Placeholders look like this.
randArr(elements: Int, max: Int)
10 elements in my array ranging from 0 to 1000.
randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]
you can use this in specific rate:
let die = [1, 2, 3, 4, 5, 6]
let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
Lets Code with Swift for the random number or random string :)
let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]
let randomNumber = arc4random_uniform(UInt32(quotes.count))
let quoteString = quotes[Int(randomNumber)]
print(quoteString)
it will give you output randomly.
Don't forget that some numbers will repeat! so you need to do something like....
my totalQuestions was 47.
func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{
var arrayOfRandomQuestions: [Int] = []
print("arraySizeRequired = 40")
print("totalQuestions = \(totalQuestions)")
//This will output a 40 random numbers between 0 and totalQuestions (47)
while arrayOfRandomQuestions.count < 40
{
let limit: UInt32 = UInt32(totalQuestions)
let theRandomNumber = (Int(arc4random_uniform(limit)))
if arrayOfRandomQuestions.contains(theRandomNumber)
{
print("ping")
}
else
{
//item not found
arrayOfRandomQuestions.append(theRandomNumber)
}
}
print("Random Number set = \(arrayOfRandomQuestions)")
print("arrayOutputCount = \(arrayOfRandomQuestions.count)")
return arrayOfRandomQuestions as! NSMutableArray
}
look, i had the same problem but i insert
the function as a global variable
as
var RNumber = Int(arc4random_uniform(9)+1)
func GetCase(){
your code
}
obviously this is not efficent, so then i just copy and paste the code into the function so it could be reusable, then xcode suggest me to set the var as constant so my code were
func GetCase() {
let RNumber = Int(arc4random_uniform(9)+1)
if categoria == 1 {
}
}
well thats a part of my code so xcode tell me something of inmutable and initialization but, it build the app anyway and that advice simply dissapear
hope it helps

Error Handling in a Recursive Swift Function [duplicate]

I am making fuction that calculate factorial in swift. like this
func factorial(factorialNumber: UInt64) -> UInt64 {
if factorialNumber == 0 {
return 1
} else {
return factorialNumber * factorial(factorialNumber - 1)
}
}
let x = factorial(20)
this fuction can calculate untill 20.
I think factorial(21) value bigger than UINT64_MAX.
then How to calculate the 21! (21 factorial) in swift?
func factorial(_ n: Int) -> Double {
return (1...n).map(Double.init).reduce(1.0, *)
}
(1...n): We create an array of all the numbers that are involved in the operation (i.e: [1, 2, 3, ...]).
map(Double.init): We change from Int to Double because we can represent bigger numbers with Doubles than with Ints (https://en.wikipedia.org/wiki/Double-precision_floating-point_format). So, we now have the array of all the numbers that are involved in the operation as Doubles (i.e: [1.0, 2.0, 3.0, ...]).
reduce(1.0, *): We start multiplying 1.0 with the first element in the array (1.0*1.0 = 1.0), then the result of that with the next one (1.0*2.0 = 2.0), then the result of that with the next one (2.0*3.0 = 6.0), and so on.
Step 2 is to avoid the overflow issue.
Step 3 is to save us from explicitly defining a variable for keeping track of the partial results.
Unsigned 64 bit integer has a maximum value of 18,446,744,073,709,551,615. While 21! = 51,090,942,171,709,440,000. For this kind of case, you need a Big Integer type. I found a question about Big Integer in Swift. There's a library for Big Integer in that link.
BigInteger equivalent in Swift?
Did you think about using a double perhaps? Or NSDecimalNumber?
Also calling the same function recursively is really bad performance wise.
How about using a loop:
let value = number.intValue - 1
var product = NSDecimalNumber(value: number.intValue)
for i in (1...value).reversed() {
product = product.multiplying(by: NSDecimalNumber(value: i))
}
Here's a function that accepts any type that conforms to the Numeric protocol, which are all builtin number types.
func factorial<N: Numeric>(_ x: N) -> N {
x == 0 ? 1 : x * factorial(x - 1)
}
First we need to declare temp variable of type double so it can hold size of number.
Then we create a function that takes a parameter of type double.
Then we check, if the number equal 0 we can return or do nothing. We have an if condition so we can break the recursion of the function. Finally we return temp, which holds the factorial of given number.
var temp:Double = 1.0
func factorial(x:Double) -> Double{
if(x==0){
//do nothing
}else{
factorial(x: x-1)
temp *= x
}
return temp
}
factorial(x: 21.0)
I make function calculate factorial like this:
func factorialNumber( namber : Int ) -> Int {
var x = 1
for i in 1...namber {
x *= i
}
return x
}
print ( factorialNumber (namber : 5 ))
If you are willing to give up precision you can use a Double to roughly calculate factorials up to 170:
func factorial(_ n: Int) -> Double {
if n == 0 {
return 1
}
var a: Double = 1
for i in 1...n {
a *= Double(i)
}
return a
}
If not, use a big integer library.
func factoruial(_ num:Int) -> Int{
if num == 0 || num == 1{
return 1
}else{
return(num*factoruial(num - 1))
}
}
Using recursion to solve this problem:
func factorial(_ n: UInt) -> UInt {
return n < 2 ? 1 : n*factorial(n - 1)
}
func factorial(a: Int) -> Int {
return a == 1 ? a : a * factorial(a: a - 1)
}
print(factorial(a : 5))
print(factorial(a: 9))

How do I return functions with inout parameters and a return type of Void in Swift?

I have attempted to run this code in an Xcode 6.0 playground and in an iOS project through the viewController viewDidLoad function, and in both settings the program crashes the compiler. I have read about people having similar issues when returning inout functions when the program is run through a playground, however the issue was resolved when they ran their program through a project. Is something incorrect with my code, and if so what is wrong, or am I running the code incorrectly in the playground or project?
// testingPlayground
// July 18, 2015
func chooseFunction(isYNegative lessThanZero: Bool) -> (inout Int) -> Void {
func increaseY(inout #yValue: Int){ // Increases yValue
yValue += 1
}
func decreaseY(inout #yValue: Int){ // Decreases yValue
yValue -= 1
}
return lessThanZero ? increaseY : decreaseY // Returns either the increase or decrease yValue function
}
var yValue = -1
var changeYFunction = chooseFunction(isYNegative: yValue < 0)
while yValue != 0 {
changeYFunction(&yValue) // Increments/Decrements yValue
}
The code works fine for me after removing the # from both of the #yValue: Int parameters inside chooseFunction (having the # would imply that an argument name must be given, which you don't do).
Alternatively, you need to specify the parameter name in the return type of chooseFunction and use it when you call the returned function, i.e.:
func chooseFunction(isYNegative lessThanZero: Bool) -> ((inout yValue: Int) -> Void) {
And:
changeYFunction(yValue: &yValue)
In other words, the problem is that you are not consistent with whether or not the returned functions require a name for the argument or not.
edit: As yet another alternative, you could consider refactoring the whole thing, e.g., use the shorthand for curried functions:
func stepper(increase increase: Bool)(inout _ y: Int) {
increase ? ++y : --y
}
var y = -5
let step = stepper(increase: y < 0)
while y != 0 {
step(&y)
}
In fact, even the following works, although the hairy syntax required makes me wary:
func stepper(increase increase: Bool)(inout _ y: Int)() {
increase ? ++y : --y
}
var y = -5
let stepY = stepper(increase: y < 0)(&y)
while y != 0 {
stepY()
}

No output in Swift Playground

I am trying to put fibonacci number in an array and wanted to see the array output in playground console but for some reason I do not see any ouput. Can someone plz help in making me understand the mistake that I am cdoing in my program ?
import UIKit
class FibonacciSequence {
let includesZero: Bool
let values: [Int]
init(maxNumber: Int, includesZero: Bool) {
self.includesZero = includesZero
values = [0]
var counter: Int
if (includesZero == true) { counter = 0 }
else { counter = 1 }
for counter <= maxNumber; {
if ( counter == 0 ) {
values.append(0)
counter = 1
}
else {
counter = counter + counter
values.append(counter)
}
}
println(values)
}
println(values)
return values
}
let fibanocciSequence = FibonacciSequence(maxNumber:123, includesZero: true)
#ABakerSmith has given you a good rundown of the problems in the code as-is, but you also might want to consider, instead of a class that initializes an array member variable, writing a SequenceType that returns fibonacci numbers:
struct FibonacciSequence: SequenceType {
let maxNumber: Int
let includesZero: Bool
func generate() -> GeneratorOf<Int> {
var (i, j) = includesZero ? (0,1) : (1,1)
return GeneratorOf {
(i, j) = (j, i+j)
return (i < self.maxNumber) ? i : nil
}
}
}
let seq = FibonacciSequence(maxNumber: 20, includesZero: false)
// no arrays were harmed in the generation of this for loop
for num in seq {
println(num)
}
// if you want it in array form:
let array = Array(seq)
You could of course memoize the sequence if you want to improve performance on multiple generations.
Your problem is your code has errors in it; if there are errors in your code Playgrounds won't run it and you won't get any output.
On the line for counter <= maxNumber; you've got a semi-colon, but also, I'm pretty sure you can't declare a for loop like that, unless I'm missing something? You could use a while loop though.
Why are you trying to return values from your init method?
You've declared values as a constant but are then trying to change it using append.
Using this code and fixing the errors stated does not produce the Fibonacci sequence, instead it produces: [0, 0, 2, 4, 8, 16, 32, 64, 128]
Try this code:
class FibonacciSequence {
let values: [Int]
init(maxNumber: Int, includesZero: Bool) {
var tempValues = includesZero ? [0] : [1]
var current = 1
do {
tempValues.append(current)
let nMinus2 = tempValues[tempValues.count - 2]
let nMinus1 = tempValues[tempValues.count - 1]
current = nMinus2 + nMinus1
} while current <= maxNumber
self.values = tempValues
}
}
Then create an instance:
let fibanocciSequence = FibonacciSequence(maxNumber:123, includesZero: true)
println(fibanocciSequence.values) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Hope that helps!

Resources