TI-84 programming Python – Mastermind

In this project you’ll learn how to adapt source-code to TI-84.
I’ve used this code as a base: Mastermind

The game
If you want to play the game you have to know the rules of Mastermind.
There are 6 colors, each of them have a different number:
1 – RED, 2 – GREEN, 3 – YELLOW, 4 – BLUE, 5 – BLACK, 6 – ORANGE
Example: RED YELLOW ORANGE BLACK —> 1 3 6 5

After entering your code (for instance 1 1 2 2) you’ll get back feedback with two characters:
R – color and position is OK
W – only the color is OK

The source code

I’ve checked the sample program in in Github, file MASTR002.py. I’ve made several commits with comments to make it easier for you to follow the steps.

There were several challenges to solve.
The “random” functionality of the TI-84 lacks a function “shuffle”, so I had to rewrite the code like this:

Original code:
random.shuffle(colors)
passcode = colors[:4]
Changed code:
col1 = random.randrange(1, 6)
col2 = random.randrange(1, 6)
col3 = random.randrange(1, 6)
col4 = random.randrange(1, 6)
# passcode = colors[:4]
passcode = []
passcode.clear()
passcode.append(colors[col1])
passcode.append(colors[col2])
passcode.append(colors[col3])
passcode.append(colors[col4])

You see, quite a change! In the first part (col1..col4) the variables are filled with a random number between 1 and 6. In the second part, the table passcode is filled with the generated codes (col1..col4)

Then, there was this problem with the display: the display of the TI-84 is quite small.
So, I’ve defined a variable called dottedline and initialized it with a much smaller value.

BEFORE
print("-----------------------------------------")
print("\t      MASTERMIND")
print("-----------------------------------------")

AFTER
dottedline="------------------------"
print(dottedline)
print(" MASTERMIND")
print(dottedline)

TESTING and REFACTORING

While testing the mastermind.py script I discovered that the setting of the guess_flags was not always correct.
Steps to improve it:
Take the original code and make a function out of it:

# Function to set the guess_flags
def setGuessflags(guess_flags, turn, code, colors_map, passcode):
    dummy_passcode = [x for x in passcode]
    pos = 0
    for x in code:
        if colors_map[x] in dummy_passcode:
            if code.index(x) == passcode.index(colors_map[x]):
                guess_flags[turn][pos] = 'R'
            else:
                guess_flags[turn][pos] = 'W'
            pos += 1
            dummy_passcode.remove(colors_map[x])
    return guess_flags

Test the function “setGuessflags” to see if it works like before.
Afterward: implement a simpler version of setGuessflags

Build unit tests first, check Stackoverflow how to do that:

import unittest
from MASTR002 import setGuessflags
# https://stackoverflow.com/questions/52013612/python-unittest-does-not-run-tests

class Mastr002TestCase(unittest.TestCase):
    def test_setGuessflagsRed(self):
        chances = 8
        passcode = []
        passcode.append(1)
        passcode.append(6)
        passcode.append(2)
        passcode.append(5)
        turn=1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['1', '6', '2', '5'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags,turn,guess_codes,passcode)
        self.assertEqual(['R', 'R', 'R', 'R'], newguessflags[1])

    def test_setGuessflagsRedWhite(self):
        chances = 8
        passcode = []
        passcode.append(1)
        passcode.append(6)
        passcode.append(2)
        passcode.append(5)
        turn=1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['1', '6', '5', '2'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags,turn,guess_codes,passcode)
        self.assertEqual(['R', 'R', 'W', 'W'], newguessflags[1])

    def test_setGuessflagsNone(self):
        chances = 8
        passcode = []
        passcode.append(1)
        passcode.append(6)
        passcode.append(2)
        passcode.append(5)
        turn=1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['2', '2', '3', '3'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags,turn,guess_codes,passcode)
        self.assertEqual(['W', '-', '-', '-'], newguessflags[1])

    def test_setGuessflagsSimulation2262(self):
        chances = 8
        passcode = []
        passcode.append(2)
        passcode.append(2)
        passcode.append(6)
        passcode.append(2)
        turn=1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['1', '1', '2', '2'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags,turn,guess_codes,passcode)
        self.assertEqual(['-', '-', 'W', 'W'], newguessflags[1])

    def test_setGuessflagsSimulation4464(self):
        chances = 8
        passcode = []
        passcode.append(4)
        passcode.append(4)
        passcode.append(6)
        passcode.append(4)
        turn = 1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['4', '4', '4', '4'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags, turn, guess_codes, passcode)
        self.assertEqual(['R', 'R', 'W', '-'], newguessflags[1])


