Magic Square

Summary

Implement a "Magic Square", where a person selects a particular letter on the screen, and the computer tells them what they chose.

Topics

Requires beginning programming topics: variables, assignment, loops, input and output. Also requires a random number generator and character functions.

Standards

From the CSTA standards:

  • 1B-AP-09 Create programs that use variables to store and modify data. (P5.2)

  • 1B-AP-10 Create programs that include sequences, events, loops, and conditionals. (P5.2)

Audience

Introductory programming students in 9-12

Difficulty

Easy to medium level of difficulty, depending on how much scaffolding is provided.

Strengths

The "mind-reader" aspect inspires students to get it to work so they can show it to family and friends. Basic programming constructs (variables, assignment, loops, decision statements) must all be used to get it to work properly.

Weaknesses

It does require the use of a random number generator, which might be unfamiliar to students

Dependencies

Requires beginning programming topics: variables, assignment, loops, input and output. Using a random number generator and character functions are required, though they can be provided as easily reusable sample code. Functions are not required but are helpful.

Variants

  • The program can prompt for what "level" of analysis to do, and sometimes give randomly wrong answers at "lower" levels of analysis, to strengthen the illusion that it is based on pattern matching.

  • A GUI version similarly can use some sort of timing on button presses to make it seem like the user interaction makes a difference in the computer's guess.

See the presentation slides.

Video of Program

See the following YouTube video showing how the program works: https://youtu.be/VsabYB3aJbM


Play Online

Run a version of this program built in Code.org's App Lab at bit.ly/uicmindreader, also shown below:

Sample Runs of the Program

Playing the game looks like the following, where user input of the level to use is shown in bold. (For the non-extra credit version this input should always be 0.)

Program #3: Mind Reader

BTT CS 111: Program Design I in Python

Our subconscious get expressed in different ways, including

through choices we make, how we type, and how quickly we type.

Python libraries include Artificial Intelligence (AI) neural

network tools that can recognize patterns.

For this program choose the algorithm analysis level. Higher

levels take longer, but are more accurate. Level 4 works most

of the time.

Enter level > 1: 0

99:x 98:W 97:X 96:q 95:O 94:H 93:B 92:f 91:l 90:h

89:r 88:s 87:A 86:g 85:i 84:y 83:F 82:c 81:t 80:T

79:o 78:e 77:a 76:y 75:F 74:f 73:K 72:t 71:G 70:V

69:g 68:w 67:m 66:a 65:n 64:e 63:t 62:c 61:J 60:T

59:A 58:V 57:k 56:j 55:j 54:t 53:w 52:f 51:P 50:f

49:I 48:A 47:x 46:m 45:t 44:R 43:n 42:M 41:a 40:B

39:F 38:g 37:y 36:t 35:o 34:q 33:q 32:y 31:D 30:X

29:L 28:j 27:t 26:N 25:c 24:K 23:t 22:e 21:I 20:W

19:c 18:t 17:v 16:j 15:C 14:E 13:w 12:p 11:x 10:C

9:t 8:T 7:m 6:H 5:t 4:i 3:u 2:e 1:u 0:t

1. Choose any two-digit number in the table above (e.g. 73).

2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63)

3. Find this new number (e.g. 63) and remember the letter next to it.

4. Press 'a' to analyze responses: a

Your letter is: t


Playing the game again might look like:

Program #3: Mind Reader

BTT CS 111: Program Design I in Python

Our subconscious get expressed in different ways, including

through choices we make, how we type, and how quickly we type.

Python libraries include Artificial Intelligence (AI) neural

network tools that can recognize patterns.

For this program choose the algorithm analysis level. Higher

levels take longer, but are more accurate. Level 4 works most

of the time.

Enter level > 1: 0

99:D 98:m 97:e 96:c 95:M 94:J 93:y 92:H 91:r 90:I

89:F 88:d 87:G 86:A 85:U 84:I 83:i 82:f 81:h 80:J

79:X 78:l 77:t 76:v 75:q 74:f 73:p 72:h 71:C 70:R

