Mastering Python: Day 26 – Memory Forge

Click on the “Python Beginner to Advanced” public account, select “Star

Essential content delivered promptly

[For reprints, please message the author]

Q: What’s the best way to learn to code?

A: Code daily! Welcome here!

First, welcome to the Python Mastery Program, I hope this is not just a challenge for you, but also a meaningful journey, and I wish you fruitful results. Have a pleasant journey.

Mastering Python: Day 26 - Memory Forge

Forging the Temple of Memory | Refining the Elixir of Knowledge

🌟Review of Previous Sessions

In the training of Day 25, we learned:

Secure architecture of password managers

Core algorithms for encrypted storage

Advanced data presentation with Treeview

For those who missed the treasure chest of keys, pleaseclick to review[1]

🚀Core Objectives for This Session

Through this lesson, you will:

  1. Implement a card flip animation effect

  2. Master the principles of spaced repetition algorithms

  3. Develop an intelligent memory management system

  4. Generate visual reports of learning progress

1. Card Forging Technique (First Reshaping)

1.1 Dynamic Cards with Canvas

class FlashCard(tk.Canvas):
    def __init__(self, master, front_text, back_text):
        super().__init__(master, width=300, height=200, bg='white')
        self.front_text = front_text
        self.back_text = back_text
        self.is_front = True
        # Draw initial front
        self.create_rectangle(5,5,295,195, outline='#4B8BBE', width=2)
        self.text = self.create_text(150, 100, text=front_text,
                                   font=('微软雅黑', 14), width=280)
        self.bind("<Button-1>", self.flip)
    def flip(self, event=None):
        """Card flip animation"""
        for i in range(0, 90, 5):
            self.configure(width=300*(1-abs(i-45)/45))
            self.update()
            self.master.after(20)
        self.delete("all")
        new_text = self.back_text if self.is_front else self.front_text
        self.create_rectangle(5,5,295,195, outline='#4B8BBE', width=2)
        self.create_text(150, 100, text=new_text,
                        font=('微软雅黑', 14), width=280)
        self.is_front = not self.is_front

2. Core Memory Algorithm (Second Infusion)

2.1 SM-2 Spaced Repetition Algorithm

from datetime import datetime, timedelta
class SpacedRepetition:
    def __init__(self):
        self.quality_map = {
            0: (0.0, 1.3),  # Incorrect
            1: (0.4, 1.3),  # Difficult
            2: (0.6, 1.5),  # Average
            3: (1.0, 2.0)   # Easy
        }
    def update_card(self, card, quality):
        """Update card memory parameters"""
        if quality < 0 or quality > 3:
            raise ValueError("Quality rating must be between 0-3")
        ease_factor = card.ease_factor
        interval = card.interval
        # Calculate new parameters
        ease_delta, interval_mod = self.quality_map[quality]
        new_ease = max(1.3, ease_factor + ease_delta)
        new_interval = interval * new_ease * interval_mod
        # Update card
        card.interval = int(round(new_interval))
        card.ease_factor = new_ease
        card.next_review = datetime.now() + timedelta(days=card.interval)

3. System Integration (Third Fusion)

3.1 Main Interface Architecture

class FlashCardApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Memory Forge v1.0")
        self.deck = self.load_deck()
        self.current_card = None
        # Control panel
        control_frame = ttk.Frame(self)
        control_frame.pack(pady=10)
        ttk.Button(control_frame, text="Remember", command=lambda: self.rate_card(3)).pack(side='left', padx=5)
        ttk.Button(control_frame, text="Vague", command=lambda: self.rate_card(2)).pack(side='left', padx=5)
        ttk.Button(control_frame, text="Forget", command=lambda: self.rate_card(0)).pack(side='left', padx=5)
        # Progress chart
        self.figure = Figure(figsize=(5,3))
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.canvas.get_tk_widget().pack()
        self.show_next_card()
    def show_next_card(self):
        """Display the next card to review"""
        due_cards = [c for c in self.deck if c.next_review <= datetime.now()]
        if due_cards:
            self.current_card = due_cards[0]
            FlashCard(self, self.current_card.front, self.current_card.back).pack(pady=20)
        else:
            tk.messagebox.showinfo("Complete", "Today's review is finished!")

4. Complete Code (Mastery Achieved)

