To solve this optimization problem, we need to define the decision variables and the objective function. Let's denote the number of easy questions solved as $x$ and the number of hard questions solved as $y$. The objective is to maximize the total points earned, which can be represented by the function $4x + 10y$.

The constraints given in the problem are:
1. Solve at least 4 easy questions: $x \geq 4$
2. Solve at least 2 hard questions: $y \geq 2$
3. Solve at most 12 easy questions: $x \leq 12$
4. Solve at most 4 hard questions: $y \leq 4$
5. Solve a maximum of 9 questions in total: $x + y \leq 9$

Since the problem involves maximizing a linear objective function subject to linear constraints, it can be formulated as a linear programming (LP) problem.

Here is how we can translate this into Gurobi code:

```python
from gurobipy import *

# Create a new model
m = Model("Exam_Questions")

# Define the decision variables
x = m.addVar(lb=4, ub=12, vtype=GRB.INTEGER, name="easy_questions")
y = m.addVar(lb=2, ub=4, vtype=GRB.INTEGER, name="hard_questions")

# Set the objective function to maximize points
m.setObjective(4*x + 10*y, GRB.MAXIMIZE)

# Add the constraint for the total number of questions
m.addConstr(x + y <= 9, "total_questions")

# Optimize the model
m.optimize()

# Print the results
if m.status == GRB.OPTIMAL:
    print("Optimal solution found:")
    print(f"Solve {x.x} easy questions")
    print(f"Solve {y.x} hard questions")
    print(f"Total points: {4*x.x + 10*y.x}")
else:
    print("No optimal solution found")
```