@Override
    public void paintObject(
        Graphics2D g2, State s, ObjectInstance ob, float cWidth, float cHeight) {

      float domainXScale = Sokoban2Domain.maxRoomXExtent(s) + 1f;
      float domainYScale = Sokoban2Domain.maxRoomYExtent(s) + 1f;

      if (maxX != -1) {
        domainXScale = maxX;
        domainYScale = maxY;
      }

      // determine then normalized width
      float width = (1.0f / domainXScale) * cWidth;
      float height = (1.0f / domainYScale) * cHeight;

      int x = ob.getIntValForAttribute(Sokoban2Domain.ATTX);
      int y = ob.getIntValForAttribute(Sokoban2Domain.ATTY);

      float rx = x * width;
      float ry = cHeight - height - y * height;

      String dir = null;
      Attribute dirAtt = ob.getObjectClass().getAttribute(Sokoban2Domain.ATTDIR);
      if (dirAtt != null) {
        dir = ob.getStringValForAttribute(Sokoban2Domain.ATTDIR);
      } else {
        dir = "south";
      }

      BufferedImage img = this.dirToImage.get(dir);
      g2.drawImage(img, (int) rx, (int) ry, (int) width, (int) height, this);
    }
    @Override
    public void paintObject(
        Graphics2D g2, State s, ObjectInstance ob, float cWidth, float cHeight) {

      float domainXScale = Sokoban2Domain.maxRoomXExtent(s) + 1f;
      float domainYScale = Sokoban2Domain.maxRoomYExtent(s) + 1f;

      if (maxX != -1) {
        domainXScale = maxX;
        domainYScale = maxY;
      }

      // determine then normalized width
      float width = (1.0f / domainXScale) * cWidth;
      float height = (1.0f / domainYScale) * cHeight;

      int top = ob.getIntValForAttribute(Sokoban2Domain.ATTTOP);
      int left = ob.getIntValForAttribute(Sokoban2Domain.ATTLEFT);
      int bottom = ob.getIntValForAttribute(Sokoban2Domain.ATTBOTTOM);
      int right = ob.getIntValForAttribute(Sokoban2Domain.ATTRIGHT);

      g2.setColor(Color.white);

      for (int i = left; i <= right; i++) {
        for (int j = bottom; j <= top; j++) {

          float rx = i * width;
          float ry = cHeight - height - j * height;
          g2.fill(new Rectangle2D.Float(rx, ry, width, height));
        }
      }
    }
    @Override
    public void paintObject(
        Graphics2D g2, State s, ObjectInstance ob, float cWidth, float cHeight) {

      g2.setColor(Color.darkGray);

      float domainXScale = Sokoban2Domain.maxRoomXExtent(s) + 1f;
      float domainYScale = Sokoban2Domain.maxRoomYExtent(s) + 1f;

      if (maxX != -1) {
        domainXScale = maxX;
        domainYScale = maxY;
      }

      // determine then normalized width
      float width = (1.0f / domainXScale) * cWidth;
      float height = (1.0f / domainYScale) * cHeight;

      int x = ob.getIntValForAttribute(Sokoban2Domain.ATTX);
      int y = ob.getIntValForAttribute(Sokoban2Domain.ATTY);

      float rx = x * width;
      float ry = cHeight - height - y * height;

      g2.fill(new Rectangle2D.Float(rx, ry, width, height));
    }
    @Override
    public void paintObject(
        Graphics2D g2, State s, ObjectInstance ob, float cWidth, float cHeight) {

      float domainXScale = Sokoban2Domain.maxRoomXExtent(s) + 1f;
      float domainYScale = Sokoban2Domain.maxRoomYExtent(s) + 1f;

      if (maxX != -1) {
        domainXScale = maxX;
        domainYScale = maxY;
      }

      // determine then normalized width
      float width = (1.0f / domainXScale) * cWidth;
      float height = (1.0f / domainYScale) * cHeight;

      int top = ob.getIntValForAttribute(Sokoban2Domain.ATTTOP);
      int left = ob.getIntValForAttribute(Sokoban2Domain.ATTLEFT);
      int bottom = ob.getIntValForAttribute(Sokoban2Domain.ATTBOTTOM);
      int right = ob.getIntValForAttribute(Sokoban2Domain.ATTRIGHT);

      Color rcol = colorForName(ob.getStringValForAttribute(Sokoban2Domain.ATTCOLOR));
      float[] hsb = new float[3];
      Color.RGBtoHSB(rcol.getRed(), rcol.getGreen(), rcol.getBlue(), hsb);
      hsb[1] = 0.4f;
      rcol = Color.getHSBColor(hsb[0], hsb[1], hsb[2]);

      for (int i = left; i <= right; i++) {
        for (int j = bottom; j <= top; j++) {

          float rx = i * width;
          float ry = cHeight - height - j * height;

          if (i == left || i == right || j == bottom || j == top) {
            if (Sokoban2Domain.doorContainingPoint(s, i, j) == null) {
              g2.setColor(Color.black);
              g2.fill(new Rectangle2D.Float(rx, ry, width, height));
            }
          } else {
            g2.setColor(rcol);
            g2.fill(new Rectangle2D.Float(rx, ry, width, height));
          }
        }
      }
    }
    @Override
    public void paintObject(
        Graphics2D g2, State s, ObjectInstance ob, float cWidth, float cHeight) {

      float domainXScale = Sokoban2Domain.maxRoomXExtent(s) + 1f;
      float domainYScale = Sokoban2Domain.maxRoomYExtent(s) + 1f;

      if (maxX != -1) {
        domainXScale = maxX;
        domainYScale = maxY;
      }

      // determine then normalized width
      float width = (1.0f / domainXScale) * cWidth;
      float height = (1.0f / domainYScale) * cHeight;

      int x = ob.getIntValForAttribute(Sokoban2Domain.ATTX);
      int y = ob.getIntValForAttribute(Sokoban2Domain.ATTY);

      float rx = x * width;
      float ry = cHeight - height - y * height;

      String colName = ob.getStringValForAttribute(Sokoban2Domain.ATTCOLOR);
      String shapeName = ob.getStringValForAttribute(Sokoban2Domain.ATTSHAPE);
      String key = this.shapeKey(shapeName, colName);
      BufferedImage img = this.shapeAndColToImages.get(key);

      if (img == null) {
        Color col = colorForName(ob.getStringValForAttribute(Sokoban2Domain.ATTCOLOR)).darker();

        g2.setColor(col);
        g2.fill(new Rectangle2D.Float(rx, ry, width, height));

      } else {
        g2.drawImage(img, (int) rx, (int) ry, (int) width, (int) height, this);
      }
    }