if __name__ == '__main__':
    unittest.main()

After successful unit tests the code looks like this:

# Function to set the guess_flags
def setGuessflags(guess_flags, turn, code, passcode):
    ii = 0
    passcodeItemChecked=[]
    for x in code:
        if (ii==turn):
           cc=0
           for codeitem in x:
               pp=0
               for passcodeitem in passcode:
                   # check if passworditem is already processed
                   toprocess = True
                   for pitem in passcodeItemChecked:
                       if pitem == pp:
                           toprocess = False
                   if toprocess == True:
                      if (str(codeitem)==str(passcodeitem)):
                         if cc==pp:
                            guess_flags[turn][cc] = 'R'
                         else:
                            guess_flags[turn][cc] = 'W'
                         passcodeItemChecked.append(pp)
                         break
                   pp +=1
               cc +=1
        ii +=1

    return guess_flags

Fine Tuning

After further testing I’ve discovered another smaller problem: I’ve forgotten to prioritize:
The most important are the RED colors (code and position).

So, I’ve added another Unittest (test first!):

    def test_setGuessflagsSimulation4464(self):
        chances = 8
        passcode = []
        passcode.append(4)
        passcode.append(4)
        passcode.append(6)
        passcode.append(4)
        turn = 1
        guess_flags = [['-', '-', '-', '-'] for x in range(chances)]
        guess_codes = [['4', '4', '4', '4'] for x in range(chances)]
        newguessflags = setGuessflags(guess_flags, turn, guess_codes, passcode)
        self.assertEqual(['R', 'R', '-', 'R'], newguessflags[1])



And changed (and tested) the method “setGuessflags”:

def setGuessflags(guess_flags, turn, code, passcode):
    ii = 0
    passcodeItemChecked=[]
    # check code and position
    for x in code:
        if (ii==turn):
           cc=0
           for codeitem in x:
               pp=0
               # check code and position
               for passcodeitem in passcode:
                   # check if passworditem is already processed
                   toprocess = True
                   for pitem in passcodeItemChecked:
                       if pitem == pp:
                           toprocess = False
                   if toprocess == True:
                      if (str(codeitem)==str(passcodeitem)):
                         if cc==pp:
                            guess_flags[turn][cc] = 'R'
                            passcodeItemChecked.append(pp)
                         break
                   pp +=1
               cc +=1
        ii += 1
    ii = 0
    # check code independent of position
    for x in code:
        if (ii == turn):
           cc = 0
           for codeitem in x:
               pp = 0
               # check code
               for passcodeitem in passcode:
                   # check if passworditem is already processed
                   toprocess = True
                   for pitem in passcodeItemChecked:
                       if pitem == pp:
                           toprocess = False
                   if toprocess == True:
                       if (str(codeitem) == str(passcodeitem)):
                           if cc == pp:
                               guess_flags[turn][cc] = 'R'
                           else:
                               guess_flags[turn][cc] = 'W'
                           passcodeItemChecked.append(pp)
                           break
                   pp += 1
               cc +=1
        ii +=1
    return guess_flags



Next challenges
Try to define more functions in the source code MASTR002 and test it with Unit-Tests


Try to implement Mastermind in another language like react.
You can see a sample here:
https://react.rocks/example/Mastermind