@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 paintStatePolicy(Graphics2D g2, State s, Policy policy, float cWidth, float cHeight) {
    ObjectInstance xOb = this.xObjectInstance(s);
    ObjectInstance yOb = this.yObjectInstance(s);

    Attribute xAtt = xOb.getObjectClass().getAttribute(xAttName);
    Attribute yAtt = yOb.getObjectClass().getAttribute(yAttName);

    float domainXScale = 0f;
    float domainYScale = 0f;
    float xval = 0f;
    float yval = 0f;
    float width = 0f;
    float height = 0f;

    if (xAtt.type == Attribute.AttributeType.DISC) {

      if (this.numXCells != -1) {
        domainXScale = this.numXCells;
      } else {
        domainXScale = xAtt.discValues.size();
      }

      width = cWidth / domainXScale;
      xval = xOb.getDiscValForAttribute(xAttName) * width;
    }

    if (yAtt.type == Attribute.AttributeType.DISC) {

      if (this.numYCells != -1) {
        domainYScale = this.numYCells;
      } else {
        domainYScale = yAtt.discValues.size();
      }

      height = cHeight / domainYScale;
      yval = cHeight - height - yOb.getDiscValForAttribute(yAttName) * height;
    }

    List<ActionProb> pdist = policy.getActionDistributionForState(s);
    double maxp = 0.;
    for (ActionProb ap : pdist) {
      if (ap.pSelection > maxp) {
        maxp = ap.pSelection;
      }
    }

    if (true) {
      if (this.renderStyle == PolicyGlyphRenderStyle.MAXACTIONSOFTTIE) {
        maxp -= this.softTieDelta;
      }

      for (ActionProb ap : pdist) {
        if (ap.pSelection >= maxp) {
          ActionGlyphPainter agp = this.actionNameToGlyphPainter.get(ap.ga.actionName());
          if (agp != null) {
            agp.paintGlyph(g2, xval, yval, width, height);
          }
        }
      }

    } else {
      for (ActionProb ap : pdist) {
        float[] scaledRect =
            this.rescaleRect(xval, yval, width, height, (float) (ap.pSelection / maxp));
        ActionGlyphPainter agp = this.actionNameToGlyphPainter.get(ap.ga.actionName());
        if (agp != null) {
          agp.paintGlyph(g2, scaledRect[0], scaledRect[1], scaledRect[2], scaledRect[3]);
        }
      }
    }
  }