"""Memory Card Spaced Repetition System - Memory Forge v1.2
Author: This Traveler
Function Description:
1. A graphical interface application built with tkinter
2. Supports card front and back flip animation effects
3. Implements an improved spaced repetition algorithm based on SM-2
4. Memory curve visualization function
5. Automatic save/load learning progress"""
# Import necessary libraries
import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime, timedelta
import json
import os
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class FlashCard(tk.Canvas):
    """Flippable memory card component"""
    def __init__(self, master, front_text, back_text, **kwargs):
        """
        Initialize memory card
        :param master: Parent container
        :param front_text: Front text content
        :param back_text: Back text content
        """
        super().__init__(master, width=300, height=200, bg='white', **kwargs)
        self.front_text = front_text  # Card front content
        self.back_text = back_text    # Card back content
        self.is_front = True         # Current display is front
        # Initialize drawing card front
        self.draw_card(self.front_text)
        # Bind click event
        self.bind("<Button-1>", self.flip)
    def draw_card(self, text):
        """Draw card content"""
        self.delete("all")  # Clear canvas
        # Draw blue border
        self.create_rectangle(5, 5, 295, 195, outline='#4B8BBE', width=2)
        # Add text content (supports automatic line wrapping)
        self.create_text(150, 100, text=text,
                         font=('微软雅黑', 14), width=280, tags="text")
    def flip(self, event=None):
        """Execute card flip animation"""
        # Use width change to simulate 3D flip effect
        for i in range(0, 90, 5):
            self.configure(width=300*(1-abs(i-45)/45))  # Dynamically adjust width
            self.update()
            self.master.after(20)  # Control animation speed
        # Switch display content
        new_text = self.back_text if self.is_front else self.front_text
        self.is_front = not self.is_front  # Switch front and back state
        self.draw_card(new_text)
class Card:
    """Memory card data model"""
    def __init__(self, front, back):
        """
        Initialize card data
        :param front: Front content
        :param back: Back content
        """
        self.front = front            # Card front question
        self.back = back              # Card back answer
        self.interval = 1            # Current review interval (days)
        self.ease_factor = 2.5        # Ease factor (for adjusting interval)
        self.next_review = datetime.now()  # Next review time
        self.review_count = 0        # Total review count
        self.history = []             # Review history record (date, rating)
class SpacedRepetition:
    """Spaced repetition scheduling algorithm (based on improved SM-2)"""
    def update_card(self, card, quality):
        """
        Update card memory parameters
        :param card: Card object to update
        :param quality: User rating (0-3)
        """
        # Rating corresponding parameter mapping table (ease adjustment value, interval adjustment coefficient)
        quality_map = {
            0: (0.0, 0.8),   # Forget
            1: (0.4, 0.9),   # Difficult
            2: (0.6, 1.1),   # Average
            3: (1.0, 1.3)    # Easy
        }
        # Get adjustment parameters
        ease_delta, interval_mod = quality_map.get(quality, (0, 1))
        # Adjust ease factor (minimum 1.3)
        card.ease_factor = max(1.3, card.ease_factor + ease_delta)
        # Calculate new interval (rounded)
        card.interval = int(round(card.interval * card.ease_factor * interval_mod))
        # Set next review time
        card.next_review = datetime.now() + timedelta(days=card.interval)
        card.review_count += 1  # Increase review count
        # Record review history
        card.history.append((datetime.now().strftime("%Y-%m-%d"), quality))
