To solve this problem, we first need to define the decision variables and the objective function. Let's denote the number of type A layouts as $x_A$, the number of type B layouts as $x_B$, and the number of type C layouts as $x_C$. The objective is to maximize profit, which can be calculated based on the profits per layout type.

The profit for each type of layout is given:
- Type A: $200
- Type B: $175
- Type C: $225

We also have constraints based on the availability of rock, mulch, and grass:
- Rock: 10 units/type A + 5 units/type B + 12 units/type C ≤ 1200 units
- Mulch: 7 units/type A + 12 units/type B + 4 units/type C ≤ 700 units
- Grass: 15 units/type A + 10 units/type B + 12 units/type C ≤ 2000 units

Additionally, the number of layouts cannot be negative.

Now, let's translate this problem into Gurobi code in Python:

```python
from gurobipy import *

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

# Define decision variables
xA = m.addVar(name="Type_A", vtype=GRB.INTEGER, lb=0)
xB = m.addVar(name="Type_B", vtype=GRB.INTEGER, lb=0)
xC = m.addVar(name="Type_C", vtype=GRB.INTEGER, lb=0)

# Objective function: Maximize profit
m.setObjective(200 * xA + 175 * xB + 225 * xC, GRB.MAXIMIZE)

# Constraints
# Rock constraint
m.addConstr(10 * xA + 5 * xB + 12 * xC <= 1200, name="Rock_Constraint")

# Mulch constraint
m.addConstr(7 * xA + 12 * xB + 4 * xC <= 700, name="Mulch_Constraint")

# Grass constraint
m.addConstr(15 * xA + 10 * xB + 12 * xC <= 2000, name="Grass_Constraint")

# Optimize the model
m.optimize()

# Print results
if m.status == GRB.OPTIMAL:
    print(f"Optimal solution found.")
    print(f"Type A layouts: {xA.x}")
    print(f"Type B layouts: {xB.x}")
    print(f"Type C layouts: {xC.x}")
    print(f"Maximum profit: ${200 * xA.x + 175 * xB.x + 225 * xC.x:.2f}")
else:
    print("No optimal solution found.")
```