69:j 68:J 67:W 66:J 65:Y 64:g 63:h 62:N 61:j 60:o

59:h 58:I 57:b 56:b 55:U 54:h 53:I 52:R 51:P 50:k

49:v 48:c 47:G 46:u 45:h 44:i 43:l 42:X 41:K 40:r

39:k 38:B 37:h 36:h 35:Y 34:T 33:h 32:K 31:f 30:o

29:b 28:w 27:h 26:J 25:V 24:k 23:k 22:K 21:E 20:u

19:T 18:h 17:c 16:t 15:o 14:e 13:M 12:f 11:s 10:l

9:h 8:o 7:L 6:L 5:J 4:d 3:g 2:g 1:b 0:h

1. Choose any two-digit number in the table above (e.g. 73).

2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63)

3. Find this new number (e.g. 63) and remember the letter next to it.

4. Press 'a' to analyze responses: a

Your letter is: h

What You Need to Know

The function used to get a random letter is shown below. This is used once at the beginning of the program to select the secret_character, and is also called once for every table location that is below loop counter value of 90 that is not divisible by 9, to get a random character to be displayed.


def get_Random_Letter():

# Get a random number, which will be the offset from 'a' or 'A'

letter_offset = random.randrange(0,25)

# Randomly choose between upper and lower case

if bool(random.getrandbits(1)):

# Make it upper case

random_char = chr(65 + letter_offset) #65 is the code for 'A'

else:

# Make it lower case

random_char = chr(97 + letter_offset) # 97 is the code for 'a'

return random_char

The secret to the program is that the program itself chooses a random "magic character" ahead of time, which in the case of the most recent table above is the character 'h'. For any number, if you subtract its individual digits from itself, then you end up with a number that is evenly divisible by 9. When the table is printed, in all the numbered locations below 90 where 9 is a factor (9, 18, 27, 36, 45, 54, 63,72, 81) the special character 'h' that was chosen ahead of time is displayed there. For all the rest of the characters a random character is chosen.

Suggested Steps

  1. Display the header lines at the top of the program

  2. Use a while loop to count from 99 down to 0. Display just those numbers, with a colon ':' and then a space after each one.

  3. Add code using the mod (%) function so that you print a new line character after each set of 10 output values. This will result in a row of numbers from 99 down to 90, a second row from 89 down to 80, and so on.

  4. After each number now also get a random letter by calling get_Random_Letter() (see below) and print that letter after the colon.

  5. Declare and use a variable for the secret letter. To do this, at the beginning of your program call function get_Random_Letter()and store the result into the secret letter variable (e.g. secret_char = get_Random_Letter() ). So that your output matches the expected output in the test cases, you should call the random number generator the minimum number of times. When your program starts, as explained above you should call function get_Random_Letter() once to find and store the secret letter, as explained above. Then for each table entry that is not less than 90 and evenly divisible by 9) you will again call get_Random_Letter(). You should not call the random number generator besides this, so that your output matches the expected output.

  6. Add code at the spot in your program where you display a random character for each table entry. If the loop counter is less than 90 and the counter value is evenly divisible by 9, then display the already-chosen secret_char and not a random character.

  7. Add the text and prompt at the bottom of the program.

Extra Credit

An extra credit version includes extra flair in the computer making the guess where there is extra output because the program is "Building a Neural Network" to make its forecast. This can be found at:

https://youtu.be/YcA78ERA0DQ

Running the extra credit version looks like:


Program #3: Mind Reader

BTT CS 111: Program Design I in Python

Our subconscious get expressed in different ways, including

through choices we make, how we type, and how quickly we type.

Python libraries include Artificial Intelligence (AI) neural

network tools that can recognize patterns.

For this program choose the algorithm analysis level. Higher

levels take longer, but are more accurate. Level 4 works most

of the time.

Enter level > 1: 4

99:D 98:m 97:e 96:c 95:M 94:J 93:y 92:H 91:r 90:I

89:F 88:d 87:G 86:A 85:U 84:I 83:i 82:f 81:h 80:J

79:X 78:l 77:t 76:v 75:q 74:f 73:p 72:h 71:C 70:R

