Rewrote basically half the app

+ reamde
+ noDebug.xcscheme
+ ui improvements
+max die is 100+overflow protextion
+fix giant padding in diceview
+rewrite rng2()
+ui friedlification
+rewrite arrCombine
This commit is contained in:
neon443
2024-12-01 11:18:15 +00:00
parent b94536cea1
commit 64a517333b
7 changed files with 236 additions and 194 deletions

8
README.md Normal file
View File

@@ -0,0 +1,8 @@
# RNG_Swift
A fully featured Randomizer written in Swift with UI in SwiftUI!
## Features
- Number generator
- Password generator
- Die Generator

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1610"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
BuildableName = "RNG.app"
BlueprintName = "RNG"
ReferencedContainer = "container:RNG.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
BuildableName = "RNG.app"
BlueprintName = "RNG"
ReferencedContainer = "container:RNG.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A9794C7E2CB70ADA00527984"
BuildableName = "RNG.app"
BlueprintName = "RNG"
ReferencedContainer = "container:RNG.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -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()
}

View File

@@ -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..<displayDies.count, id: \.self) { index in
Image(systemName: "die.face.\(displayDies[index])")
if displayDies.isEmpty {
Text("Tap Generate to get started!")
.font(.headline)
.fontWeight(.heavy)
.frame(alignment: .center)
} else {
LazyVGrid(columns: columns, spacing: 2.5) {
ForEach(0..<displayDies.count, id: \.self) { index in
Image(systemName: "die.face.\(displayDies[index])")
.resizable()
.scaledToFit()
.frame(width: 40, height: 40)
if index != displayDies.count-1 {
Image(systemName: displayMultiDieMode)
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
if index != displayDies.count-1 {
Image(systemName: displayMultiDieMode)
.resizable()
.scaledToFit()
.frame(width: 10, height: 10)
}
.frame(width: 15, height: 15)
}
}.padding()
}
}
}
}
}
Text(String(result))
.font(.system(size: 75, weight: .bold))
.font(.system(size: 50, weight: .bold))
.foregroundColor(.gray)
.frame(height: 50)
.frame(height: 40)
Text(resultDescription)
.frame(height: 20)
.frame(height: 10)
.font(.system(size: 10))
Button {
generated = rngN6DieArr(dies: Int(dies))
displayDies = generated
@@ -90,12 +100,12 @@ func describeResult(inp: [Int], combineMode: String) -> 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
}
}

View File

@@ -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 {

View File

@@ -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")

View File

@@ -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())