diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0fbe67 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# RNG_Swift + +A fully featured Randomizer written in Swift with UI in SwiftUI! + +## Features +- Number generator +- Password generator +- Die Generator \ No newline at end of file diff --git a/RNG.xcodeproj/xcshareddata/xcschemes/RNG-noDebug.xcscheme b/RNG.xcodeproj/xcshareddata/xcschemes/RNG-noDebug.xcscheme new file mode 100644 index 0000000..7361d06 --- /dev/null +++ b/RNG.xcodeproj/xcshareddata/xcschemes/RNG-noDebug.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RNG/ContentView.swift b/RNG/ContentView.swift index 6d2721d..d9aee3e 100644 --- a/RNG/ContentView.swift +++ b/RNG/ContentView.swift @@ -12,44 +12,46 @@ struct ContentView: View { VStack { NavigationSplitView { List { - NavigationLink { - NumberView() - .navigationTitle("Random Number Generator") - } label: { - HStack { - Text("Random Number Generator") - Spacer() - Image(systemName: "textformat.123") - } - } - NavigationLink { - DiceView() - .navigationTitle("Dice") - } label: { - HStack { - Text("Dice") - Spacer() - Image(systemName: "die.face.1") - Image(systemName: "die.face.2.fill") - Image(systemName: "die.face.3") - Image(systemName: "die.face.4.fill") - Image(systemName: "die.face.5") - Image(systemName: "die.face.6.fill") - } - } - NavigationLink { - PasswordView() - .navigationTitle("Password") - } label: { - HStack { - Text("Password") - Spacer() - Image(systemName: "rectangle.and.pencil.and.ellipsis") + Section("Generate...") { + NavigationLink { + NumberView() + .navigationTitle("Numbers") + } label: { + HStack { + Text("Numbers") + Spacer() + Image(systemName: "textformat.123") + } + } + NavigationLink { + DiceView() + .navigationTitle("Die") + } label: { + HStack { + Text("Die") + Spacer() + Image(systemName: "die.face.1") + Image(systemName: "die.face.2.fill") + Image(systemName: "die.face.3") + Image(systemName: "die.face.4.fill") + Image(systemName: "die.face.5") + Image(systemName: "die.face.6.fill") + } + } + NavigationLink { + PasswordView() + .navigationTitle("Passwords") + } label: { + HStack { + Text("Passwords") + Spacer() + Image(systemName: "rectangle.and.pencil.and.ellipsis") + } } } + .navigationTitle("RNG") + .navigationBarTitleDisplayMode(.inline) } - .navigationTitle("RNG") - .navigationBarTitleDisplayMode(.inline) } detail: { Image(systemName: "dice.fill") } @@ -57,3 +59,6 @@ struct ContentView: View { } } +#Preview { + ContentView() +} diff --git a/RNG/DiceView.swift b/RNG/DiceView.swift index 5b955a3..598a391 100644 --- a/RNG/DiceView.swift +++ b/RNG/DiceView.swift @@ -8,26 +8,36 @@ import SwiftUI struct DiceView: View { - @State var generated: [Int] = [0] + @State var advanced: Bool = false + @State var generated: [Int] = [] @State var displayDies: [Int] = [] @State var displayMultiDieMode = "" @State var multiDieMode = "plus" - @State var result = 0 + @State var result: UInt = 0 @State var resultDescription = "" - @State var history: [Int] = [] let columns = [GridItem(.adaptive(minimum: 25, maximum: 75))] @State var dies: Double = 2 + var body: some View { VStack { List { Section("Number of die") { + Toggle(isOn: $advanced) { + Text("Advanced Mode") + } HStack { - Text( String( Int(dies) ) ) - .font(.system(size: 25, weight: .bold)) + Text(String(Int(dies))) + .font(.system(size: 20, weight: .heavy)) + .frame(width: ((dies > 99) ? 40 : (dies > 9) ? 30 : 20)) Divider() Text("1") - Slider(value: $dies, in: 1...20, step: 1) - Text("20") + if advanced { + Slider(value: $dies, in: 1...100, step: 1) + Text("100") + } else { + Slider(value: $dies, in: 1...20, step: 1) + Text("20") + } } } Section("Multi die mode") { @@ -37,36 +47,36 @@ struct DiceView: View { }.pickerStyle(SegmentedPickerStyle()) } Section("Visual") { - HStack { - Spacer() - if displayDies.isEmpty { - Text("Results are visualised here when you press the generate button") - .font(.subheadline) - } else { - LazyVGrid(columns: columns, spacing: 10) { - ForEach(0.. String { var result = "" var symbol = "" if inp.isEmpty { - return "0" + return "" } else { if combineMode == "plus" { - symbol = " + " + symbol = "+" } else if combineMode == "multiply" { - symbol = " x " + symbol = "x" } for i in 0...len { if i == len { @@ -104,7 +114,6 @@ func describeResult(inp: [Int], combineMode: String) -> String { result += String(inp[i]) + symbol } } - result += " = " + String(arrCombine(arr: inp, combineMode: combineMode)) return result } } diff --git a/RNG/NumberView.swift b/RNG/NumberView.swift index 7371f74..30d150c 100644 --- a/RNG/NumberView.swift +++ b/RNG/NumberView.swift @@ -5,36 +5,17 @@ // Created by Nihaal on 09/10/2024. // - - - - - - - - - -//fix date created -//TODO: readd ios 16 support -//TODO: try to use inject - - - - - - - import SwiftUI struct NumberView: View { @State var low: String = "1" @State var high: String = "10" @State var exclude: String = "none" - @State var generated = "5" + @State var generated = "" @State var prevGen = "" @State var generatedInt: Int = 0 @State var prevGenInt: Int = 0 - @State var dispResult = 5 + @State var dispResult = 0 var body: some View { List { HStack { @@ -65,30 +46,18 @@ struct NumberView: View { } Section("Description") { Text(describeInputs(min: low, max: high, exclude: exclude)) + .font(.headline) + .fontWeight(.heavy) + .frame(alignment: .center) } } - Text(String(dispResult)) - .font(.system(size: 75, weight: .bold)) + Text(generated) + .font(.system(size: 50, weight: .bold)) .foregroundColor(.gray) - .frame(height: 50) + .frame(height: 40) Button { prevGen = generated - generated = rng2(min: low, max: high, exclude: exclude) - prevGenInt = Int(prevGen)! - generatedInt = Int(generated)! - if prevGenInt < generatedInt { - for _ in prevGenInt...generatedInt { - dispResult += 1 - //sleep( UInt32( 1 / (generatedInt - prevGenInt) ) ) - } - } else if prevGenInt > generatedInt { - for _ in generatedInt...prevGenInt { - dispResult -= 1 - //sleep( UInt32( 1 / (prevGenInt - generatedInt) ) ) - } - } else if prevGenInt == generatedInt { - dispResult = generatedInt - } + generated = rng3(min: low, max: high, exclude: exclude) } label: { Text("Generate") .padding(.horizontal) @@ -96,26 +65,26 @@ struct NumberView: View { } .buttonStyle(BorderedProminentButtonStyle()) .cornerRadius(15) - .padding(.bottom) + .padding(.vertical) } } func describeInputs(min: String, max: String, exclude: String) -> String { - let validExcludes = ["start", "end", "both", "none"] + let validExcludes = ["start", "none", "end", "both"] guard validExcludes.contains(exclude) else { print("invalid exclude: " + exclude) return "invalid exclude: " + exclude } var result = "Any number from " - result += min != "" ? min : "_" + result += min result += " to " - result += max != "" ? max : "_" + result += max if min == "" || max == "" { return "Enter values above." - } else { - switch exclude { + } + switch exclude { case "start": result += ", excluding \(min)" case "end": @@ -126,48 +95,31 @@ func describeInputs(min: String, max: String, exclude: String) -> String { break default: result = "invalid 'exclude'" - } } - result += "." - return result + return result + "." } -enum rng2Errors: Error { - case h -} - -func rng2(min: String, max: String, exclude: String) -> String { - guard min != "" || max != "" else { - return "Enter values above." +func rng3(min: String, max: String, exclude: String) -> String { + var newMin = Int(min)! + var newMax = Int(max)! + guard newMin <= newMax else { + return "Invalid inputs" } - guard var minInt = Int(min) else { - print("invalid min") - return "-1" + guard newMin != newMax else { + return "No numbers" } - guard var maxInt = Int(max), maxInt >= minInt else { - print("invalid max or is less than min") - return "-1" + guard newMin + 1 != newMax else { + return "No numbers" } - guard exclude != "both", min != max else { - print("excluding both but min == max") - return "No possible numbers, both bounds equal." - } - let minIntPlus1 = minInt + 1 - guard exclude != "both", minIntPlus1 != maxInt else { - print("excluding both but min +1 == max") - return "No possible numbers." - } - var generated = 0 if exclude == "both" { - maxInt -= 1 - minInt += 1 + newMax -= 1 + newMin += 1 } else if exclude == "start" { - minInt += 1 + newMin += 1 } else if exclude == "end" { - maxInt -= 1 + newMax -= 1 } - generated = rng(min: minInt, max: maxInt) - return String(generated) + return String(rng(min: newMin, max: newMax)) } #Preview { diff --git a/RNG/PasswordView.swift b/RNG/PasswordView.swift index 2c6807c..af7dc55 100644 --- a/RNG/PasswordView.swift +++ b/RNG/PasswordView.swift @@ -10,12 +10,12 @@ import SwiftUI struct PasswordView: View { @State var selectedOptions: [PassOption] = [] let options: [PassOption] = [ - PassOption(name: "0-9", chars: Array("0123456789")), - PassOption(name: "a-z", chars: Array("abcdefghijklmnopqrstuvwxyz")), - PassOption(name: "A-Z", chars: Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + PassOption(name: "Digits", chars: Array("0123456789")), + PassOption(name: "Lowercase characters", chars: Array("abcdefghijklmnopqrstuvwxyz")), + PassOption(name: "Uppercase characters", chars: Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) ] @State var presetLen = 4 - @State var customLen = 8 + @State var customLen: Int = 0 @State var generated = "" @State var result = "" @State var history: [Int] = [] @@ -23,16 +23,6 @@ struct PasswordView: View { var body: some View { VStack { List { - Text("Hello, world!") - .font(.largeTitle) - .foregroundColor(.white) - .padding() - .background(Color.blue) - .padding() - .background(Color.mint) - .padding() - .background(Color.green) - Section("Include") { ForEach(options) { option in Toggle(isOn: Binding( @@ -59,35 +49,30 @@ struct PasswordView: View { Text("Custom: \(customLen)").tag(-1) } .pickerStyle(SegmentedPickerStyle()) + + if presetLen == -1 { + TextField("Custom", value: $customLen, formatter: NumberFormatter()) + .keyboardType(.numberPad) + .frame(width: 50) + } } - - if presetLen == -1 { - TextField("Custom", value: $customLen, formatter: NumberFormatter()) - .keyboardType(.numberPad) - .frame(width: 50) - } - - Text(String(result)) - .font(.system(size: 75, weight: .bold)) - .foregroundColor(.gray) - .frame(height: 50) - - Text(String(generated)) - .font(.system(size: 75, weight: .bold)) - .foregroundColor(.gray) - .frame(height: 50) - - Button { - generated = genPass(selectdOpts: selectedOptions, len: (presetLen == -1 ? customLen : presetLen)) - } label: { - Text("Generate") - .padding(.horizontal) - .font(.system(size: 25, weight: .bold)) - } - .buttonStyle(BorderedProminentButtonStyle()) - .cornerRadius(15) - .padding(.vertical) } + + Text(String(generated)) + .font(.system(size: 50, weight: .bold)) + .foregroundColor(.gray) + .frame(height: 40) + + Button { + generated = genPass(selectdOpts: selectedOptions, len: (presetLen == -1 ? customLen : presetLen)) + } label: { + Text("Generate") + .padding(.horizontal) + .font(.system(size: 25, weight: .bold)) + } + .buttonStyle(BorderedProminentButtonStyle()) + .cornerRadius(15) + .padding(.vertical) } } } @@ -103,7 +88,7 @@ struct PassOption: Identifiable { } func genPass(selectdOpts: [PassOption], len: Int) -> String { - let characters = selectdOpts.flatMap { $0.chars } + let characters = selectdOpts.flatMap { $0.chars } guard !(characters.isEmpty) else { print("characters empty") diff --git a/RNG/RNGApp.swift b/RNG/RNGApp.swift index dfc8044..aeddae9 100644 --- a/RNG/RNGApp.swift +++ b/RNG/RNGApp.swift @@ -35,15 +35,22 @@ func totalDoubleArr(arr: [Double]) -> Double { } // array combiner, adds or multiplies all ints in an array -func arrCombine(arr: [Int], combineMode: String) -> Int { - var output = 0 +func arrCombine(arr: [Int], combineMode: String) -> UInt { + var newArr: [UInt] = [] + for i in 0...(arr.count-1) { + newArr.append(UInt(arr[i])) + } + var output: UInt = 0 if combineMode == "plus" { - for num in arr { + for num in newArr { output += num } } else if combineMode == "multiply" { output = 1 - for num in arr { + for num in newArr { + guard output <= UInt.max / num else { + return UInt.max //cap at uint.max 2^64 + } output *= num } } else { @@ -53,11 +60,8 @@ func arrCombine(arr: [Int], combineMode: String) -> Int { return output } - func rng(min: Int, max: Int) -> Int { - var rng = 0 - rng = Int.random(in: min...max) - return rng + return Int.random(in: min...max) } func rng6Die() -> Int { @@ -69,6 +73,7 @@ func rngCDie(min: Int, max: Int) -> Int { } func rngN6DieArr(dies: Int) -> [Int] { + guard dies > 0 else { return [] } var output: [Int] = [] for _ in 1...dies { output.append(rng6Die())