Python Strings
Intro - Tic-Tac-Toe Example
- This notebook teaches Python
strbasics.- Uses small examples drawn from the Tic-tac-toe notebooks in this repository.
- We use the board representation and display function from the existing Tic-tac-toe lesson to demonstrate how strings are used in a simple game context.
Sources referenced: _notebooks/Foundation/F-projects/2025-08-13-tic-tac-toe-code-lesson.ipynb and 2025-08-18-tictactoe-code.ipynb (display and win-check logic).
Key ideas about Python str
- Strings are immutable: once created, their contents can’t be changed (operations return new strings).
- Use
==to compare string contents (notis). - Common operations: concatenation (
+), repetition (*), slicing (s[1:3]),len(s),s.upper(),s.lower(),s.split(), ` .join(list)`. - A single character is also a string of length 1 in Python (there’s no distinct
chartype).
String basics (literals, escaping, indexing, slicing)
- Quotes: use single
'...'or double"..."quotes for strings. Triple quotes'''...'''or"""..."""are for multi-line strings. - Escape sequences:
\n(newline),\t(tab),\"and\'for embedded quotes; use raw stringsr'...'to avoid processing escapes (useful for file paths/regex). - Indexing:
s[0]is the first character,s[-1]is the last. - Slicing:
s[start:end](end is exclusive), e.g.s[:3],s[3:],s[::-1]reverses a string. - Strings are immutable: you cannot assign to
s[0]— operations return new strings instead. - Formatting: f-strings
f"{name} is {age}"andformat()are common for building strings.
Try the runnable examples in the next cell to see these concepts in action.
# String basics examples
a = 'hello'
b = "world"
print('a, b ->', a, b)
# multi-line and raw strings
multi = '''line1
line2'''
print('multi (repr) ->', repr(multi))
raw = r'C:\temp\newfile.txt'
print('raw ->', raw)
# indexing and slicing
print('a[0] ->', a[0])
print('a[-1] ->', a[-1])
print('a[1:4] ->', a[1:4])
# concatenation, repetition, and common methods
print('concat ->', a + ' ' + b)
print('repeat ->', a * 2)
print('upper ->', a.upper())
print('replace ->', a.replace('l','L'))
print('find ->', a.find('l'))
print('split ->', 'a,b,c'.split(','))
print('join ->', '-'.join(['a','b','c']))
# immutability demonstration
try:
a[0] = 'H'
except TypeError as e:
print('immutability error (expected):', e)
# formatting
name = 'Alice'; score = 42
print(f'{name} scored {score}')
print('format -> {}'.format(name))
# small exercise: build a one-line board string
board = [' ', 'X', 'O', ' ', 'X', ' ', 'O', ' ', ' ']
one_line = ''.join(board)
print('one_line ->', repr(one_line))
print('split back ->', list(one_line))
# 🔧 Mini-Challenge 1: Create and Explore the Board
# Create an empty board (9 empty spaces)
board = [" "] * 9
print("Our empty board list:") # Print a string
print(board)
print()
# Let's see what's at different positions
print("Position 0 (top-left):", repr(board[0]))
print("Position 4 (center):", repr(board[4]))
print("Position 8 (bottom-right):", repr(board[8]))
print()
# Now let's place some symbols and see what happens
board[0] = "X" # Top-left
board[4] = "O" # Center
board[8] = "X" # Bottom-right
print("After placing some symbols:")
print(board)
Our empty board list:
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
Position 0 (top-left): ' '
Position 4 (center): ' '
Position 8 (bottom-right): ' '
After placing some symbols:
['X', ' ', ' ', ' ', 'O', ' ', ' ', ' ', 'X']
Board as a list of strings
We represent the Tic-tac-toe board as board = [
] * 9 where each square is a string (empty string or a single-character mark like 'X' or 'O'). The repository’s Tic-tac-toe lesson uses a print_board function; we include it here exactly as used in the lesson so you can copy/run it.
# print_board function taken from the Tic-tac-toe lesson notebook
def print_board(board):
"""This function takes a board list and displays it as tic-tac-toe"""
print() # Empty line for spacing
print(f" {board[0]} | {board[1]} | {board[2]}")
print("---+---+---")
print(f" {board[3]} | {board[4]} | {board[5]}")
print("---+---+---")
print(f" {board[6]} | {board[7]} | {board[8]}")
print() # Empty line for spacing
# create a board and demonstrate placing moves
board = [' '] * 9
board[4] = 'X' # place X in the center
board[0] = 'O' # place O at top-left
print_board(board)
Useful string operations with game examples
We’ll demonstrate some common str operations and why they matter when handling board contents.
s = 'x'
print('original:', s)
print('upper ->', s.upper())
print('concat ->', s + ' and O')
print('repeat ->', s * 3)
# converting marks to a single string representation of the board
row = '|'.join(board[0:3])
print('row string ->', row)
# splitting back into list values (example)
parts = row.split('|')
print('parts ->', parts)
Checking wins (win patterns)
The Tic-tac-toe lesson uses a set of winning index patterns. The check below is adapted from the repository’s notebook and returns True when a player has three matching marks (non-empty) in any winning pattern.
win_patterns = [
[0,1,2], [3,4,5], [6,7,8], # rows
[0,3,6], [1,4,7], [2,5,8], # columns
[0,4,8], [2,4,6] # diagonals
]
def check_winner(board, symbol):
"""Return True if `symbol` (e.g. 'X') has a winning pattern on `board`.
This uses the same idea shown in the Tic-tac-toe lesson notebooks.
"""
for combo in win_patterns:
if all(board[i] == symbol for i in combo):
return True
return False
# quick check
b = ['X','X','X',' ',' ',' ',' ',' ',' ']
print('check_winner ->', check_winner(b, 'X')) # True
Finding a two-in-a-row (simple example)
To connect string handling to game heuristics, here is a small helper that finds an empty cell that would complete a player’s three-in-a-row (similar to patterns used in some Tic-tac-toe AI). This is a direct, minimal translation of the idea used in the JS implementation in the repository.
def find_best_move(board, player):
"""Return index of empty square that completes `player` to three-in-a-row, or -1 if none.
"""
for pattern in win_patterns:
line = [board[i] for i in pattern]
player_count = sum(1 for cell in line if cell == player)
empty_count = sum(1 for cell in line if cell == ' ')
if player_count == 2 and empty_count == 1:
empty_pos = pattern[line.index(' ')]
return empty_pos
return -1
# test the helper
test_board = ['X','X',' ',' ',' ',' ',' ',' ',' ']
print('find_best_move ->', find_best_move(test_board, 'X')) # Expect 2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 15
13 # test the helper
14 test_board = ['X','X',' ',' ',' ',' ',' ',' ',' ']
---> 15 print('find_best_move ->', find_best_move(test_board, 'X')) # Expect 2
Cell In[4], line 4, in find_best_move(board, player)
1 def find_best_move(board, player):
2 """Return index of empty square that completes `player` to three-in-a-row, or -1 if none.
3 """
----> 4 for pattern in win_patterns:
5 line = [board[i] for i in pattern]
6 player_count = sum(1 for cell in line if cell == player)
NameError: name 'win_patterns' is not defined
# full small demonstration putting it together
board_demo = [' ',' ',' ',' ',' ',' ',' ',' ',' ']
board_demo[0] = 'X'
board_demo[1] = 'X'
print_board(board_demo)
move = find_best_move(board_demo, 'X')
print('best move for X ->', move)
if move != -1:
board_demo[move] = 'X'
print_board(board_demo)
print('X wins?', check_winner(board_demo, 'X'))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[3], line 5
3 board_demo[0] = 'X'
4 board_demo[1] = 'X'
----> 5 print_board(board_demo)
6 move = find_best_move(board_demo, 'X')
7 print('best move for X ->', move)
NameError: name 'print_board' is not defined
Notes and next steps
- This lesson reuses display and win-check ideas directly from the repository’s Tic-tac-toe notebooks.
- Exercises: try using
''.join(board)to create a single-line board representation and then parse it back; try replacing string marks with single-charactercharequivalents in other languages — in Python a single character is also astr. - To expand this into a full program, add input handling and a game loop (the Tic-tac-toe notebooks in this repo show a complete game loop you can copy).
Beginner-friendly recap and helpers
Below are clearer, well-commented helper implementations for the key ideas shown in this lesson (win detection, finding a blocking/winning move, and safe move placement). These are written so beginners can read and understand every step — run the cell to make the helpers available and then run the quick checks that follow.
# Beginner-friendly helper implementations
win_patterns = [
[0,1,2], [3,4,5], [6,7,8], # rows
[0,3,6], [1,4,7], [2,5,8], # columns
[0,4,8], [2,4,6] # diagonals
]
def check_winner_simple(board, symbol):
"""Return True if `symbol` appears in any win pattern on `board`.
This beginner-friendly version loops explicitly so new learners can follow the logic.
"""
for combo in win_patterns:
a, b, c = combo # unpack the three indices
# Check each position in the pattern contains the symbol
if board[a] == symbol and board[b] == symbol and board[c] == symbol:
return True
return False
def find_best_move_simple(board, player):
"""Return index of empty square that completes `player` to three-in-a-row, or -1 if none.
This version builds the line values and counts occurrences in a readable way.
"""
for pattern in win_patterns:
line = [board[i] for i in pattern] # values at the three positions
# Count how many of the player's marks and how many empty spaces
player_count = sum(1 for cell in line if cell == player)
empty_count = sum(1 for cell in line if cell == ' ')
if player_count == 2 and empty_count == 1:
# find which position in the pattern is empty and return its board index
empty_pos_in_line = line.index(' ')
return pattern[empty_pos_in_line]
return -1
def make_move_simple(board, position, player):
"""Try to place player's mark at position (0-8). Return True if successful.
This function validates the position and ensures we don't overwrite an occupied square.
"""
# Validate position is an integer in the right range
if not isinstance(position, int):
return False
if position < 0 or position > 8:
return False
# Check if the square is empty (represented by a single space ' ')
if board[position] != ' ':
return False
# Place the player's symbol and return True
board[position] = player
return True
# Make these the default helpers for the rest of the notebook (simple names)
check_winner = check_winner_simple
find_best_move = find_best_move_simple
make_move = make_move_simple
print('Beginner-friendly helpers loaded: check_winner, find_best_move, make_move')
# Quick assertions to help beginners self-validate the functions
assert check_winner(['X','X','X',' ',' ',' ',' ',' ',' '], 'X') == True, 'check_winner failed for top row'
assert check_winner(['O',' ',' ','O',' ',' ','O',' ',' '], 'O') == True, 'check_winner failed for column'
assert check_winner(['X','O','X','O','X','O','O','X','O'], 'X') == False, 'check_winner false positive'
assert find_best_move(['X','X',' ',' ',' ',' ',' ',' ',' '], 'X') == 2, 'find_best_move should return 2'
assert find_best_move(['O',' ',' ','O',' ',' ','O',' ',' '], 'O') == 6, 'find_best_move should return 6'
assert find_best_move(['X','O','X','O','X','O','O','X','O'], 'X') == -1, 'find_best_move should return -1 when none'
b = [' ',' ',' ',' ',' ',' ',' ',' ',' ']
assert make_move(b, 4, 'X') == True and b[4] == 'X', 'make_move should place X at 4'
b2 = ['X',' ',' ',' ',' ',' ',' ',' ',' ']
assert make_move(b2, 0, 'O') == False and b2[0] == 'X', 'make_move should not overwrite'
print('All beginner checks passed — if you see this message you are ready to continue!')