69:j 68:J 67:W 66:J 65:Y 64:g 63:h 62:N 61:j 60:o

59:h 58:I 57:b 56:b 55:U 54:h 53:I 52:R 51:P 50:k

49:v 48:c 47:G 46:u 45:h 44:i 43:l 42:X 41:K 40:r

39:k 38:B 37:h 36:h 35:Y 34:T 33:h 32:K 31:f 30:o

29:b 28:w 27:h 26:J 25:V 24:k 23:k 22:K 21:E 20:u

19:T 18:h 17:c 16:t 15:o 14:e 13:M 12:f 11:s 10:l

9:h 8:o 7:L 6:L 5:J 4:d 3:g 2:g 1:b 0:h

1. Choose any two-digit number in the table above (e.g. 73).

2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63)

3. Find this new number (e.g. 63) and remember the letter next to it.

4. Press 'a' to analyze responses: a

Building neural network

.

.

.

.

Your letter is: h

Java Version

/** ---------------------------------------------

* This program implements a "Magic Square".

* The user chooses a two-digit number (i.e. 45) then

* subtracts the two digits in that number (i.e. 45 - 4 - 5 = 36)

* The user then remembers the letter next to that number.

*

* The computer then predicts what that letter is.

*

* Class: CS 102, Spring 2007

* Lab: Englebert Humberdink, Mon. 5:00 AM

* System: BlueJ 2.0.5, jsdk 1.5, Windows XP

*

* @author Dale Reed

* @version Jan 19, 2007

* ----------------------------------------------

*/


import java.util.Scanner; // used for console input

import java.util.Random; // used to get random numbers

// Declare the class

public class MagicSquare3

{

// Fields that can be accessed anywhere in the class go here

Scanner keyboard = new Scanner( System.in); // used to read user input

Random randomNumbers = new Random(); // used to generate random numbers


//----------------------------------------------------------------------------------------

// main() - startup main loop. It is necessary to create an instance of this class

// and then call a method from that instance, otherwise there are all kinds

// of error messages having to do with non-static objects (e.g. keyboard)

// being called from a static context (e.g. main). By creating the instance

// and *then* using keyboard, it is not longer being called from a static

// context. Don't worry about understanding all this right now.

//

public static void main(String[] args)

{

// create an instance of this class

MagicSquare3 theMagicSquare3Instance = new MagicSquare3();

// call a non-static method to do everything else

theMagicSquare3Instance.mainLoop();

}

//----------------------------------------------------------------------------------------

// mainLoop() - display identifying information and run main loop

//

void mainLoop()

{

// Display identifying information

System.out.println( "Author: Dale Reed \n" +

"Program 1: Magic Square \n" +

"TA: Billie Joe Armstrong, T 6:00 AM \n" +

"Jan 18, 2007\n");

// declare variables

String menuResponse = ""; // stores keypresses of user input

int randomNumber; // stores random numbers

char specialSymbol; // The special character for multiples of 9

// Outer loop allows repeating the program

while( ! menuResponse.equals("x")) {

// get a random number from 0..25

randomNumber = Math.abs( randomNumbers.nextInt()%26);

// determine the special character for multiples of 9

// If the random number is even, we'll create an upper case character. If the random number

// is odd, we'll create a lower-case character.

if( randomNumber%2 == 0) {

// random number is even, since the remainder after dividing by 2 == 0

specialSymbol = (char) ('A' + randomNumber); // create new upper-case letter

}

else {

specialSymbol = (char) ('a' + randomNumber); // create new lower-case letter

}


// set the counter and run the loop that displays the numbers

int counter = 99;

char characterToPrint = ' '; // stores the character to print on each iteration

System.out.println(); // leave a blank line at top of table

while( counter >= 0) {

// Find a random number from 0..25

randomNumber = Math.abs( randomNumbers.nextInt()%26);

// find out which character we will be printing, and store it in characterToPrint

// if the counter is a multiple of 9, store the special character to be displayed

if( ((counter%9) == 0) && (counter!=90)) {

characterToPrint = specialSymbol;

}

else {

// counter is not a multiple of 9

// If the random number is even, we'll create an upper case character. If the random number

// is odd, we'll create a lower-case character.

if( randomNumber%2 == 0) {

// random number is even, since the remainder after dividing by 2 == 0

characterToPrint = (char)('A'+randomNumber); // create new upper-case letter

}

else {

characterToPrint = (char)('a'+randomNumber); // create new lower-case letter

}

}

// now print the character, whatever it is

System.out.printf( "%4d:%c ", counter, characterToPrint);

// print an extra space to make things line up for values < 10

// go to a new line if we are at an even multiple of 10

if( counter%10 == 0) {

System.out.println();

}

// decrement the counter

counter--;

}//end while ( counter...

// display instructions

System.out.println();

System.out.println( "1. Choose any two-digit number in the table above (e.g. 73). ");

System.out.println( "2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63) ");

System.out.println( "3. Find this new number (e.g. 63) and remember the letter next to it. ");

System.out.print( "4. Now press the return key and I'll read your mind...");

menuResponse = keyboard.nextLine(); // read user input

// display "mind-reading" answer

System.out.println();

System.out.println( "I sense you are thinking of: " + specialSymbol);

// prompt for repeat or exit

System.out.println();

System.out.print( "Enter 'r' to repeat or 'x' to exit: ");

menuResponse = keyboard.nextLine(); // read user input

if( menuResponse.equals("x")) {

break; // exit the loop

}

}//end while( ! menuResponse...

System.out.println(" Thanks for playing, goodbye. \n\n");

}//end method mainLoop()


}//end class MagicSquare

