Skip to article frontmatterSkip to article content

Welcome to this lab where you will explore how computers represent numbers using a fun card-guessing game! Through this lab, you will gain an understanding of how binary numbers are used to represent decimal numbers in computers.

Card Guessing Game

Rules

Table 1:Deck of cards

12345678910JQK
DiamondA-Diamond2-Diamond3-Diamond4-Diamond5-Diamond6-Diamond7-Diamond8-Diamond9-Diamond10-DiamondJ-DiamondQ-DiamondK-Diamond
ClubA-Club2-Club3-Club4-Club5-Club6-Club7-Club8-Club9-Club10-ClubJ-ClubQ-ClubK-Club
HeartA-Heart2-Heart3-Heart4-Heart5-Heart6-Heart7-Heart8-Heart9-Heart10-HeartJ-HeartQ-HeartK-Heart
SpadeA-Spade2-Spade3-Spade4-Spade5-Spade6-Spade7-Spade8-Spade9-Spade10-SpadeJ-SpadeQ-SpadeK-Spade

Table 1 shows a deck of 52 cards:

  • Each card is in one of the four suits: Diamond ♦, Club ♣, Heart ♥, and Spade ♠.
  • Each card has a value ranging from 1 to 13. For simplicity, the original card values A, J, Q, and K are converted to the numerical values 1, 11, 12, and 13 respectively.
A player guesses a card drawn by a dealer.

Figure 1:Card guessing game

Rules

As depicted in Figure 1, the card-guessing game involves the following steps:

  • The dealer selects a card without revealing it to the player.
  • The player’s goal is to correctly guess the chosen card.
  • To make an informed guess, the player can ask up to six yes/no questions.
  • The dealer must answer each question truthfully and immediately.
Example 1 (Valid questions)

For instance, the player may ask:

  • Is the suit club?
  • Is the card diamond 1?
  • Is the value at least 10?
Example 2 (Invalid questions)

However, the player cannot ask:

  • What is the value?
  • What is the suit?

because the answers are not yes/no.

One strategy is to ask whether the randomly drawn card is a specific card, e.g.,

Is it the Diamond 1?

If the answer is yes, the player can confidently guess that the card is Diamond 1 and win the game. However, if the answer is no, the player can continue to check another card, e.g.,

Is it the Diamond 2?

and so on...

A pseudocode that summarizes the above strategy (or algorithm) is shown below.

# YOUR CODE HERE
raise NotImplementedError
# tests
assert chance >= 0
assert chance <= 1
# hidden tests

Virtual Cards

Instead of drawing a physical card, the dealer can use programming to generate a virtual deck and draw a random[1] virtual card from it. Run the code below to get the required tools.

from collections import namedtuple  # for naming the cards
from random import choice  # for randomly drawing cards

You’ll learn the syntax in a future lecture, but even now, it is clear that the code imports libraries for creating named tuples and making random choices, thanks to the design of Python being a high-level programming language.

To create a deck of cards, run the following cell.

suits = ("Diamond", "Club", "Heart", "Spade")
values = range(1, 14)
Card = namedtuple("Card", ["value", "suit"])
deck = [Card(value, suit) for value in values for suit in suits]
deck

The code above uses composite data types like tuples and lists, which will be formally introduced later in the course. They are handy for storing and manipulating collections of values.

Now, you can use the following program to play the game with your friends:

choice(deck)
def draw_five_cards_randomly():
    # YOUR CODE HERE
    raise NotImplementedError
    return  card1, card2, card3, card4, card5
# tests
import random

random.seed(1302)  # to make pseudo-random sequences reproducible
assert (lambda cards: any(cards[i] != cards[4] for i in range(4)))(
    draw_five_cards_randomly()
)
# hidden tests

Virtual Player

Given you have randomly drawn a card,

  1. run the following code cell, and
  2. answer the 6 questions raised by the player honestly by entering
    • 1 for yes and
    • 0 for no.
def is_yes(question):
    """Get an answer to a yes/no question."""
    return "1" == input(question + " 1:yes [0:no] ")


suit_idx = number = 0
if is_yes("Is the suite either heart or spade?"):
    suit_idx += 2
if is_yes("Is the suite either club or spade?"):
    suit_idx += 1
for i in range(3, -1, -1):
    number += 2**i * is_yes(f"Is the number {number+2**i} or above?")
print(f"The card is {suits[suit_idx]} {number}")

The code above provides an overview of various programming syntaxes to be covered in the course. Although you don’t need to be familiar with them now, it’s good to have a basic understanding:

  • The program first defines a function called is_yes that checks whether the answer to a given question is yes.
  • To compute the guess, the program modifies the values of the variables suit_idx and number using
    • conditional if statements and
    • a for loop, along with
    • different operations such as
      • chained assignment =,
      • augmented assignment +=,
      • equality comparison ==, and
      • exponentiation **.
def number_of_cards(number_of_questions):
    # YOUR CODE HERE
    raise NotImplementedError
    return ans
