1

I'm trying to make a caesar cipher in Swift Playgrounds but whenever the letter is for example "W" and I'm trying to shift it by 4, instead of getting "A" I just get an error. If the ascii code + shift doesn't exceed the ascii code for Z, it works just fine, otherwise I get

error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).

Here is my code:

func cipher(messageToCipher: String, shift: UInt32) {
    var ciphredMessage = ""

    for char in messageToCipher.unicodeScalars {
        var unicode : UInt32 = char.value

        if char.value > 64 && char.value < 123 {
            var modifiedShift = shift
            if char.value >= 65 && char.value <= 90 {
                while char.value + modifiedShift > 90 {
                 //return to A
                    modifiedShift -= 26
                }
            } else if char.value >= 97 && char.value <= 122 {
                while char.value + modifiedShift > 122 {
                  //return to a
                    modifiedShift -= 26
                }
            }

            unicode = char.value + modifiedShift
        }

        ciphredMessage += String(UnicodeScalar(unicode)!)
    }

    print(ciphredMessage)
}

Can anyone tell me why I get error when the ascii code for the letter + shift exceeds the "z"'s ascii code?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
AndreiVataselu
  • 216
  • 2
  • 16

2 Answers2

3

The shift is UInt32. So, with var modifiedShift = shift, modifiedShift is inferred to be UInt32, too. So when you set modifiedShift to 4, and then try to subtract 26 from it, that's not an acceptable UInt32 value.

Bottom line, use signed integers.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • @AndreiVataselu It is just not allowed for a `UInt32` value to be lower than 0. Otherwise you can subtract from it as long this condition is fulfilled – Qbyte Dec 03 '17 at 23:57
  • Yes, I deleted my comment after I checked the range of UInt32 on the internet and realized I'm stupid. Thanks a lot man, didn't think a second about UInt32 ranges – AndreiVataselu Dec 03 '17 at 23:59
1

The problem is that the value of modifiedShift can be negative which is NOT allowed for a value of type UInt32 so I would suggest to use only Int whenever you can:

// use `Int` for `shift`
func cipher(messageToCipher: String, shift: Int) {
    var ciphredMessage = ""

    for char in messageToCipher.unicodeScalars {
        // convert to `Int`
        var unicode = Int(char.value)

        if unicode > 64 && unicode < 123 {
            var modifiedShift = shift
            if unicode >= 65 && unicode <= 90 {
                while unicode + modifiedShift > 90 {
                    //return to A
                    modifiedShift -= 26
                }
            } else if unicode >= 97 && unicode <= 122 {
                while unicode + modifiedShift > 122 {
                    //return to a
                    modifiedShift -= 26
                }
            }

            unicode += modifiedShift
        }

        ciphredMessage += String(UnicodeScalar(unicode)!)
    }

    print(ciphredMessage)
}

Note: you can also use if case for range matching. The following lines are semantically equivalent:

if unicode > 64 && unicode < 123 { ... }
if case 65..<123 = unicode { ... }
if (65..<123).contains(unicode) { ... }
Qbyte
  • 12,753
  • 4
  • 41
  • 57