C++ Version

/* ------------------------------------------------

* guessit.cc

* Program displays a grid of numbered symbols, then asks

* user to select one position, remembering the number.

* The digits of that number are subtracted from the original

* number, giving a new number. The user is asked to

* remember the symbol at that new number position.

* The computer then "guesses" what that symbol is and

* displays it.

*

* Class: Program #1 for CS 141, Fall 2017.

* Lab: Wed 5am

* System: Windows 10

* Author: Dale Reed

*

Running the program looks like:

Program #1: Guess It

Author: Dale Reed

Lab: Tues 5am

System: C++ on Cloud 9

99:w 98:X 97:e 96:k 95:R 94:a 93:y 92:g 91:y 90:w

89:c 88:e 87:V 86:N 85:w 84:y 83:X 82:a 81:w 80:P

79:c 78:y 77:D 76:c 75:R 74:N 73:m 72:w 71:q 70:H

69:R 68:c 67:k 66:R 65:B 64:g 63:w 62:N 61:F 60:N

59:D 58:P 57:i 56:D 55:T 54:w 53:F 52:R 51:w 50:w

49:D 48:m 47:J 46:o 45:w 44:T 43:L 42:s 41:J 40:J

39:k 38:i 37:P 36:w 35:F 34:e 33:a 32:w 31:m 30:H

29:V 28:H 27:w 26:c 25:N 24:y 23:V 22:V 21:w 20:c

19:D 18:w 17:c 16:g 15:V 14:P 13:y 12:H 11:o 10:R

9:w 8:i 7:m 6:w 5:s 4:k 3:J 2:u 1:R 0:w

1. Choose any two-digit number in the table above (e.g. 73).

2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63)

3. Find this new number (e.g. 63) and remember the letter next to it.

4. Now press the return key and I'll read your mind...

You selected the character: w

*/

#include <iostream> // For printf

#include <ctime> // For time()

#include <cstdlib> // For srand()

#include <iomanip> // For formatted output

using namespace std;



//-----------------------------------------------------------------------------------------

int main()