# tests
assert number_of_cards(number_of_questions=6) > len(deck) 
# hidden tests

Binary Number System

Representing non-negative integers

The following table gives the binary representions of unsigned decimal integers from 0 to 7.

Table 2:Encoding positive integers

BinaryDecimal
0000
0011
0102
0113
1004
1015
1106
1117

Observe that the binary representations of 4, 5, 6, and 7 all have 1 in the leftmost (most significant) bit. Consider that bit as the answer to the following yes/no question when converting an integer n to binary:

Is the integer 4 or above, i.e., n4n\geq 4?

Now, to convert the entire binary sequence to decimal, we can think of the conversion as a guessing game where

  • the binary sequence is a sequence of yes (1) or no (0) answers to certain yes/no questions, and
  • the informed guess is the integer represented by the binary sequence.
Decoding tree

The following code attempts to convert integers between 0 and 7 to their binary strings.

def decimal_to_binary(n):
    def get_bit(cond):
        return "1" if cond else "0"
    return get_bit(eval(Q1)) + get_bit(eval(Q2)) + get_bit(eval(Q3))

# Define the questions
Q1, Q2, Q3 = "n >= 4", "n >= 2", "n >= 1"

# Print the conversions decimal (binary)
print(*[f"{i} ({decimal_to_binary(i)})" for i in range(8)], sep="\n")
# Assign strings to Q2 and Q3
# YOUR CODE HERE
raise NotImplementedError
Q2, Q3
# test
assert decimal_to_binary(2) == '010'
assert decimal_to_binary(4) == '100'
assert decimal_to_binary(5) == '101'
assert decimal_to_binary(6) == '110' 
# hidden tests

Representing negative numbers

The following also uses 3 bits to represent 8 integers but half of them are negative.

Table 3:Encoding positive integers

BinaryDecimal
0000
0011
0102
0113
100-4
101-3
110-2
111-1

What is the benefit of the above representation?

To subtract a positive binary number xx from another positive binary number yy, i.e.,

xy,x - y,

it seems we can instead perform the binary addition

x+(y)x + (-y)

of a positive binary number xx and a negative binary number y-y.

For example,

01123+10024=11121\overbrace{011_2}^{3} + \overbrace{100_2}^{-4} = \underbrace{111_2}_{-1}

It seem to work as well if there are bits carried forward, e.g., 1+(3)1 + (- 3) in binary is

0011+101110\begin{array}{rrrr} & 0 & \overset{\color{blue} 1}0 & 1 \\ + & 1 & 0 & 1 \\\hline & 1 & 1 & 0 \end{array}

which translate to -2 in decimal as desired.

YOUR ANSWER HERE

Logic Gates

A computer is built from transistors that operates on binary states on/off, which is also represented as bits 1/0, or the boolean value true/false. Play with the following simulator to see some examples.

Logic simulator

  1. Click the logic simulator header above.
  2. Select 1-Bit Full Adder.
  3. Change the input and observe the output.

Table 4 gives the input and output relationship of a simpler adder, called the half adder, which computes the addition of two input bits AA and BB as

A+B=CSA + B = C\circ S

where CC and SS are the output bits, and CSC\circ S is the concatenation of two bits CC and SS.

Table 4:Adder.

ABCS
0000
0101
1001
1110

The operation can be built using transistors, called logic gates, that can carry out basic logic operations such as

  • AANDBA \operatorname{AND} B: which returns 1 if and only if both AA and BB are 1, and 0 otherwise.
  • AXORBA \operatorname{XOR} B: which returns 1 if and only if either AA and BB are 1 but not both.

The input and output relationships are listed below:

from pandas import DataFrame

DataFrame(
    [[A, B, A & B, A ^ B] for A in (0, 1) for B in (0, 1)],
    columns=["A", "B", "A AND B", "A XOR B"],
)

YOUR ANSWER HERE

Glossary

algorithm
An algorithm is a set of instructions that a computer program follows to solve a problem or complete a task. It is a step-by-step approach designed to be efficient and accurate.
bitwise operator
Bitwise operators are used to manipulate individual bits of binary numbers. They allow for the manipulation of data at a low level, such as setting or clearing specific bits, shifting bits left or right, or performing logical operations on bits.
composite data type
A composite data type groups related data into a single unit so that they can be easily stored and manipulated together.
conditional
A conditional statement is used to perform different actions based on different conditions. It allows the program to make decisions and execute specific code blocks based on the evaluation of a given condition.
iteration
An iteration is a repeated execution until a condition is met. It allows for the efficient repetition of tasks without the need for writing the same code multiple times.
library
A library is a collection of pre-written code that developers can use to perform common tasks. It contains functions, classes, and other reusable code that can be integrated into a larger software application, saving time and effort.
pseudocode
Pseudocode is a high-level description of a program or algorithm, using natural language and code-like syntax to express logic without being bound to a specific programming language. It is used during planning and design phases of software development.
Footnotes
  1. The truth is, the random generation process will look random but is not truly random. You will learn about this pseudorandomness later in the course.