You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
12 KiB
Markdown

# Know Foolery - Game Mechanics Documentation
## Overview
Know Foolery is a quiz game where players answer questions to earn points within a time-limited session. The game emphasizes strategic thinking through its hint system and attempt limitations.
## Core Game Flow
### 1. Game Session Initialization
```
Player Input: Name → Session Creation → Question Selection → Game Start
```
**Process:**
1. Player enters their name (required)
2. System creates new game session
3. System randomly selects first question
4. 30-minute timer starts
5. Game begins with question display
**Validation:**
- Player name: 2-50 characters, alphanumeric + spaces
- Session uniqueness: One active session per player
- Timer initialization: Server-side timestamp
### 2. Question Presentation
**Question Structure:**
```typescript
interface Question {
id: string
theme: string // e.g., "Geography", "History", "Science"
text: string // The actual question
answer: string // Correct answer (case-insensitive)
hint: string // Optional hint text
difficulty?: number // Future enhancement
}
```
**Display Format:**
```
┌─────────────────────────────────────┐
│ Theme: Geography ⏱️ 28:45 │
├─────────────────────────────────────┤
│ │
│ What is the capital of France? │
│ │
│ [Your answer here... ] 💡 │
│ │
│ Attempts remaining: 3/3 │
│ Current score: 4 points │
└─────────────────────────────────────┘
```
### 3. Answer Submission Process
**Player Actions:**
1. **Direct Answer**: Submit answer without hint
2. **Request Hint**: View hint before answering
3. **Skip Question**: Move to next question (future enhancement)
**Answer Validation:**
```go
// Server-side validation logic
func ValidateAnswer(userAnswer, correctAnswer string) bool {
// Normalize both answers
user := strings.ToLower(strings.TrimSpace(userAnswer))
correct := strings.ToLower(strings.TrimSpace(correctAnswer))
// Exact match
if user == correct {
return true
}
// Fuzzy matching (future enhancement)
similarity := calculateSimilarity(user, correct)
return similarity > 0.85
}
```
## Scoring System
### Point Values
- **Correct without hint**: 2 points
- **Correct with hint**: 1 point
- **Incorrect answer**: 0 points
- **Session timeout**: 0 points for remaining questions
### Scoring Logic
```go
type AttemptResult struct {
IsCorrect bool
UsedHint bool
AttemptNum int // 1, 2, or 3
}
func CalculateScore(result AttemptResult) int {
if !result.IsCorrect {
return 0
}
if result.UsedHint {
return 1 // Reduced score for using hint
}
return 2 // Full score for direct correct answer
}
```
### Score Tracking
```go
type GameSession struct {
PlayerName string
TotalScore int
QuestionsAsked int
QuestionsCorrect int
HintsUsed int
StartTime time.Time
EndTime *time.Time
IsActive bool
}
```
## Attempt System
### Attempt Rules
- **Maximum Attempts**: 3 per question
- **Attempt Tracking**: Server-side validation
- **Attempt Consequences**:
- Attempt 1-3: Normal scoring if correct
- After 3 failed attempts: Move to next question automatically
### Attempt Flow
```go
type QuestionAttempt struct {
SessionID string
QuestionID string
AttemptNum int // 1, 2, or 3
Answer string
IsCorrect bool
UsedHint bool
Timestamp time.Time
}
func ProcessAttempt(sessionID, questionID, answer string) AttemptResult {
// 1. Validate session is active
// 2. Check attempts remaining
// 3. Validate answer
// 4. Update score if correct
// 5. Move to next question if needed
}
```
## Hint System
### Hint Mechanics
- **Availability**: One hint per question
- **Timing**: Can be requested before any attempt
- **Impact**: Reduces maximum score from 2 to 1 points
- **Content**: Provides helpful clue without giving away answer
### Hint Implementation
```typescript
interface HintRequest {
sessionId: string
questionId: string
}
interface HintResponse {
hint: string
scoreImpact: string // "Using this hint will reduce your score to 1 point"
attemptsRemaining: number
}
```
### Hint Examples
```javascript
const hintExamples = {
question: "What is the capital of France?",
hint: "This city is famous for the Eiffel Tower and is located on the Seine River.",
question: "Who painted the Mona Lisa?",
hint: "This Italian Renaissance artist was also an inventor and scientist.",
question: "What is the largest planet in our solar system?",
hint: "This gas giant is named after the king of the Roman gods."
}
```
## Time Management
### Session Timer
- **Duration**: 30 minutes maximum per session
- **Display**: Real-time countdown timer
- **Warnings**: Visual alerts at 5 minutes and 1 minute remaining
- **Timeout**: Automatic session termination when time expires
### Timer Implementation
```go
type SessionTimer struct {
SessionID string
StartTime time.Time
Duration time.Duration // 30 minutes
WarningsSent map[int]bool // Track warnings sent
}
func (t *SessionTimer) TimeRemaining() time.Duration {
elapsed := time.Since(t.StartTime)
remaining := t.Duration - elapsed
if remaining < 0 {
return 0
}
return remaining
}
func (t *SessionTimer) IsExpired() bool {
return t.TimeRemaining() == 0
}
```
### Timer Events
```typescript
interface TimerEvent {
type: 'warning' | 'timeout'
timeRemaining: number // seconds
message: string
}
// Timer warnings
const timerWarnings = [
{ at: 300, message: "5 minutes remaining!" }, // 5 minutes
{ at: 60, message: "1 minute remaining!" }, // 1 minute
{ at: 10, message: "10 seconds left!" } // 10 seconds
]
```
## Question Selection
### Random Selection Algorithm
```go
func SelectRandomQuestion(sessionID string, excludeAnswered bool) (*Question, error) {
var questions []Question
query := db.Question.Query()
if excludeAnswered {
// Exclude questions already answered in this session
answeredIDs := getAnsweredQuestions(sessionID)
query = query.Where(question.IDNotIn(answeredIDs...))
}
questions, err := query.All(ctx)
if err != nil {
return nil, err
}
if len(questions) == 0 {
return nil, errors.New("no more questions available")
}
// Random selection
randomIndex := rand.Intn(len(questions))
return &questions[randomIndex], nil
}
```
### Question Difficulty (Future Enhancement)
```go
type DifficultyLevel int
const (
Easy DifficultyLevel = iota + 1
Medium
Hard
)
// Adaptive difficulty based on player performance
func SelectQuestionByDifficulty(sessionID string, targetDifficulty DifficultyLevel) (*Question, error) {
// Implementation for adaptive difficulty
// Consider player's success rate, current score, etc.
}
```
## Leaderboard System
### Leaderboard Calculation
```go
type LeaderboardEntry struct {
PlayerName string
Score int
QuestionsAnswered int
SuccessRate float64 // Percentage of correct answers
SessionDuration time.Duration
CompletedAt time.Time
}
func CalculateLeaderboard() ([]LeaderboardEntry, error) {
sessions := getCompletedSessions()
entries := make([]LeaderboardEntry, 0, len(sessions))
for _, session := range sessions {
entry := LeaderboardEntry{
PlayerName: session.PlayerName,
Score: session.TotalScore,
QuestionsAnswered: session.QuestionsAsked,
SuccessRate: float64(session.QuestionsCorrect) / float64(session.QuestionsAsked) * 100,
SessionDuration: session.EndTime.Sub(session.StartTime),
CompletedAt: *session.EndTime,
}
entries = append(entries, entry)
}
// Sort by score (descending), then by completion time (ascending)
sort.Slice(entries, func(i, j int) bool {
if entries[i].Score == entries[j].Score {
return entries[i].CompletedAt.Before(entries[j].CompletedAt)
}
return entries[i].Score > entries[j].Score
})
// Return top 10
if len(entries) > 10 {
entries = entries[:10]
}
return entries, nil
}
```
### Leaderboard Display
```
🏆 LEADERBOARD
Rank | Player | Score | Questions | Success Rate | Duration
-----|-----------|-------|-----------|--------------|----------
1 | Alice | 24 | 14 | 86% | 28m
2 | Bob | 22 | 13 | 85% | 25m
3 | Charlie | 20 | 12 | 83% | 30m
4 | Diana | 18 | 11 | 82% | 22m
5 | Eve | 16 | 10 | 80% | 27m
```
## Game State Management
### Session States
```go
type SessionState int
const (
SessionCreated SessionState = iota
SessionActive
SessionPaused // Future enhancement
SessionCompleted
SessionTimedOut
SessionAbandoned
)
type GameSession struct {
ID string
PlayerName string
State SessionState
CurrentQuestion *Question
Score int
// ... other fields
}
```
### State Transitions
```
Created → Active → {Completed, TimedOut, Abandoned}
Paused → Active (future enhancement)
```
## Anti-Cheating Measures
### Server-Side Validation
```go
type SecurityCheck struct {
SessionID string
QuestionID string
ExpectedAnswer string
SubmittedAnswer string
TimestampSubmit time.Time
TimestampShow time.Time
IsValid bool
Reason string
}
func ValidateSubmission(check SecurityCheck) bool {
// 1. Check minimum time between question show and answer submit
minTime := 2 * time.Second
if check.TimestampSubmit.Sub(check.TimestampShow) < minTime {
check.Reason = "Answer submitted too quickly"
return false
}
// 2. Validate session state
session := getSession(check.SessionID)
if session.State != SessionActive {
check.Reason = "Invalid session state"
return false
}
// 3. Check if question belongs to session
if session.CurrentQuestion.ID != check.QuestionID {
check.Reason = "Question mismatch"
return false
}
return true
}
```
### Client-Side Integrity
```typescript
// Prevent common cheating attempts
class GameIntegrity {
private questionStartTime: number = 0
onQuestionDisplayed() {
this.questionStartTime = Date.now()
// Disable browser dev tools (basic deterrent)
this.disableDevTools()
// Prevent copy-paste in answer input
this.disableCopyPaste()
}
onAnswerSubmit(answer: string) {
const timeTaken = Date.now() - this.questionStartTime
// Include timing in submission for server validation
return {
answer,
timeTaken,
timestamp: Date.now()
}
}
private disableDevTools() {
// Basic dev tools detection (not foolproof)
const devtools = {
open: false,
orientation: null
}
const threshold = 160
setInterval(() => {
if (window.outerHeight - window.innerHeight > threshold ||
window.outerWidth - window.innerWidth > threshold) {
console.warn('Developer tools detected')
// Log security event
}
}, 500)
}
}
```
## Future Enhancements
### Planned Features
1. **Question Categories**: Filter questions by subject
2. **Difficulty Progression**: Adaptive difficulty based on performance
3. **Multiplayer Mode**: Real-time competition between players
4. **Daily Challenges**: Special themed question sets
5. **Achievement System**: Badges and milestones
6. **Question Contributions**: Player-submitted questions
### Scoring Enhancements
1. **Time Bonus**: Extra points for quick correct answers
2. **Streak Bonus**: Consecutive correct answers bonus
3. **Difficulty Multiplier**: Higher points for harder questions
4. **Perfect Game Bonus**: Bonus for 100% correct rate
This game mechanics documentation ensures consistent implementation across all platforms and provides clear guidelines for future enhancements.