{

int randValue; // random number

char c; // random character, determined with a random number

char specialCharacter; // The special character that the computer will "guess"

// seed the random number generator

srand( time( 0)); // use this for different results each time


// Display ID information

cout << "\n";

cout << "Program #1: Guess It \n";

cout << "Author: Dale Reed \n";

cout << "Lab: Tues 5am \n";

cout << "System: C++ on Cloud 9\n";

cout << " \n";

// Choose a random character

randValue = rand() % 26; // generates a random value 0..25

// Add this random number to either 'A' or 'a' to get a random character.

// If the random number is odd, add it to 'a'. If even, add it to 'A'

if( randValue %2 == 0) {

specialCharacter = 'A' + randValue;

}

else {

specialCharacter = 'a' + randValue;

}

// For debugging:

// cout << "Special character is: %c \n\n", specialCharacter);

// Set the output precision

cout << fixed;

cout << setprecision(5);

// Display the 10x10 table of numbers and random characters

for( int i=99; i>=0; i--) {

// Get a random number 0..25

randValue = rand() % 26;

// Get a random character c, again making it upper-case if the random number

// was even, and making it lower-case if the random number was odd.

if( randValue %2 == 0) {

c = 'A' + randValue;

}

else {

c = 'a' + randValue;

}

// Display the number that preceeds each displayed character

printf("%2d:", i);

// Display this random character. If the position is a multiple

// of 9, display the "special" character instead.

if( i%9 != 0) {

cout << c; // display the random character

}

else {

cout << specialCharacter; // display the special character

}

cout << " ";

// print a newline character if we're at the end of a line

if( i%10 == 0) {

cout << "\n";

}

}//end for( int i...

// Display instructions and have user press enter when ready

cout << "\n";

cout << "1. Choose any two-digit number in the table above (e.g. 73). \n";

cout << "2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63) \n";

cout << "3. Find this new number (e.g. 63) and remember the letter next to it. \n";

cout << "4. Now press 'r' and I'll read your mind... ";

cin >> c; // read user input

cout << endl;

// Display computer forecast

cout << "You selected the character: " << specialCharacter;

cout << endl;

return 0;

}//end main()



Python Version

# Magic Square mind-reader program

# Dale Reed, UIC BTT CS 111, Spring 2022

#

# Program #3: Mind Reader

# BTT CS 111: Program Design I in Python

#

# Sample run of program:

#

# Our subconscious get expressed in different ways, including

# through choices we make, how we type, and how quickly we type.

# Python libraries include Artificial Intelligence (AI) neural

# network tools that can recognize patterns.

# For this program choose the algorithm analysis level. Higher

# levels take longer, but are more accurate. Level 4 works most

# of the time.

# Enter level > 1: 0

#

# 99:y 98:i 97:P 96:o 95:u 94:g 93:p 92:m 91:T 90:y

# 89:w 88:I 87:H 86:D 85:k 84:a 83:U 82:A 81:E 80:M

# 79:G 78:N 77:A 76:H 75:O 74:P 73:h 72:E 71:H 70:H

# 69:O 68:J 67:a 66:R 65:u 64:F 63:E 62:X 61:j 60:x

# 59:X 58:W 57:N 56:v 55:j 54:E 53:S 52:P 51:q 50:S

# 49:b 48:H 47:m 46:v 45:E 44:L 43:W 42:V 41:l 40:O

# 39:q 38:y 37:Q 36:E 35:m 34:P 33:a 32:b 31:W 30:T

# 29:s 28:u 27:E 26:F 25:H 24:A 23:G 22:r 21:M 20:L

# 19:s 18:E 17:O 16:I 15:R 14:x 13:M 12:X 11:E 10:Y

# 9:E 8:g 7:b 6:L 5:r 4:q 3:P 2:l 1:l 0:E

#

# 1. Choose any two-digit number in the table above (e.g. 73).

# 2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63)

# 3. Find this new number (e.g. 63) and remember the letter next to it.

# 4. Now press 'a' to analyze responses: a

#

# Your letter is: E


import random # Needed for random number generation

import time # Needed for sleep, which pauses the program


# --------------------------------------------------------------------------

# Get a random letter, which could be upper-case or lower-case

def get_Random_Letter():

# Get a random number, which will be the offset from 'a' or 'A'

letter_offset = random.randrange(0,25)

# Randomly choose between upper and lower case

if bool(random.getrandbits(1)):

# Make it upper case

