Skip to main content
Glama

analyze_difficulty

Analyze current level difficulty and characteristics to assess puzzle complexity and design quality for ice puzzle creation.

Instructions

Analyze current level difficulty and characteristics

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Complete implementation of the analyze_difficulty tool including registration, input schema, and handler. The handler analyzes difficulty by checking solvability, move count, mechanics used, direction balance, quadrants visited, dead ends, and calculates estimated difficulty rating (tutorial/easy/medium/hard/expert).
    {
      name: 'analyze_difficulty',
      description: 'Analyze the difficulty and characteristics of the current level',
      inputSchema: {
        type: 'object',
        properties: {}
      },
      handler: async () => {
        const error = checkActiveDraft();
        if (error) {
          return { content: [{ type: 'text', text: error }] };
        }
    
        const draft = draftStore.getCurrentDraft()!;
        const puzzleData = draftStore.exportPuzzleData();
        if (!puzzleData) {
          return { content: [{ type: 'text', text: 'Failed to export puzzle data' }] };
        }
    
        // Solve to get the solution
        const solverResult = solve(puzzleData);
    
        let output = `Difficulty Analysis\n${'='.repeat(50)}\n\n`;
    
        // Solvability
        output += `Solvable: ${solverResult.solvable ? '✓ Yes' : '❌ No'}\n`;
        if (!solverResult.solvable) {
          output += `\nCannot analyze unsolvable level.\n`;
          return { content: [{ type: 'text', text: output }] };
        }
    
        const moves = solverResult.moves!;
        const solution = solverResult.solution!;
    
        // Move count
        output += `Move count: ${moves}\n\n`;
    
        // Mechanics used
        const mechanics = detectMechanics(draft);
        output += `Mechanics used (${mechanics.length}):\n`;
        mechanics.forEach(m => output += `  • ${m}\n`);
        output += `\n`;
    
        // Direction balance
        const directionBalance: Record<Direction, number> = {
          up: 0,
          down: 0,
          left: 0,
          right: 0
        };
        solution.forEach(dir => {
          directionBalance[dir]++;
        });
    
        output += `Direction balance:\n`;
        output += `  Up:    ${directionBalance.up} (${Math.round(directionBalance.up / moves * 100)}%)\n`;
        output += `  Down:  ${directionBalance.down} (${Math.round(directionBalance.down / moves * 100)}%)\n`;
        output += `  Left:  ${directionBalance.left} (${Math.round(directionBalance.left / moves * 100)}%)\n`;
        output += `  Right: ${directionBalance.right} (${Math.round(directionBalance.right / moves * 100)}%)\n`;
        output += `\n`;
    
        // Quadrants visited
        const quadrants = new Set<number>();
        let pos = { ...draft.startPosition };
        quadrants.add(getQuadrant(pos.x, pos.y, draft.gridWidth, draft.gridHeight));
    
        for (const dir of solution) {
          const result = slideWithHazards(pos, dir, puzzleData, [], [], false);
          pos = result.position;
          quadrants.add(getQuadrant(pos.x, pos.y, draft.gridWidth, draft.gridHeight));
        }
    
        output += `Quadrants visited: ${Array.from(quadrants).sort().join(', ')} (${quadrants.size}/4)\n`;
        output += `\n`;
    
        // Dead ends
        const deadEndCount = countDeadEnds(draft, puzzleData);
        output += `Dead ends (3+ blocked directions): ${deadEndCount}\n`;
        output += `\n`;
    
        // Estimated difficulty
        let difficulty: 'tutorial' | 'easy' | 'medium' | 'hard' | 'expert';
        if (moves <= 6) difficulty = 'tutorial';
        else if (moves <= 12) difficulty = 'easy';
        else if (moves <= 17) difficulty = 'medium';
        else if (moves <= 24) difficulty = 'hard';
        else difficulty = 'expert';
    
        // Adjust based on mechanics
        if (mechanics.length >= 3 && difficulty === 'easy') difficulty = 'medium';
        if (mechanics.length >= 4 && difficulty === 'medium') difficulty = 'hard';
    
        output += `Estimated difficulty: ${difficulty.toUpperCase()}\n`;
        output += `  (tutorial: 2-6 moves, easy: 6-12, medium: 10-17, hard: 14-24, expert: 18+)\n`;
    
        return { content: [{ type: 'text', text: output }] };
      }
    }
  • Input schema definition for analyze_difficulty tool - empty object since it requires no parameters.
    inputSchema: {
      type: 'object',
      properties: {}
    },
  • Core handler logic for analyze_difficulty: runs solver to get optimal solution, calculates metrics (moves, mechanics, directions, quadrants, dead ends), and estimates difficulty level based on move count and mechanics complexity.
    handler: async () => {
      const error = checkActiveDraft();
      if (error) {
        return { content: [{ type: 'text', text: error }] };
      }
    
      const draft = draftStore.getCurrentDraft()!;
      const puzzleData = draftStore.exportPuzzleData();
      if (!puzzleData) {
        return { content: [{ type: 'text', text: 'Failed to export puzzle data' }] };
      }
    
      // Solve to get the solution
      const solverResult = solve(puzzleData);
    
      let output = `Difficulty Analysis\n${'='.repeat(50)}\n\n`;
    
      // Solvability
      output += `Solvable: ${solverResult.solvable ? '✓ Yes' : '❌ No'}\n`;
      if (!solverResult.solvable) {
        output += `\nCannot analyze unsolvable level.\n`;
        return { content: [{ type: 'text', text: output }] };
      }
    
      const moves = solverResult.moves!;
      const solution = solverResult.solution!;
    
      // Move count
      output += `Move count: ${moves}\n\n`;
    
      // Mechanics used
      const mechanics = detectMechanics(draft);
      output += `Mechanics used (${mechanics.length}):\n`;
      mechanics.forEach(m => output += `  • ${m}\n`);
      output += `\n`;
    
      // Direction balance
      const directionBalance: Record<Direction, number> = {
        up: 0,
        down: 0,
        left: 0,
        right: 0
      };
      solution.forEach(dir => {
        directionBalance[dir]++;
      });
    
      output += `Direction balance:\n`;
      output += `  Up:    ${directionBalance.up} (${Math.round(directionBalance.up / moves * 100)}%)\n`;
      output += `  Down:  ${directionBalance.down} (${Math.round(directionBalance.down / moves * 100)}%)\n`;
      output += `  Left:  ${directionBalance.left} (${Math.round(directionBalance.left / moves * 100)}%)\n`;
      output += `  Right: ${directionBalance.right} (${Math.round(directionBalance.right / moves * 100)}%)\n`;
      output += `\n`;
    
      // Quadrants visited
      const quadrants = new Set<number>();
      let pos = { ...draft.startPosition };
      quadrants.add(getQuadrant(pos.x, pos.y, draft.gridWidth, draft.gridHeight));
    
      for (const dir of solution) {
        const result = slideWithHazards(pos, dir, puzzleData, [], [], false);
        pos = result.position;
        quadrants.add(getQuadrant(pos.x, pos.y, draft.gridWidth, draft.gridHeight));
      }
    
      output += `Quadrants visited: ${Array.from(quadrants).sort().join(', ')} (${quadrants.size}/4)\n`;
      output += `\n`;
    
      // Dead ends
      const deadEndCount = countDeadEnds(draft, puzzleData);
      output += `Dead ends (3+ blocked directions): ${deadEndCount}\n`;
      output += `\n`;
    
      // Estimated difficulty
      let difficulty: 'tutorial' | 'easy' | 'medium' | 'hard' | 'expert';
      if (moves <= 6) difficulty = 'tutorial';
      else if (moves <= 12) difficulty = 'easy';
      else if (moves <= 17) difficulty = 'medium';
      else if (moves <= 24) difficulty = 'hard';
      else difficulty = 'expert';
    
      // Adjust based on mechanics
      if (mechanics.length >= 3 && difficulty === 'easy') difficulty = 'medium';
      if (mechanics.length >= 4 && difficulty === 'medium') difficulty = 'hard';
    
      output += `Estimated difficulty: ${difficulty.toUpperCase()}\n`;
      output += `  (tutorial: 2-6 moves, easy: 6-12, medium: 10-17, hard: 14-24, expert: 18+)\n`;
    
      return { content: [{ type: 'text', text: output }] };
    }
  • Helper function detectMechanics() - scans the draft for level mechanics including lava, hot_coals, thin_ice, pushable_rocks, warps, and pressure_plate_barrier combinations.
    function detectMechanics(draft: any): string[] {
      const mechanics: string[] = [];
    
      // Check obstacles
      const hasLava = draft.obstacles.some((o: any) => o.type === 'lava');
      const hasHotCoals = draft.obstacles.some((o: any) => o.type === 'hot_coals' || o.type === 'spike');
    
      if (hasLava) mechanics.push('lava');
      if (hasHotCoals) mechanics.push('hot_coals');
    
      // Check special elements
      if (draft.thinIceTiles && draft.thinIceTiles.length > 0) {
        mechanics.push('thin_ice');
      }
      if (draft.pushableRocks && draft.pushableRocks.length > 0) {
        mechanics.push('pushable_rocks');
      }
      if (draft.warpPairs && draft.warpPairs.length > 0) {
        mechanics.push('warps');
      }
      if (draft.pressurePlate && draft.barrier) {
        mechanics.push('pressure_plate_barrier');
      }
    
      return mechanics;
    }
  • Helper function countDeadEnds() - counts tiles with 3+ blocked directions to identify dead ends in the puzzle layout.
    function countDeadEnds(draft: any, puzzleData: any): number {
      let deadEndCount = 0;
    
      for (let y = 0; y < draft.gridHeight; y++) {
        for (let x = 0; x < draft.gridWidth; x++) {
          const pos = { x, y };
    
          // Skip if there's an obstacle here
          const hasObstacle = puzzleData.obstacles.some((o: any) => o.x === x && o.y === y);
          if (hasObstacle) continue;
    
          // Count how many directions lead to walls or hazards
          let blockedDirections = 0;
    
          for (const dir of ALL_DIRECTIONS) {
            const result = slideWithHazards(pos, dir, puzzleData, [], [], false);
    
            // Consider blocked if we didn't move or hit something deadly immediately
            if ((result.position.x === x && result.position.y === y) ||
                result.hitLava ||
                (result.hitBarrier && !result.crossedPressurePlate)) {
              blockedDirections++;
            }
          }
    
          if (blockedDirections >= 3) {
            deadEndCount++;
          }
        }
      }
    
      return deadEndCount;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It mentions analysis but doesn't disclose behavioral traits such as whether this is a read-only operation, if it requires a level to be loaded, what the output format might be, or any performance considerations. This leaves significant gaps for an agent to understand how to use it effectively.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's purpose without unnecessary words. It's appropriately sized for a zero-parameter tool and front-loaded with the core action.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of analyzing 'difficulty and characteristics' with no annotations, no output schema, and vague purpose, the description is incomplete. It doesn't explain what the analysis entails, what metrics are used, or how results are returned, making it inadequate for an agent to leverage this tool fully.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0 parameters and 100% schema description coverage, the baseline is high. The description implies the tool operates on a 'current level' context, which adds semantic meaning beyond the empty schema, suggesting it might rely on an implicit state rather than explicit inputs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Analyze current level difficulty and characteristics' states a clear verb ('Analyze') and resource ('current level'), but is vague about what constitutes 'difficulty and characteristics' and doesn't differentiate from sibling tools like 'get_level_requirements' or 'validate_quality_gate' that might provide related information. It's functional but lacks specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives. With siblings like 'get_level_requirements' and 'validate_quality_gate', the description doesn't indicate if this is for real-time analysis, post-creation evaluation, or comparison purposes, leaving usage context unclear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wmoten/ice-puzzle-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server