DEV Community

Cover image for 3 Intermediate Python coding challenges (with solutions)
rachel
rachel

Posted on

3 Intermediate Python coding challenges (with solutions)

The previous Python coding challenges for beginners seem to be well-received so I decided to create another post for intermediate coding challenges. Have fun solving & don't hesistate to share your feedback or solutions in the comment section :)

1. Caesar Cipher

Background:
Caesar's cipher is a simple encryption technique, in which the plaintext character is replaced by a letter some fixed number of positions down the alphabet.

For example, with a right shift of 3, A would be replaced by D, B would become E, and so on.

Caesar's cipher

Task:
Write a Python program to decode the following secret message: N qtaj uwtlwfrrnsl zxnsl Udymts, given that the key is 5.

Starter code:



ciphertext = "N qtaj uwtlwfrrnsl zxnsl Udymts"

def decrypt(ciphertext, key):
    # complete code here

decrypt(ciphertext, 5)


Enter fullscreen mode Exit fullscreen mode

Sample solution:



def decrypt(ciphertext, key):
    letters = "abcdefghijklmnopqrstuvwxyz"
    letters_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

    message = ""

    for char in ciphertext:
        if char in letters:      
            position = letters.find(char)
            new_pos = (position - key) % 26
            new_char = letters[new_pos]
            message += new_char
        elif char in letters_upper:
            position = letters_upper.find(char)
            new_pos = (position - key) % 26
            new_char = letters_upper[new_pos]
            message += new_char
        else:
            message += char
        return message

print(decrypt(cipher, 5))


Enter fullscreen mode Exit fullscreen mode

2. Simple Mastermind Game

Task:
Write a program that randomly generates a 4 digit number. The user has maximum 10 tries to guess the number.

  • If any of the digit guessed is wrong, print "A" to indicate wrong guess.

  • If the digit is guessed correctly but in the wrong position, print "B".

  • If the digit guessed is both the correct value and position, print "C".

Starter code:



import random

def generate_number():
    # complete code here

def input_guess():
    guess = input("Enter your guess: ")
    return guess

def start_game():
    # complete code here

start_game()


Enter fullscreen mode Exit fullscreen mode

Sample solution:



import random

def generate_number():
    num = random.randint(1000,9999)
    num = [int(x) for x in str(num)]
    return num

def input_guess():
    guess = input("Enter your guess: ")
    return guess

def start_game():
    tries = 0
    number = generate_number()

    while tries < 10:
        result = ""
        guess = [int(i) for i in input_guess()]

        if len(guess) != 4:
            print("Enter only 4 digit number")
            continue

        if guess == number:
            print("You won with ", tries, " attempts.")
            break

        for element in guess:
            if element in number:
                if guess.index(element) == number.index(element):
                    result+="C"
                else:
                    result+="B"
            else:
                result+="A"
        print(result)
        tries += 1

    else:   
        print("You ran out of attempts. The answer is: " , "".join(map(str, number)))   

start_game()


Enter fullscreen mode Exit fullscreen mode

3. Roman Numerals & Integer Converter

Background:
The Roman numeral system consists of the following symbols:

Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000

Numbers are constructed by combining these symbols. For instance, the number 12 can be represented by XII, since X + I + I = 10 + 1 + 1.

The following list is set of rules for Roman numerals:

  • Zero is not represented.

  • A symbol can be repeated only for three times.

  • Roman numerals are repeated to add value: III is equivalent to 1 +1 +1 = 3. However, only powers of 10 may be repeated in this way. Thus, VV is invalid; 5 + 5 would instead be expressed as X.

  • When a Roman numeral is placed after another Roman numeral of greater value, the result is the sum of the numerals. When a Roman numeral is placed before another Roman numeral of greater value, the result is the difference between the numerals.

  • Only I, X, and C can be used as subtractive numerals as shown:

    • I can be used before V(5) and X(10) to make it IV(4) and XV(9) respectively.
    • X cab be used before L(50) and C(100) to make it XL(40) and XC(90) respectively
    • C can be used before D(500) and M(1000) to make them CD(400) and CM(900) respectively.

Task:
Write a program that allows users to either convert integers to roman numerals, or convert roman numerals to integers.

Starter code:



def roman_to_int(roman):
  # complete code here

def int_to_roman(int):
  # complete code here

print(" ---------- Roman Numberals Conversion ----------")  
print(" > 1 - Convert an integer to a roman numerals,")  
print(" > 2 - Convert a roman numerals to an integer.")  
option = input("Choose an option (1 or 2):")  
# complete code here


Enter fullscreen mode Exit fullscreen mode

Sample solution:



def roman_to_int(s):
    roman_values = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}

    result = 0

    for i in range(len(s)):
        if i + 1 < len(s) and roman_values[s[i]] < roman_values[s[i + 1]]:
            result -= roman_values[s[i]]
        else:
            result += roman_values[s[i]]

    return result


def int_to_roman(x):
    roman_map = { 1: 'I', 4: 'IV', 5: 'V', 9: 'IX', 10: 'X', 40: 'XL', 50: 'L', 90: 'XC', 100: 'C', 400: 'XD', 500: 'D', 900: 'CM', 1000: 'M'}
    integers = list(roman_map)
    symbols = list(roman_map.values())

    i = 12
    result = ""

    while x != 0:
        if integers[i] <= x:
            result += symbols[i]
            x -= integers[i]
        else:
            i -= 1

    return result


print(" ---------- Roman Numberals Conversion ----------")  
print(" > 1 - Convert an integer to a roman numerals,")  
print(" > 2 - Convert a roman numerals to an integer.")  
option = input("Choose an option (1 or 2):")  

if option == "1":
    num = int(input("Enter an integer: "))
    print(int_to_roman(num))
elif option == "2":
    roman = input("Enter a Roman numeral: ")
    print(roman_to_int(roman))
else:
    print("Invalid input.")


Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
bunny03 profile image
Ondřej

Hello, I think your mastermind game code has a mistake. For exaple when the number is 9950 and the guess is 9955, it prints out "CCCC" even tho the guess is not correct.
The problem is in the for cycle when comparing indexes. I tried to rewrite the code so it works better. Here is the part of my code:

        j = -1
        for element in guess:
            j += 1
            if element in number:
                if element == number[j]:
                    result+="C"
                else:
                    result+="B"
            else:
                result+="A"
Enter fullscreen mode Exit fullscreen mode

What do you think about it?

Collapse
 
rachelsarchive profile image
rachel • Edited

Yes, you are right. In my original code, the index() method returns the index of the first occurrence of the element in the list, resulting in only comparing the initial index of the elements rather than the actual index. Your code works correctly, I will also include an alternate method below:

for index, element in enumerate(guess):
      if (element == number[index]):
        result += 'C'
      elif element in number:
        result += 'B'
      else:
        result += 'A'
Enter fullscreen mode Exit fullscreen mode

Thank you for your comment!

Collapse
 
skaarjwarrior profile image
Jonathan • Edited

Cypher breaks the first covenant: DRY.
A better, shorter and more functional solution is here:

Image description

It's just a case of determining the character code of each character, adjusting for SPC, case and alphabetical wrap around and subtracting the key.

Collapse
 
rachelsarchive profile image
rachel

Thank you for the insight! I wrote this in the beginning of my coding journey and reflecting now, I must say that it is not the optimal solution. Your code is more succint and effiecient. By using the ord() approach, it eliminates the need of predefining the letter strings. It also handles wraparound cases more elegantly, as it directly calculates the new ASCII value based on the shift.