class FlashCardApp(tk.Tk):
    """Main application"""
    def __init__(self):
        super().__init__()
        # Basic window settings
        self.title("Memory Forge v1.2")
        self.geometry("600x800")
        self.scheduler = SpacedRepetition()  # Initialize scheduler
        self.deck = self.load_deck()        # Load card data
        self.current_card = None           # Currently displayed card
        # Initialize interface
        self.create_widgets()
        self.show_next_card()  # Display the first card
        # Set close event handling
        self.protocol("WM_DELETE_WINDOW", self.on_close)
    def create_widgets(self):
        """Create interface components"""
        # Control button panel
        control_frame = ttk.Frame(self)
        control_frame.pack(pady=10, fill='x')
        # Define rating button configuration
        buttons = [
            ("Forget (0)", 0, '#FF6B6B'),    # Red
            ("Difficult (1)", 1, '#FFD93D'),    # Yellow
            ("Average (2)", 2, '#6C5CE7'),    # Purple
            ("Remember (3)", 3, '#00B894')     # Green
        ]
        # Create and arrange rating buttons
        for text, q, color in buttons:
            btn = ttk.Button(
                control_frame,
                text=text,
                command=lambda q=q: self.rate_card(q),
                style=f'{color}.TButton'
            )
            btn.pack(side='left', padx=5, expand=True)
        # Card display area
        self.card_frame = ttk.Frame(self)
        self.card_frame.pack(pady=20, fill='both', expand=True)
        # Initialize statistics chart
        self.figure = Figure(figsize=(5, 3), dpi=100)
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.canvas.get_tk_widget().pack(fill='both', expand=True)
        # Configure button styles
        self.style = ttk.Style()
        self.style.configure('TButton', font=('微软雅黑', 10))
        # Set colors for different buttons
        for color in ['#FF6B6B', '#FFD93D', '#6C5CE7', '#00B894']:
            self.style.configure(f'{color}.TButton', foreground='white', background=color)
    def load_deck(self):
        """Load card data"""
        # Default card data (used when file does not exist)
        default_cards = [
            {"front": "What is Python's GIL?", "back": "Global Interpreter Lock"},
            {"front": "What is the purpose of @staticmethod?", "back": "Declare a static method that does not require an instance parameter"}
        ]
        try:
            # Attempt to load data from JSON file
            with open('flashcards.json', 'r', encoding='utf-8') as f:
                data = json.load(f)
                return [Card(**item) for item in data]
        except FileNotFoundError:
            # Use default cards when file does not exist
            return [Card(**item) for item in default_cards]
    def save_deck(self):
        """Save card data to JSON file"""
        data = []
        for card in self.deck:
            data.append({
                "front": card.front,
                "back": card.back,
                "interval": card.interval,
                "ease_factor": card.ease_factor,
                "next_review": card.next_review.strftime("%Y-%m-%d %H:%M:%S"),
                "review_count": card.review_count,
                "history": card.history
            })
        # Write to JSON file
        with open('flashcards.json', 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    def show_next_card(self):
        """Display the next card to review"""
        # Clear current card display area
        for widget in self.card_frame.winfo_children():
            widget.destroy()
        # Filter cards that need to be reviewed (next review time has arrived)
        due_cards = [c for c in self.deck if datetime.now() > c.next_review]
        if due_cards:
            self.current_card = due_cards[0]
            # Create and display card component
            FlashCard(self.card_frame, self.current_card.front, self.current_card.back).pack()
            self.update_chart()  # Update statistics chart
        else:
            self.update_chart()
            messagebox.showinfo("Complete", "All cards have been reviewed today!")
    def rate_card(self, quality):
        """Process user rating"""
        if self.current_card:
            self.scheduler.update_card(self.current_card, quality)
            self.show_next_card()
    def update_chart(self):
        """Update memory curve chart"""
        self.ax.clear()  # Clear old chart
        # Collect all cards' historical data
        dates = []
        intervals = []
        for card in self.deck:
            if card.history:
                # Get the most recent review date
                last_date = datetime.strptime(card.history[-1][0], "%Y-%m-%d")
                dates.append(last_date)
                intervals.append(card.interval)
        # Draw scatter plot
        if dates and intervals:
            self.ax.scatter(dates, intervals, c='#6C5CE7', alpha=0.7)
            self.ax.set_title("Memory Interval Trend")
            self.ax.set_ylabel("Next Review Interval (days)")
            self.ax.grid(True)
            self.figure.autofmt_xdate()  # Automatically adjust date format
            self.canvas.draw()  # Redraw canvas
    def on_close(self):
        """Handle window close event"""
        self.save_deck()  # Save data
        self.destroy()
if __name__ == "__main__":
    app = FlashCardApp()
    app.mainloop()

Guidelines to Avoid Pitfalls

  1. Animation Lag Optimization

# Incorrect approach (directly in the main thread loop)
for i in range(100):
    update_animation()
    time.sleep(0.1)  # Will cause the interface to freeze
# Correct approach (using after method)
def animate(frame=0):
    if frame < 90:
        update_frame(frame)
        self.after(20, animate, frame+1)
animate()
  1. Timezone Handling Standards

# Incorrect approach (using naive time)
datetime.now()  # May cause timezone confusion
# Correct approach (specifying timezone)
from datetime import timezone
datetime.now(timezone.utc).astimezone()  # Get local timezone time

🔮Next Session Preview

Day 27: Time Sword – Date Management and Email Automation

Advanced techniques of the datetime module

Implementation of scheduled tasks

Sending encrypted emails with smtplib

Automatically generating daily reports

Core function preview:

# Email sending example
import smtplib
from email.mime.text import MIMEText
def send_email(subject, content):
    msg = MIMEText(content, 'html')
    msg['Subject'] = subject
    msg['From'] = 'Daily Report <[email protected]>'
    msg['To'] = '[email protected]'
    with smtplib.SMTP_SSL('smtp.example.com', 465) as server:
        server.login('user', 'password')
        server.send_message(msg)

💬Practice Room

Share in the comments:

  1. What knowledge area do you want to memorize the most?

  2. Special animation effects for the designed flashcards. The top 3 liked will receive the “SuperMemo Memory Algorithm White Paper” + “Python Automation Secrets” e-books.

🚀Memory is eternal, the path remains forever

Click “♥” to mark your progress, and tomorrow at noon we will jointly wield the Time Sword!

#Previous Recommendations

Day 25: Treasure Chest of Keys – Password Management[2]

Day 24: Interface Mastery – Advanced Tkinter[3]

References

[1]

Click to review: Python Mastery Day 25: Treasure Chest of Keys – Practical Password Manager with Tkinter

[2]

Day 25: Treasure Chest of Keys – Password Management

[3]

Day 24: Interface Mastery – Advanced Tkinter

Complete Code:

https://github.com/Zesheng-Wang/100-days-python

Mastering Python: Day 26 - Memory Forge

Errata:

As I am not a seasoned programming expert, despite striving for accuracy while creating this content and consulting numerous resources, there may still be oversights. If you find any errors, please leave a message in the public account, and corrections are welcome.

You should secretly learn Python and amaze everyone.

Mastering Python: Day 26 - Memory Forge

Mastering Python: Day 26 - Memory Forge

-END-

Thank you all for your attention

Everything you care about is here

Mastering Python: Day 26 - Memory Forge

Leave a Comment