Drawing boxes

Hello, Community!

Here's an interesting task I found on the Internet.

Problem description

Write a method that would draw a box of a specified size.

The goal is to write the shortest method.

Here's a method signature (it can't be modified):

ClassMethod main(s As %Integer = 10)

And call sample:

>do ##class(ITPlanet.Task4).main(5)
#####
## ##
# # #
## ##
#####

>do ##class(ITPlanet.Task4).main(10)
##########
##      ##
# #    # #
#  #  #  #
#   ##   #
#   ##   #
#  #  #  #
# #    # #
##      ##
##########
 
>do ##class(ITPlanet.Task4).main(20)
####################
##                ##
# #              # #
#  #            #  #
#   #          #   #
#    #        #    #
#     #      #     #
#      #    #      #
#       #  #       #
#        ##        #
#        ##        #
#       #  #       #
#      #    #      #
#     #      #     #
#    #        #    #
#   #          #   #
#  #            #  #
# #              # #
##                ##
####################

Also, here's the code to  check your result length:

ClassMethod length(class = {$classname()}, method = "main") As %Integer
{
    #dim methodObj As %Dictionary.MethodDefinition
    set methodObj = ##class(%Dictionary.MethodDefinition).IDKEYOpen(class, method)
    quit methodObj.Implementation.Size
}

My best result is 91 76 so far.

What's yours? ;)

  • + 2
  • 0
  • 322
  • 10
  • 7

Answers

My best result is 77 72 69 67 so far.

Class ITPlanet.Task4 Abstract ]
{

ClassMethod main(As %Integer 10)
{
 x=1:1:y=1:1:w $c(y#s<2!$lf($lb(1,s,y,s-y+1),x)*3+32)
}

ClassMethod length(
  class = {$classname()},
  method "main"As %Integer CodeMode = expression ]
{
##class(%Dictionary.MethodDefinition).IDKEYOpen(classmethod).Implementation.Size
}

}

USER>##class(ITPlanet.Task4).length()
67
USER>##class(ITPlanet.Task4).main(11)

###########
##       ##
# #     # #
#  #   #  #
#   # #   #
#    #    #
#   # #   #
#  #   #  #
# #     # #
##       ##
###########

Sorry to be late. I was busy today:

Thanks to  @Eduard Lebedyuk

I did it in a traditional one-liner: 79  77 char.   + 4 char extra to read the size.

I'll wrap it into a method later to see how much waste of space this generates. devil

5 min. later:
OK. Method consumes 3 char. extra {} to enclose it + blank at the start   =>>> 82   80  ~3.9% overhead

s=1...4 looks odd but it improves.

f j=1:1:15 zw j d ##class(DC.size).main(j) 

j=1
#
j=2
##
##
j=3
###
###
###
j=4
####
####
####
####
j=5
#####
## ##
# # #
## ##
#####
j=6
######
##  ##
# ## #
# ## #
##  ##
######
j=7
#######
##   ##
# # # #
#  #  #
# # # #
##   ##
#######
j=8
########
##    ##
# #  # #
#  ##  #
#  ##  #
# #  # #
##    ##
########

It's short!
I assume it will be published after the competition.
keep patient. And try it too wink 

That's mine:

ClassMethod main(As %Integer = 10)
r=1:1:! c=1:1:$s(c=1!(r=1)!(r=s)!(c=s)!(c=r)!(s-r+1=c):"#",1:" ")}

FOO>d ##class(FOO.Boxes).main(20)
 
####################
##                ##
# #              # #
#  #            #  #
#   #          #   #
#    #        #    #
#     #      #     #
#      #    #      #
#       #  #       #
#        ##        #
#        ##        #
#       #  #       #
#      #    #      #
#     #      #     #
#    #        #    #
#   #          #   #
#  #            #  #
# #              # #
##                ##
####################


FOO>w ##class(FOO.Boxes).length()
75

Still thinking, seems like it might go a bit smaller...

i=1:1:! j=1:1:$c(i=1!(i=s)!(j=1)!(j=s)!(j=i)!(s-i+1=j)*3+32)

70 or 73, depending on how cheeky you'll let me be wink

edit: 69 for my cheeky solution, the other one was the same as Zenkov's below but I wasted a character on a for bracket because I foolishly put my newline on the other side of the $s()

My cheeky solution was 

 r=1:1:! c=1:1:w:r#s<2!(c#s<2)!(c=r)!(s-r+1=c) "#" " "

I'm not sure if it will copy/paste properly, but there's a backspace character in the string before the #  laugh I considered it cheeky because despite looking correct in the terminal it's definitely not if you compared it byte for byte wink

Let's finish this competition this Wednesday (so it would be a week) and publish our best efforts then.

ClassMethod main(As %Integer = 10)
 i=1:1:! j=1:1:$S(j#s<2!(i#s<2)!(j=i)!(s-i+1=j):"#",1:" "}

Nice! And you can shave off 3 characters by using $EXTRACT instead of $SELECT

f i=1:1:s w ! f j=1:1:s w $e(" #",j#s<2!(i#s<2)!(j=i)!(s-i+1=j)+1)

My solution and how I got there.

I started with this:

 r=1:1:s{c=1:1:s{r=1!(r=s)!(c=1)!(c=s)!(r=c)!(s=(c+r-1)){"#"}else{" "c=s{!}}}

First improvement was thanks to @Robert Cemper who suggested moving i c=s{w !}}} into a first for:

 r=1:1:! c=1:1:r=1!(r=s)!(c=1)!(c=s)!(r=c)!(s=(c+r-1)){"#"}else{" "}

Finally got the idea of using $lb/$lf to get my best result of 76:

f r=1:1:s w ! f c=1:1:s w $s($lf($lb(c,r,r=s,c=s,c=r,r+c-s),1):"#",1:" ")

Some other ideas that didn't pan out.

First of all I thought about replacing $lf($lb)) with $f() but -1 and 1x numbers became a problem:

f r=1:1:s w ! f c=1:1:s w $s($f(c_r_(r=s)_(c=s)_(c=r)_$replace(r+c-s,-1,""),1):"#",1:" ")

Other idea was using $translate:

f r=1:1:s w ! f c=1:1:s w $tr(''$lf($lb(c,r,r=s,c=s,c=r,r+c-s),1),10,"# ")

Interestingly if we allow the box to be made of any symbols, some other solutions became possible. For example binary box (63 symbols):

f r=1:1:s w ! f c=1:1:s w '$lf($lb(c,r,r=s,c=s,c=r,r+c-s),1)