## Problem Description and Formulation

The hockey store wants to maximize its profit from selling hockey sticks and pucks. The store has a budget constraint of $20,000. The cost and profit of each item are as follows:

- Hockey stick: Cost = $75, Profit = $50
- Puck: Cost = $2, Profit = $5

The store owner estimates the following constraints:

- The number of hockey sticks sold per month is at least 50 but at most 110.
- The number of pucks sold is at most three times the number of hockey sticks sold.

## Mathematical Formulation

Let's denote:
- \(x\) as the number of hockey sticks sold,
- \(y\) as the number of pucks sold.

The objective function to maximize profit is:
\[ \text{Maximize:} \quad 50x + 5y \]

Subject to the constraints:
1. Budget constraint: \( 75x + 2y \leq 20000 \)
2. Hockey sticks sold constraint: \( 50 \leq x \leq 110 \)
3. Pucks sold constraint: \( y \leq 3x \)
4. Non-negativity constraint: \( x \geq 0, y \geq 0 \)

Since \(x\) and \(y\) represent the number of items, they are implicitly non-negative integers.

## Gurobi Code

```python
import gurobi

def hockey_store_optimization():
    # Create a new model
    model = gurobi.Model()

    # Define variables
    x = model.addVar(lb=50, ub=110, vtype=gurobi.GRB.INTEGER, name="Hockey_Sticks")
    y = model.addVar(vtype=gurobi.GRB.INTEGER, name="Pucks")

    # Objective function: Maximize profit
    model.setObjective(50 * x + 5 * y, gurobi.GRB.MAXIMIZE)

    # Budget constraint
    model.addConstr(75 * x + 2 * y <= 20000, name="Budget_Constraint")

    # Pucks sold constraint
    model.addConstr(y <= 3 * x, name="Pucks_Sold_Constraint")

    # Solve the model
    model.optimize()

    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal Solution: Hockey Sticks = {x.varValue}, Pucks = {y.varValue}")
        print(f"Max Profit: ${model.objVal}")
    else:
        print("The model is infeasible")

# Run the optimization
hockey_store_optimization()
```

This code defines the optimization problem using Gurobi's Python interface, solves it, and prints out the optimal solution if one exists. Note that the `vtype=gurobi.GRB.INTEGER` argument ensures that \(x\) and \(y\) are treated as integer variables, which is suitable for the number of items sold.