Reputation: 25
For example on this app (I simply created for my character creation needs for D&D), when you press "Roll", the program rolls 3 times "d6 (6 sided dice)" and adds them up, and adds the sum to a the corresponding "Stat" Array, it does this 3 times, and then takes the highest value from the array as a result.
My noob function code here is here;
func rollStr() {
strArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
strArray.append(r1 + r2 + r3)
strArray.append(r4 + r5 + r6)
strArray.append(r7 + r8 + r9)
strStat = strArray.max()!
}
I didn't manage to declare only 3 values and roll it 3 times, so I decided to do it with 9 variables. Anyway as you see above there are "strArray" and "strStat" in this function. I had to write 6 copies of this function for each different stat. I tried to use an editable function like;
func rollStat(arrayNumber: Int, statNumber: Int) {
var allArrays = [strArray, dexArray, consArray, intArray, wisArray, chaArray]
var allStats = [strStat, dexStat, consStat, intStat, wisStat, chaStat]
allArrays[arrayNumber].removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
allArrays[arrayNumber].append(r1 + r2 + r3)
allArrays[arrayNumber].append(r4 + r5 + r6)
allArrays[arrayNumber].append(r7 + r8 + r9)
allStats[statNumber] = allArrays[arrayNumber].max()!
}
and wanted to call the function as "rollStat(arrayNumber: 1, statNumber: 1)" to use one base function to call what value I need instead of using multiple copies, but I couldn't manage to make it work. What am I doing wrong here?
As I said I achieved what I needed, the program works but if possible I want to know the tricks of doing it with only one function.
I will paste all the code below, if you wanted to know anything about the previous lines. Thanks in advance.
struct ContentView: View {
// MARK: PROPERTY
@State private var strArray:[Int] = [0,0,0]
@State private var dexArray:[Int] = [0,0,0]
@State private var consArray:[Int] = [0,0,0]
@State private var intArray:[Int] = [0,0,0]
@State private var wisArray:[Int] = [0,0,0]
@State private var chaArray:[Int] = [0,0,0]
@State private var strStat = 0
@State private var dexStat = 0
@State private var consStat = 0
@State private var intStat = 0
@State private var wisStat = 0
@State private var chaStat = 0
// MARK: METHOD
func rollStr() {
strArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
strArray.append(r1 + r2 + r3)
strArray.append(r4 + r5 + r6)
strArray.append(r7 + r8 + r9)
strStat = strArray.max()!
}
func rollDex() {
dexArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
dexArray.append(r1 + r2 + r3)
dexArray.append(r4 + r5 + r6)
dexArray.append(r7 + r8 + r9)
dexStat = dexArray.max()!
}
func rollCons() {
consArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
consArray.append(r1 + r2 + r3)
consArray.append(r4 + r5 + r6)
consArray.append(r7 + r8 + r9)
consStat = consArray.max()!
}
func rollInt() {
intArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
intArray.append(r1 + r2 + r3)
intArray.append(r4 + r5 + r6)
intArray.append(r7 + r8 + r9)
intStat = intArray.max()!
}
func rollWis() {
wisArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
wisArray.append(r1 + r2 + r3)
wisArray.append(r4 + r5 + r6)
wisArray.append(r7 + r8 + r9)
wisStat = wisArray.max()!
}
func rollCha() {
chaArray.removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
chaArray.append(r1 + r2 + r3)
chaArray.append(r4 + r5 + r6)
chaArray.append(r7 + r8 + r9)
chaStat = chaArray.max()!
}
func rollStat(arrayNumber: Int, statNumber: Int) {
var allArrays = [strArray, dexArray, consArray, intArray, wisArray, chaArray]
var allStats = [strStat, dexStat, consStat, intStat, wisStat, chaStat]
allArrays[arrayNumber].removeAll()
let r1 = Int.random(in: 1...6)
let r2 = Int.random(in: 1...6)
let r3 = Int.random(in: 1...6)
let r4 = Int.random(in: 1...6)
let r5 = Int.random(in: 1...6)
let r6 = Int.random(in: 1...6)
let r7 = Int.random(in: 1...6)
let r8 = Int.random(in: 1...6)
let r9 = Int.random(in: 1...6)
allArrays[arrayNumber].append(r1 + r2 + r3)
allArrays[arrayNumber].append(r4 + r5 + r6)
allArrays[arrayNumber].append(r7 + r8 + r9)
allStats[statNumber] = allArrays[arrayNumber].max()!
}
// MARK: BODY
var body: some View {
// MARK: STATS UI
VStack {
HStack(spacing: 10) {
VStack(spacing: 6) {
sixDiceView()
sixDiceView()
sixDiceView()
sixDiceView()
sixDiceView()
sixDiceView()
} //: Vstack
statNames()
ZStack {
VStack(spacing: 16) {
Text(String(strStat))
Text(String(dexStat))
Text(String(consStat))
Text(String(intStat))
Text(String(wisStat))
Text(String(chaStat))
}
VStack(spacing: 6) {
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 60, height: 30)
} //: VStack
} //: ZStack
ZStack {
rollsCapsule()
VStack(alignment: .leading, spacing: 16) {
Text("\(strArray[0]),\(strArray[1]),\(strArray[2])")
Text("\(dexArray[0]),\(dexArray[1]),\(dexArray[2])")
Text("\(consArray[0]),\(consArray[1]),\(consArray[2])")
Text("\(intArray[0]),\(intArray[1]),\(intArray[2])")
Text("\(wisArray[0]),\(wisArray[1]),\(wisArray[2])")
Text("\(chaArray[0]),\(chaArray[1]),\(chaArray[2])")
} //: VStack
} //: ZStack
} //: HStack
// MARK: BUTTON ROLL
Button(action: {
rollStr()
rollDex()
rollCons()
rollInt()
rollWis()
rollCha()
}) {
rollButton()
} //: BUTTON
} //: VStack
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
}
Upvotes: 2
Views: 66
Reputation: 154671
Swift functions can return multiple values using a tuple. If you create a general roll function to return the array and maximum value, you can just call it and assign the result to your variables:
func roll() -> (array: [Int], max: Int) {
var result = [Int]()
for _ in 1...3 {
var sum = 0
for _ in 1...3 {
sum += Int.random(in: 1...6)
}
result.append(sum)
}
return (result, result.max()!)
}
Then you'd call it like this:
(strArray, strStat) = roll()
(dexArray, dexStat) = roll()
RollData
structYour array and stat shouldn't be two different @State vars since they are related. You should combine them into a struct
.
struct RollData {
let array: [Int]
let stat: Int
}
func roll() -> RollData {
var result = [Int]()
for _ in 1...3 {
var sum = 0
for _ in 1...3 {
sum += Int.random(in: 1...6)
}
result.append(sum)
}
return RollData(array: result, stat: result.max()!)
}
Then you'd declare your @State vars like this:
@State private var strRoll = roll()
@State private var dexRoll = roll()
and roll like this:
strRoll = roll()
dexRoll = roll()
and access the data like this:
Text(String(strRoll.stat))
Text("\(strRoll.array[0]),\(strRoll.array[1]),\(strRoll.array[2])")
This is a fun project to play with. I made some additional changes that I thought you might like to see.
Notes:
DieType
enum
which has a value for each die type. I made it of type Int
so that we could use it as in index into an array of all of the dies. I made it CaseIterable
so that we can get an array of all types with DieType.allCases
. I made it CustomStringConvertible
so the type would nicely print its name as returned by the computed property description
. I made it Identifiable
so that we can use it SwiftUI like this: ForEach(DieType.allCases) { die in
.AllDice
struct
which holds all of the dice. Now we only need one @State dice = AllDice()
for the app. It has properties to roll all of the dice, roll a single die by type, get the stat
and array
for a die.VStack
with a row for each die type. There are no hardcoded 6's for number of die types. By defining a new die type, or removing one, the code adapts automatically.import SwiftUI
struct RollData {
let array: [Int]
let stat: Int
}
func roll() -> RollData {
var result = [Int]()
for _ in 1...3 {
var sum = 0
for _ in 1...3 {
sum += Int.random(in: 1...6)
}
result.append(sum)
}
return RollData(array: result, stat: result.max()!)
}
enum DieType: Int, CaseIterable, CustomStringConvertible, Identifiable {
case strength = 0, dexterity, constitution, intelligence, wisdom, charisma
var id: Int { self.rawValue }
var description: String {
switch self {
case .strength: return "Strength"
case .dexterity: return "Dexterity"
case .constitution: return "Constitution"
case .intelligence: return "Intelligence"
case .wisdom: return "Wisdom"
case .charisma: return "Charisma"
}
}
}
struct AllDice {
private var dice: [RollData] = (0..<DieType.allCases.count).map { _ in roll() }
func array(die: DieType) -> [Int] {
dice[die.rawValue].array
}
func stat(die: DieType) -> Int {
dice[die.rawValue].stat
}
mutating func rollDie(die: DieType) {
dice[die.rawValue] = roll()
}
mutating func rollAll() {
for die in DieType.allCases {
rollDie(die: die)
}
}
}
struct ContentView: View {
@State private var dice = AllDice()
var body: some View {
// MARK: STATS UI
VStack {
ForEach(DieType.allCases) { die in
let array = dice.array(die: die)
HStack(spacing: 10) {
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 80, height: 30)
.overlay (
HStack {
Text("3 x")
Image(systemName: "dice")
.foregroundColor(.red)
}
)
Text(String(describing: die))
.frame(width: 100)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 50, height: 30)
.overlay (
Text(String(describing: dice.stat(die: die)))
)
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 100, height: 30)
.overlay (
Text("\(array[0]), \(array[1]), \(array[2])")
)
} //: HStack
} //: ForEach
// MARK: BUTTON ROLL
Button(action: {
dice.rollAll()
}) {
Capsule()
.fill(Color.blue.opacity(0.2))
.frame(width: 130, height: 30)
.overlay (
HStack {
Image(systemName: "dice")
Text("Roll Stats")
}
.foregroundColor(.red)
)
} //: BUTTON
} //: VStack
}
}
Upvotes: 3