To solve this problem, we first need to convert the natural language description into a symbolic representation. Let's denote the number of easy puzzles as $x_1$ and the number of hard puzzles as $x_2$. The objective is to maximize the total points earned from solving these puzzles.

The symbolic representation of the problem can be described as follows:
```json
{
    'sym_variables': [('x1', 'number of easy puzzles'), ('x2', 'number of hard puzzles')],
    'objective_function': '5*x1 + 8*x2',
    'constraints': ['x1 >= 3', 'x2 >= 1', 'x1 <= 10', 'x2 <= 5', 'x1 + x2 <= 10']
}
```
This representation captures the essence of the problem: we want to maximize the points earned from easy and hard puzzles, subject to the constraints on the minimum and maximum number of each type of puzzle that can be solved, as well as the overall limit on the total number of puzzles.

To solve this optimization problem using Gurobi in Python, we will use the following code:
```python
from gurobipy import *

# Create a model
m = Model("Puzzle Optimization")

# Define variables
x1 = m.addVar(lb=3, ub=10, vtype=GRB.INTEGER, name="easy_puzzles")
x2 = m.addVar(lb=1, ub=5, vtype=GRB.INTEGER, name="hard_puzzles")

# Set the objective function
m.setObjective(5*x1 + 8*x2, GRB.MAXIMIZE)

# Add constraints
m.addConstr(x1 + x2 <= 10, "total_puzzles")

# Optimize the model
m.optimize()

# Print the solution
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Easy puzzles: {x1.x}")
    print(f"Hard puzzles: {x2.x}")
    print(f"Total points: {5*x1.x + 8*x2.x}")
else:
    print("No optimal solution found")
```