secret_char = chr(65 + letter_offset)

else:

# Make it lower case

secret_char = chr(97 + letter_offset)

return secret_char



# --------------------------------------------------------------------------

# Main part of the program.

# Display identifying information when program runs

print('Program #3: Mind Reader')

print('BTT CS 111: Program Design I in Python')

print()


# Pretend that we have different "levels" of brain scan.

# Display a distractor message.

print('Our subconscious get expressed in different ways, including')

print('through choices we make, how we type, and how quickly we type.')

print('Python libraries include Artificial Intelligence (AI) neural ')

print('network tools that can recognize patterns.')

print('For this program choose the algorithm analysis level. Higher')

print('levels take longer, but are more accurate. Level 4 works most')

print('of the time.')

level = int( input('Enter level > 1: '))

print()


# Use the level as the random number generator seed. Multiple runs using the same

# level should give the same result.

random.seed( level)


# Generate a random secret letter

secret_char = get_Random_Letter()


counter = 99

while counter >= 0:

# Get the character to be displayed. This should be a random character,

# unless the current counter value is evenly divisible by 9, in which

# case it should be the secret_char.

if (counter % 9 == 0) and (counter < 90):

the_char = secret_char

else:

the_char = get_Random_Letter()

print(f'{counter:2d}:{the_char} ', end = '')

# Print a new line if we're at the end of a row

if counter % 10 == 0:

print()

# Increment the loop counter

counter -= 1


# Display instructions for users to find their new table cell, and

# prompt for 'a' to analyze responses.

print()

print('1. Choose any two-digit number in the table above (e.g. 73).')

print('2. Subtract its two digits from itself (e.g. 73 - 7 - 3 = 63) ')

print('3. Find this new number (e.g. 63) and remember the letter next to it. ')

userInput = input("4. Press 'a' to analyze responses: ")


# If input was > 0 then display the dots . . . indicating the program is thinking

if level > 0:

print(' Building neural network')

counter = 1

# Ensure the number of seconds to wait is a maximum of 5

if level > 5:

level = 5

while counter <= level:

print(' .')

time.sleep( 1)

counter += 1

# Display the computer's character guess

print()

print('Your letter is: ', end = '')

# Display the correct answer for levels 5+. For level 0 always give the right answer.

# For levels 1..4 use probabilities. The probability of the right answer being shown

# depends on the level: 1 = 20%, 2 = 40%, 3 = 60%, 4 = 80%, 5+ = 100%

if level == 0:

success_probability = 1.0 # Ensure level 0 always gives the correct answer

else:

success_probability = level * .2

random_Number = random.random()

if random_Number <= success_probability:

# Show the correct answer

print(secret_char)

else:

print( get_Random_Letter())

Python Starter Code

# Sample code to illustrate concepts needed for this program

import random # Needed for random number generation


# Initialize the random number generator so the results are reproducible each time.

# Comment out the following line, or simply remove the number in parenthesis to give

# different results each time the program is run. Make sure this line is uncommented

# when you test/turn in your program, so your results will match the expected results!

# random.seed( 1)


# Generate a random number in the range 0..25

value = random.randrange(0,25)

print('Random value is:',value)

# Display the corresponding alphabetical character. 65 corresponds to 'A', 66 to 'B',

# and so on. The chr() function converts a number to its corresponding character.

print( chr(65+value))


# Get a random true / false value

random_true_or_false = bool(random.getrandbits( 1)) # Generate a single 0/1 bit and convert it to true/false

print('Random value is:',random_true_or_false)


# Illustrate how a while loop works

counter = 1 # Initialize the loop counter

while counter < 10: # Check the loop ending condition

print( counter," ",end=' ')

counter += 1 # Increment the loop counter

print()


# Prompt for a value, and print a message indicating whether or not it is divisible by 3

print('Enter an integer number, to see if it is divisible by 3:', end=' ')

value = int(input())

if value % 3 == 0:

print(value,'is divisible by 3.')

else:

print(value,'is NOT divisible.')

Dale Reed, reed@uic.edu
Brenda Remess, bremess@cps.edu