Draw a sudoku board using line drawing characters

20

4

This is code golf. For this challenge, I will accept a method (you don't need a full program), but the method signature does count towards the byte count and I want to see the full signature (not a lamdba). The input for the method is an integer array with 81 elements. The output/return value from the method is a string that represents the array as an ascii sudoku board.

If you're using an esoteric language or something that absolutely doesn't have methods, you can adapt, but if the language supports this at all I want to see something might actually be plugged into a "real" ungolfed program, even if the method body itself is a pain to work with. The requirement is not meant to block languages like Jelly or 05AB1E, but to make it easier for languages like Java to build something that makes sense for that platform.

For the input, integer values 1-9 should have obvious meanings. A 0 should always be interpreted as a blank cell. You may also interpret anything else outside the 1-9 range as a blank cell, but this is not required. Positioning from the array to the puzzle starts at the top left and fills each row from left to right before moving to the next row.

For the boxes, I want double lines around the outside and between each 3x3 region, and single lines between other cells. These should be drawn with line drawing characters (if your I/O format represents strings as a sequence of bytes rather than a sequence of characters, you should represent them in a well-known encoding such as UTF-8 or codepage 347).

For this challenge, I am NOT asking you to generate the sudoku puzzle. That is the input for the function. I am NOT asking you to solve the puzzle. I'm just asking you to produce a string to "draw" what you're given (in as few bytes as possible).

Example Input:

Values for the array:

{ 8, 5, 0, 0, 0, 2, 4, 0, 0, 7, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 0, 2, 3, 0, 5, 0, 0, 0, 9, 0, 0 ,0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 7, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 0, 4, 0}

The values can use whatever mechanism is natural for your language: int[], ArrayList, sequence, tuple, string of digits, whatever, as long as you have a value in the input for every cell (no maps for only populated cells to positions). Remember that the input is supplied... it is not part of your byte count. But the input might represent any sudoku puzzle, and the puzzle might not even have a valid solution. You do get to assume that puzzle is printable. You won't get something with 82 elements, for example.

You also get to assume a reasonable fixed-width font.

Corresponding Output:

╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ 8 │ 5 │   ║   │   │ 2 ║ 4 │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 7 │ 2 │   ║   │   │   ║   │   │ 9 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │ 4 ║   │   │   ║   │   │   ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║ 1 │   │ 7 ║   │   │ 2 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 3 │   │ 5 ║   │   │   ║ 9 │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │ 4 │   ║   │   │   ║   │   │   ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║   │ 8 │   ║   │ 7 │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │ 1 │ 7 ║   │   │   ║   │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │   ║   │ 3 │ 6 ║   │ 4 │   ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝

Joel Coehoorn

Posted 2017-06-16T16:11:34.557

Reputation: 355

4Are you sure about the method part? That doesn't make sense for a lot of languages (i.e., languages without methods). – Cyoce – 2017-06-16T16:30:53.930

1For languages that don't have methods, you can adapt. But if they do, I'm looking for something that might actually be useful to plug into a "real" program. I'll add that to question. – Joel Coehoorn – 2017-06-16T16:32:34.493

2What's the reasoning for not allowing lambdas? Those could certainly be plugged into a "real" program just as well as named functions / methods – Julian Wolf – 2017-06-16T19:05:49.050

2

Nitpicky but important: There's no such thing as an "ASCII box drawing character." ASCII covers codes 0 through 127, none of which are box drawing characters. In recent times, Unicode is the standard, but it has several different encodings: UTF-8, UTF-16 etc, all of which use more than 1 byte per boxdrawing character. Older encodings such as Codepage 437 support single-byte box drawing characters. When you use characters outside the ASCII range, you should specify which encodings are valid. https://en.wikipedia.org/wiki/Box-drawing_character https://en.wikipedia.org/wiki/Unicode

– Level River St – 2017-06-16T21:02:21.410

2"Method" should probably be "named function" to get the closest possible equivalent to a method in non-object-oriented languages. (For example, C, a widely used language, doesn't have methods but does have named functions.) In most of the languages I'm aware of which have methods, they're that language's equivalent of a named function. (The best-known exception I'm aware of is C++, where using a named function would be a lot more plausible for this task than using a method would be, as it's really unclear what sort of object you'd associate the method with.) – None – 2017-06-17T00:58:40.510

Answers

9

Python 3, 232 bytes

Thanks to those who helped to golf this down.

Encryption within encryption...

q=lambda x,y:x+y+x+y+x
r=lambda a,b,c,d,e:a+q(q(b*3,c),d)+e+"\n"
print(((r(*"╔═╤╦╗")+q(q("║ %d │ %d │ %d "*3+"║\n",r(*"╟─┼╫╢")),r(*"╠═╪╬╣"))+r(*"╚═╧╩╝"))%eval(input())).replace(*"0 "))

Try it online!

To be golfed.

Leaky Nun

Posted 2017-06-16T16:11:34.557

Reputation: 45 011

How did I not notice that... that's like the entire reason why I used Python 2, but thanks. – Leaky Nun – 2017-06-16T16:35:50.267

1Actually you're better off using Python 3 since then you won't need the first line. – Erik the Outgolfer – 2017-06-16T16:36:20.237

1

You can remove more parens on the last line: tio

– Conor O'Brien – 2017-06-16T16:37:14.510

Remove definition of f and define i as i=["╔"+(g+"╦")*2+g+"╗"]+d+2*(["╠"+(e+"╬")*2+e+"╣"]+d)+["╚"+(h+"╩")*2+h+"╝"] saves 4 bytes – officialaimm – 2017-06-16T16:41:03.227

7

C (gcc), 398 395 291 bytes

Saved 3 bytes by working through the string reversed, and 104 (!) bytes thanks to Leaky Nun.

#include<locale.h>
#define q(x,y) x y x y x
#define D L"╝"q(q("═══","╧"),"╩")"╚"q(q("\n║"q(q(" & ","│"),"║")"║","\n╢"q(q("───","┼"),"╫")"╟"),"\n╣"q(q("═══","╪"),"╬")"╠")"\n╗"q(q("═══","╤"),"╦")"╔"
i;f(int*t){setlocale(LC_ALL,"");for(i=721;i--;)wprintf(L"%lc",D[i]%19?D[i]:*t++?48+t[-1]:32);}

Try it online!

C (gcc), 395 bytes

I'll keep this here so its more evident as to how the program works.

#include<locale.h>
#define A L"\n╢───┼───┼───╫───┼───┼───╫───┼───┼───╟"
#define B L"\n║ & │ & │ & ║ & │ & │ & ║ & │ & │ & ║"
#define C L"\n╣═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╠"
#define E B A B A B
#define D L"╝═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╚"E C E C E L"\n╗═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╔"
i;f(int*t){setlocale(LC_ALL,"");for(i=721;i--;)wprintf(L"%lc",D[i]%19?D[i]:*t++?48+t[-1]:32);}

Try it online!

Working with unicode in C is... costly. Takes input as an int* as shown in the link and in the specification.

I'm going to see if I can save bytes using some number magic instead of hardcoding the string.

Conor O'Brien

Posted 2017-06-16T16:11:34.557

Reputation: 36 228

355 bytes – Leaky Nun – 2017-06-16T19:04:22.217

@LeakyNun Huh, thanks! It's 291 bytes according to TIO – Conor O'Brien – 2017-06-16T19:10:13.213

TIO is counting using SBCS.

– Leaky Nun – 2017-06-16T19:12:37.397

6

PHP, 297 bytes

<?for(;$l<19;$l++)echo$l&1?strtr(vsprintf(str_pad("",67,"║ %d │ %d │ %d "),array_slice($_GET,9*($l/2^0)-9,9)),0," "):str_pad([╔,╟,╠,╚][$b=$l?$l<18?$l%6<1?2:1:3:0],108,strtr("11101110111".[╦,╫,╬,╩][$b],[[╤,═],[┼,─],[╪,═],[╧,═]][$b])).[╗,╢,╣,╝][$b],"
";

Try it online!

Expanded

for(;$l<19;$l++)  # loop thrpugh lines
  echo$l&1 # Output
    ?strtr(
        vsprintf(str_pad("",67,"║ %d │ %d │ %d ") # formated string for lines with numbers
        ,array_slice($_GET,9*($l/2^0)-9,9)) # nine items of the input array
      ,0," ") #replace zeros with space
    :str_pad([╔,╟,╠,╚][$b=$l?$l<18?$l%6<1?2:1:3:0] # start character non number lines and switch number four cases
      ,108 # fill too 108 bytes
      ,strtr("11101110111".[╦,╫,╬,╩][$b] # with string 
        ,[[╤,═],[┼,─],[╪,═],[╧,═]][$b]))  #replace ones and zero with the two character in array chosed 
    .[╗,╢,╣,╝][$b] # end row with chosen character
  ,"
    "; # end line with new line

used functions for both versions

vsprintf , strtr , str_pad , array_slice , array_chunk

PHP, 313 bytes

<?$r=($s=str_pad)(╔,108,($t=strtr)(($p=11101110111).╦,[╤,═])).╗;foreach(array_chunk($_GET,9)as$v)$r.=$t(vsprintf($s("
",68,"║ %d │ %d │ %d "),$v),0," ").(++$k%9?$k%3?$s("
╟",109,$t($p.╫,[┼,─])).╢:$s("
╠",109,$t($p.╬,[╪,═])).╣:"");echo$r.$s("
╚",109,$t($p.╩,[╧,═])).╝;

Try it online!

Jörg Hülsermann

Posted 2017-06-16T16:11:34.557

Reputation: 13 026

How does this work? – Cyoce – 2017-06-16T19:39:21.020

@Cyoce I have added an explanation for my new version – Jörg Hülsermann – 2017-06-16T22:00:32.063

5

T-SQL, 445 437 bytes (in 381 characters)

DECLARE @r INT=0,@ NVARCHAR(999)=N'╔=╤=╤=╦=╤=╤=╦=╤=╤=╗P'p:SELECT @+=FORMAT(CAST(SUBSTRING(a,@r*9+1,9)AS INT),N'║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║P')FROM t
SET @r+=1IF @r=9SET @+=N'╚=╧=╧=╩=╧=╧=╩=╧=╧=╝P'ELSE IF @r%3=0SET @+=N'╠=╪=╪=╬=╪=╪=╬=╪=╪=╣P'ELSE SET @+=N'╟-┼-┼-╫-┼-┼-╫-┼-┼-╢P'IF @r<9GOTO p
PRINT REPLACE(REPLACE(REPLACE(REPLACE(@,'=',N'═══'),'-',N'───'),'0',' '),'P',CHAR(13))

Input is via a string of digits stored in column a of pre-existing table t, per approved methods.

Format and Explanation:

DECLARE @r INT=0, @ NVARCHAR(999)= N'╔=╤=╤=╦=╤=╤=╦=╤=╤=╗P'
p:
    SELECT @+= FORMAT(CAST(SUBSTRING(a, @r*9+1, 9) AS INT),
        N'║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║P') FROM t
    SET @r+=1
    IF @r=9 SET @+= N'╚=╧=╧=╩=╧=╧=╩=╧=╧=╝P'
    ELSE IF @r%3=0 SET @+= N'╠=╪=╪=╬=╪=╪=╬=╪=╪=╣P'
    ELSE SET @+= N'╟-┼-┼-╫-┼-┼-╫-┼-┼-╢P'
IF @r<9 GOTO p
PRINT REPLACE(REPLACE(REPLACE(REPLACE(@, '=',N'═══'), '-',N'───'), '0',' '), 'P',CHAR(13))

In the top line of the loop I'm getting the next 9 digits of the input string from column a of pre-existing table t.

I convert that string of digits to an integer, and use the .Net FORMAT function to display them using a custom text template '║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║ 0 │ 0 │ 0 ║P'.

After that I just append the appropriate divider line, and make some byte-saving replacements before output.

Output is displayed in the results pane:

╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
║ 8 │ 5 │   ║   │   │ 2 ║ 4 │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 7 │ 2 │   ║   │   │   ║   │   │ 9 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │ 4 ║   │   │   ║   │   │   ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║ 1 │   │ 7 ║   │   │ 2 ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║ 3 │   │ 5 ║   │   │   ║ 9 │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │ 4 │   ║   │   │   ║   │   │   ║
╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣
║   │   │   ║   │ 8 │   ║   │ 7 │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │ 1 │ 7 ║   │   │   ║   │   │   ║
╟───┼───┼───╫───┼───┼───╫───┼───┼───╢
║   │   │   ║   │ 3 │ 6 ║   │ 4 │   ║
╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝

I previously had some additional replacements for some of the other drawing characters, but they ultimately didn't save me bytes.

EDIT 1: Saved 8 bytes by starting @r at zero instead of 1, and removing some unneeded spaces.

BradC

Posted 2017-06-16T16:11:34.557

Reputation: 6 099

4

Retina, 196 167 bytes

.{27}
¶N#=XZ#Q¶|$&
\d{9}\B
$&¶M#─┼Y#P¶|
\d{3}
 $& |
\B\d
 │ $&
^¶.*
B#=RT#E
$
¶H#=UW#K
+`#([^#¶]+)([^#¶])#
#$1#$2#$1#$2#$1#
#(.)#
$1$1$1
T`0=|#L` ═-╬

Try it online! Takes input as a string of length 81. Explanation: Because the box drawing characters cost three bytes, the unicode code points ═-╬ are represented in the code using =|#A-Z (not all the characters are used but sticking to ranges saves bytes). Additionally the rows are compressed using # signs: a#bcd#e expands to abbbcbbbcbbbdbbbcbbbcbbbdbbbcbbbcbbbe.

.{27}
¶N#=XZ#Q¶|$&

Inserts ╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣ for every third row, plus a at the start of every group of 27.

\d{9}\B
$&¶M#─┼Y#P¶|

Inserts ╟───┼───┼───╫───┼───┼───╫───┼───┼───╢ between the other rows, plus s at the start of those rows.

\d{3}
 $& |

Inserts s after every three digits. All the s have now been inserted.

\B\d
 │ $&

Inserts |s between all the remaining pairs of digits. (This one is the actual box drawing character rather than a pipe. Unfortunately the characters ─│┼ have codes too far apart from each other and the double box characters to make it worth while using placeholders.)

^¶.*
B#=RT#E

Changes the first row to ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗ (this saves 1 byte over not adding the first row in the first place).

$
¶H#=UW#K

Adds ╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝ after the last row.

+`#([^#¶]+)([^#¶])#
#$1#$2#$1#$2#$1#

Expands a#bcd#e, first to a#bc#d#bc#d#bc#e, then to a#b#c#b#c#b#d#b#c#b#c#b#d#b#c#b#c#b#e.

#(.)#
$1$1$1

Changes #b# to bbb. This completes the decompression.

T`0=|#L` ═-╬

Deletes all the zero entries, and replaces the placeholders with the box drawing characters.

Neil

Posted 2017-06-16T16:11:34.557

Reputation: 95 035

You forgot to replace 0 by space. – Leaky Nun – 2017-06-16T18:54:11.710

Also has double lines around every row, rather than just the border and 3x3 regions. – Joel Coehoorn – 2017-06-16T18:54:46.983

@JoelCoehoorn Fixed, sorry. – Neil – 2017-06-16T19:10:12.873

@LeakyNun Thanks, I'd overlooked that. (Also, I like to avoid lines ending with, or especially only containing, spaces, which is why I looked for an alternative 2-byte saving.) – Neil – 2017-06-16T19:11:24.763

3

SOGL V0.12, 174 172 164 160 158 bytes

«ž#>]Wž²6√±_ΕΨ╥╬]v←ē⅓ZΗ⌡z∫◄‽q   §↑╗∑Ολ[Μ↕z↓/∆Yn⁄:Ο║χ≥¾▓g*≈]═+π℮─6⁽SE/⁷,0+►Ƨ⌡u\^⁄-▼0cΦ“╤─┼╬│║═╔╗╚╝”Φ⅜nΡ¡ΞΨīŗ(`½│uģ“ ╬ζ─{ζ} 6Δ¹∑A'⁄─{IaW}¹∑#¶ŗ3 ¶ŗ ”+Ƨøp+!!┌d0@ŗčŗ

Overly long explanation:

...“                          push a big base-43 encoded number; will be used later. It's pushed here to save a byte on a quote
    ...”                      push "╤─┼╬│║═╔╗╚╝" - the chars in SOGLs encoding
        ...“                  push 679301851737965572513837476350078477
             ╬                push "╬"
              ζ               convert it to its codepoint (9580)
               ─              convert that number to an array of base-9580 numbers
                {ζ}           convert each number to a character (pushing each on the stack)
                    6Δ        push all ascii chars up to 6 (" !"#$%&'()*+,-./0123456")
                      ¹∑      join all the strings on the stack together ("╤─┼╬│║═╔╗╚╝╦╟╫╢╠╪╣╧╩ !"#$%&'()*+,-./0123456")
                        A     save on variable `A`. Now ontop of the stack is the 1st big number
                         '⁄─  onvert from base 43

{   }                           for each number do
 I                                increase
  aW                              get its position in the variable A
     ¹∑                         join all the strings ontop of the stack (the loop above pushed each char separately)
       #¶ŗ                      replace quote (") characters with newlines
          3 ¶ŗ                  replace 3s with "¶"
               ”+               append "”"
                 Ƨøp+           append "øp"
                     !!         execute the created code as SOGL
                       ┌        push "-"
                        d       push variable d - defaults to string input. In a full program could be set as an input
                         0@ŗ    replace zeroes with spaces
                            č   chop into an array
                             ŗ  replace ["-" with input chopped - so each iteratively]

The program that's executed:

───!#
 - $
¶%&¶'(
)╪)╪)+
)╤)╤),
)╧)╧).
┼#
+╬+/
0!╫0!1
,╦,2
.╩.4
5│$║&
#0
═══)
$│$5
║&&%
╠/╬+╣6'*
╟1╫0!╢(
(6
╔2╦,╗6'**╚4╩.╝”øp

where all but last line are just in the entire program replace occurrences of the last char of this line with the rest of this line. This is the reason it was possible to make half of the chars just random ascii (but getting so that spaces, dashes, and quotes are usefully used took a while to figure out)

...”    push the whole sudoku grid
    øp  print nothing (prevents bug that this code would already print and pop the result)

Try it Here!
The online interpreter code is more correct because tabs don't work with SE

-8 bytes: brute force replacement compressing the entire board, then replacing foreign chars (to the codepage) with their codepoints. Doing this took an hour less than the old program...
-4 bytes: compressing the compressed string...
-2 bytes: using a variable+string instead of array

dzaima

Posted 2017-06-16T16:11:34.557

Reputation: 19 048

2

With ideas harvested from other answers:

C# (.NET Core), 401 bytes, 349 Chars

string s(string x){Func<string,string,string>q=(m,n)=>m+n+m+n+m;var a="╔"+q(q("=","╤"),"╦")+"╗";for(var i=0;i<9;) {a+=int.Parse(x.Substring(i*9,9)).ToString("\n║"+q(q(" 0 ","│"),"║")+"║\n")+(i++<8?(i%3>0?"╟"+q(q("-","┼"),"╫")+"╢":"╠"+q(q("=","╪"),"╬")+"╣"):"╚"+q(q("=","╧"),"╩")+"╝");}return a.Replace("=","═══").Replace("-","───").Replace("0"," ");}

Ungolfed:

static public string s(string x)
{
    Func<string,string,string>q=(m,n)=>m+n+m+n+m;
    var a="╔"+q(q("=","╤"),"╦")+"╗";
    for (var i=0;i<9;) //once per row
    {
        //parse that row to an int, then spit out a formatted string
        a += int.Parse(x.Substring(i*9,9)).ToString("\n║"+q(q(" 0 ","│"),"║")+"║\n") 
          // as well as a trailing row for the box
          + (i++<8?(i%3>0?"╟"+q(q("-","┼"),"╫")+"╢":"╠"+q(q("=","╪"),"╬")+"╣"):"╚"+q(q("=","╧"),"╩")+"╝");
    }
    //expand placeholder characters before returning
    return a.Replace("=","═══").Replace("-","───").Replace("0"," ");
}

Try it online!

My Answer:

C# (.NET Core), 509 430 418 bytes, 328 chars

string b(string x){var a="╔=╤=╤=╦=╤=╤=╦=╤=╤=╗\n║";for(int i=0,j=0,k,l,m;j<3;j++)for(k=0;k<3;k++){for(l=0;l<3;l++)for(m=0;m<3;)a+=" "+x[i++]+(m++<2?" │":" ║");a+=i<80?(k<2?"\n╟-┼-┼-╫-┼-┼-╫-┼-┼-╢\n║":"\n╠=╪=╪=╬=╪=╪=╬=╪=╪=╣\n║"):"\n╚=╧=╧=╩=╧=╧=╩=╧=╧=╝";}return a.Replace("=","═══").Replace("-","───").Replace("0"," ");}

Ungolfed:

public string s(string x)
{
    var a = "╔=╤=╤=╦=╤=╤=╦=╤=╤=╗\n║";
    for (int i=0,j=0,k,l,m;j<3;j++)
    {
        for (k = 0; k < 3;k++)
        {
            for (l = 0; l < 3; l++)
            {
                for (m = 0; m < 3;)
                    a += " " + x[i++] + (m++ < 2 ? " │" : " ║");
            }
            a += i < 80 ? (k < 2 ? "\n╟-┼-┼-╫-┼-┼-╫-┼-┼-╢\n║": "\n╠=╪=╪=╬=╪=╪=╬=╪=╪=╣\n║") 
                        : "\n╚=╧=╧=╩=╧=╧=╩=╧=╧=╝";
        }
    }
    return a.Replace("=", "═══").Replace("-","───").Replace("0"," ");
}

I also looked at using a lambda for the `for` loops here, but it actually cost me one byte (saved 10 bytes per loop, with 41 bytes of overhead).

Try it online!

Joel Coehoorn

Posted 2017-06-16T16:11:34.557

Reputation: 355

Do you need to count each drawing character as two bytes? – BradC – 2017-06-16T21:09:08.070

I did, fixed now. I had meant to address that in question and count characters rather than bytes, because of those characters, but I suppose it's too late now. – Joel Coehoorn – 2017-06-16T21:13:48.347

Yep, bytes is harder, some ascii substitutions save bytes but don't impact characters (or even hurt characters). I'm working on T-SQL, and char vs nchar is a pretty big difference. – BradC – 2017-06-16T21:17:59.657

2

JavaScript (ES6), 246 bytes / 198 chars

(n,r=(x,y)=>x+y+x+y+x,q=s=>([u,w,x,y,z]=[...s[0]],u+r(r(w+w+w,x),y)+z+`
`))=>q`╔═╤╦╗`+n.reduce((o,v,i)=>o+"║││"[i++%3]+` ${v||" "} `+(i%9?e:`║
`+(i-27&&i-54?i<81?q`╟─┼╫╢`:e:q`╠═╪╬╣`)),e="")+q`╚═╧╩╝`

Input is an array of integers. Ended up using the same two helper functions as Leaky Nun's Python answer, so credit goes there.

If function is required, 263 bytes / 215 chars

function g(n,r=(x,y)=>x+y+x+y+x,q=s=>([u,w,x,y,z]=[...s[0]],u+r(r(w+w+w,x),y)+z+`
`)){return q`╔═╤╦╗`+n.reduce((o,v,i)=>o+"║││"[i++%3]+` ${v||" "} `+(i%9?e:`║
`+(i-27&&i-54?i<81?q`╟─┼╫╢`:e:q`╠═╪╬╣`)),e="")+q`╚═╧╩╝`}

Test Snippet

Any input of 81 numbers is supported (1234, 1, 2, 3, 4. [1 2 3 4], etc). Best viewed as full page.

f=
(n,r=(x,y)=>x+y+x+y+x,q=s=>([u,w,x,y,z]=[...s[0]],u+r(r(w+w+w,x),y)+z+`
`))=>q`╔═╤╦╗`+n.reduce((o,v,i)=>o+"║││"[i++%3]+` ${v||" "} `+(i%9?e:`║
`+(i-27&&i-54?i<81?q`╟─┼╫╢`:e:q`╠═╪╬╣`)),e="")+q`╚═╧╩╝`

onload=I.oninput=_=>O.innerHTML=(m=I.value.match(/\d/g))&&m.length==81?f(m.map(x=>+x)):''
<textarea id=I rows=3 style="width:95%">8, 5, 0, 0, 0, 2, 4, 0, 0, 7, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 0, 2, 3, 0, 5, 0, 0, 0, 9, 0, 0 ,0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 7, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 0, 4, 0</textarea>
<pre id=O>

Justin Mariner

Posted 2017-06-16T16:11:34.557

Reputation: 4 746

2

Batch, 332 bytes

@echo off
set/ps=
set s=%s:0= %
call:l É Í Ñ Ë »
set t="Ç Ä Å × ¶"
for %%i in (%t% %t% "Ì Í Ø Î ¹" %t% %t% "Ì Í Ø Î ¹" %t% %t% "È Í Ï Ê ¼")do call:c %%~i
exit/b
:c
set t=º
for %%j in (³ ³ º ³ ³ º ³ ³ º)do call set t=%%t%% %%s:~,1%% %%j&call set s=%%s:~1%%
echo %t%
:l
set t=%2%2%2%3%2%2%2%3%2%2%2
echo %1%t%%4%t%%4%t%%5

Needs the console to be in CP437. If that's not your default, then you can change it using the CHCP 437 command if your console is set to TrueType fonts. (It will only work with raster fonts if CP437 is already your default code page.) This is what the code looks like in CP437:

@echo off
set/ps=
set s=%s:0= %
call:l ╔ ═ ╤ ╦ ╗
set t="╟ ─ ┼ ╫ ╢"
for %%i in (%t% %t% "╠ ═ ╪ ╬ ╣" %t% %t% "╠ ═ ╪ ╬ ╣" %t% %t% "╚ ═ ╧ ╩ ╝")do call:c %%~i
exit/b
:c
set t=║
for %%j in (│ │ ║ │ │ ║ │ │ ║)do call set t=%%t%% %%s:~,1%% %%j&call set s=%%s:~1%%
echo %t%
:l
set t=%2%2%2%3%2%2%2%3%2%2%2
echo %1%t%%4%t%%4%t%%5

Neil

Posted 2017-06-16T16:11:34.557

Reputation: 95 035

1

Tcl, 599 bytes (295 chars)

Very naïve approach, but I just had to do it even it not being a winner by any measure:

puts ╔═══╤═══╤═══╦═══╤═══╤═══╦═══╤═══╤═══╗
set r ║ 
lmap x $L {if !$x {set x \ }
set r $r\ $x\ [expr [incr i]%3?"│":"║"]
if ![expr $i%9] {puts $r\n[expr $i%27?"╟───┼───┼───╫───┼───┼───╫───┼───┼───╢":$i<72?"╠═══╪═══╪═══╬═══╪═══╪═══╬═══╪═══╪═══╣":"╚═══╧═══╧═══╩═══╧═══╧═══╩═══╧═══╧═══╝"]
set r ║}}

Try it online!

sergiol

Posted 2017-06-16T16:11:34.557

Reputation: 3 055

that's 599 UTF-8 bytes. You should try to reuse the common box characters to save bytes – dzaima – 2017-06-18T21:42:53.820

@dzaima:l know, I can do what I did on A keyboard so real you can almost TASTE it

– sergiol – 2017-06-18T21:46:24.380

@dzaima: It is why I said Very naïve approach – sergiol – 2017-06-18T21:49:20.880

1

Chip, 3645 bytes

...that's not a typo...

ooooooZZ-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-).
|`xxxx-x--(x---x---x---x---x-v-x---x---x---x---x---x-.`K-)-K-)-K-)-K-).
|b|`xx-x--(x-v-x---x-v-x---x-x-x---x-v-x---x-v-x---x-x-x---x-v-x---x-.`K-).
|>xd`x-x(v-x-x-x-v-x-x-x-v-x-x-x-v-x-x-x-v-x-x-x-v-x-x-x-v-x-x-x-v-x-x-x-.|
||`--x-x-x(x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x/.
|`--z',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\',/\','
`-. |,< >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.| >.|
*-x-/xZ/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ^/xZ'
Z~' |`'|`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`' |`','`'
    `)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)-K-)'
=
oooooo).h
`)))--^M^Zh
=
oooooo
|    `(--------------------------------------------------------------------------------------------------------va
KZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ^cg
)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx-xKZvvZ
xxxxxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxxx-Kxxxx}e
)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)x))xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)x))xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)x)b`feac
  c
=
oooooo
,'   `(--------------------------------------------------------------------------------------------------------.cba
KZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ^x^^)v--.
xx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxxx-xK-'f e`.
)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx-x-K-+Z+Z}e
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxK^}b gac
xxxxxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxxx-K^d
=
oooooo
,-'
KZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZtabgfv------.
)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx-xK^^x-Zv-vZ}e
xxxxxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxxxK^---^}cade,]b
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)-K----^-^^~'
,v'
db
=
oooooo
,--' `(--------------------------------------------------------------------------------------------------------v-.,-v-ZZZZZZZZZZZZf
KZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'a{x.df
)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xx)xxKx-xxv+Zc
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)x-KZx+bge
xx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxx)xxxxxxxxxxxx---K\--^c
 a^b
=
oooooo
,---'`(--------------------------------------------------.
KZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ'gf
)xxxxx)xxxxx)xxxxx)xxxxx)xxxxx)xxxxx)xxxxx)xxxxx)xxxxx)xx-^KZc
)xxxxx)x)xxx)x)xxx)xxxxx)x)xxx)x)xxx)xxxxx)x)xxx)x)xxx)xxbahKZ\ZZZ
x))xxxxxxxxxxxxxxxx))xxxxxxxxxxxxxxxx))xxxxxxxxxxxxxxxx))-K-eh|fff
 ,--K-v-v-K--v-vK-v---K-----K-----K-----K-----K-----K `--Z-Z--'
A/ab/B/e/C/cd/D/-e/A
*}s

Try it online!, sort of. The TIO version contains a cutoff about a third of the way in (the t after the 4th oooooo), so that it should terminate in less than 60 seconds. The full version takes about 1m25s on my machine, and TIO seems about half as quick. This also means the TIO only shows the first 7 lines of output.

My first draft weighed in at a massive 19758 bytes, and took me about 8m30s to run. The final solution, pre-golfing, was a spry 5980 bytes, taking only 2m07s.

So, how's it work, then?

This takes a string of 82 bytes, 81 digits, followed by a terminator. \0 or \n or even another number will do. (This implementation actually only looks at the first 81, but requires at least one more, since Chip will terminate if it has exhausted its input. If this is unacceptable, the flag -z may be used, which effectively appends an infinite number of \0 bytes to the end of the input.) The shortened TIO code doesn't actually get to all 81 bytes, so the point is moot there.

The way I've implemented this, it only looks at the low 4 bits of the input, so anything, really, can be a sudoku 'puzzle', from raw binary data, to the lesser-known works of Shakespeare. Any character whose low 4 bits are all zero will appear as a space (a special case), all other characters map into 123456789:;<=>?. (So, the last few aren't digits, but neither is 10 a valid number in normal sudoku).

For the box-drawing characters, it produces UTF-8, equating to 3 bytes each.

What about the actual implementation?

Chip is a 3D language that is inspired by integrated circuits. It has wires, logic gates, and memory cells. Most stuff is done on 2D planes, but these planes may be stacked atop one another. That is how this program is built.

The lines that start with = are the layer separators. Then, the layers are stacked, with the top and left sides aligned. The o's serve as pins, allowing signals to pass from one layer to another.

Each layer here has a purpose, you could think of them as functions. The first layer controls everything; it 'calls' each of the other layers in turn. There is a repeating left-to-right pattern here. That pattern keeps track of which of the 19 lines of output we are currently printing.

The second layer is rather tiny, and it has a very tiny job. It sets the 0x80 bit for all the lines of output except the lines that contain numbers. h is the Chip element that corresponds to the 0x80 bit. (The low end of the alphabet h through a define all eight output bits.)

Layer three is where we really get into the meat of printing. This layer is in charge of line one. The ungolfed version has eight rows of x's and )'s, mapping to 0's and 1's for each of the eight bits of each byte. However, we can take advantage of the patterns in the bits to accomplish the same task in fewer rows.

Layer four is much like the third. It handles the horizontal double lines.

Layer five handles the last line. Note that it is missing the wire along the top that the other layers have. This is because we don't need to return control to the sequencer. Instead, we can just terminate execution here with t.

Layer six handles the horizontal single lines.

Layer seven is where the numbers are printed. It is 'called' for each the nine numeric lines. It consumes 9 bytes of input as part of its execution.

Phlarx

Posted 2017-06-16T16:11:34.557

Reputation: 1 366

1

JavaScript (ES6), 222 bytes

Using short syntax for ES6 functions - 174 chars encoded in utf8, 222 bytes (https://mothereff.in/byte-counter). Using function ... requires 16 more bytes.

F=v=>[1,...v].map((x,i)=>'│║│'[i%3]+` ${x||' '} `+(i%9?'':`║
${[h,r,s,u,t]=i%27?'─╟╫┼╢':i>80?'═╚╩╧╝':i?'═╠╬╪╣':'═╔╦╤╗',r+(s=(u=(h+=h+h)+u+h+u+h)+s)+s+u+t}
`)).join``.slice(6)

Less golfed

F=v=>{
   // horizontal lines are appended after each 9th element
   // so I need to prepend a dummy first element to draw the top horizontal line
   v = [1, ...v];
   return v.map( (x,i) => 
     '│║│'[i % 3] + ` ${x||' '} ` // left bar and cell value
     + ( i % 9 ? '' // add horizontal line after each 9th element
       // the line drawing characters are chosen according to the value of i
       : `║\n${ [h, r, s, u, t] = 
         i % 27 != 0
         ? '─╟╫┼╢'
         : i > 80 
           ? '═╚╩╧╝' // i==81, bottom row
           : i != 0
             ? '═╠╬╪╣'
             : '═╔╦╤╗', // i==0, top row
         r + (s = (u = (h += h + h) + u + h + u + h) + s) + s + u + t
         }\n`
       )
   ).join``
   .slice(6) // cut the first cell (the dummy element)
}

F=v=>[1,...v].map((x,i)=>'│║│'[i%3]+` ${x||' '} `+(i%9?'':`║
${[h,r,s,u,t]=i%27?'─╟╫┼╢':i>80?'═╚╩╧╝':i?'═╠╬╪╣':'═╔╦╤╗',r+(s=(u=(h+=h+h)+u+h+u+h)+s)+s+u+t}
`)).join``.slice(6)

function go() {
  var i=I.value
  i = i.match(/\d+/g).map(x => +x); // convert strings to numbers
  O.textContent = F(i)
}
#I { width: 90% }
<input id=I value='8 5 0 0 0 2 4 0 0 7 2 0 0 0 0 0 0 9 0 0 4 0 0 0 0 0 0 0 0 0 1 0 7 0 0 2 3 0 5 0 0 0 9 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 8 0 0 7 0 0 1 7 0 0 0 0 0 0 0 0 0 0 3 6 0 4 0'>
<button onclick='go()'>go</button>
<pre id=O></pre>

edc65

Posted 2017-06-16T16:11:34.557

Reputation: 31 086

1

Java (OpenJDK 8), 279 bytes

String f(int[]a){String P="0121213121213121214",R[]={"╔═╤╦╗","║ │║║x","╟─┼╫╢","╠═╪╬╣","╚═╧╩╝"},r="";for(int X:P.getBytes()){for(int x:P.replace("1",R[X-=48].length()>5?"151":"111").getBytes())r+=R[X].charAt(x-48);r+="\n";}for(int i:a)r=r.replaceFirst("x",i>0?""+i:" ");return r;}

Try it online!

For the byte count, use CP-437, which is natively supported by Java as IBM437 (recent APIs) or Cp437 (older APIs); so use a system that has this charset has this charset as default charset.

This code is compatible from Java 5 onwards, but was tested on Java 8 only.

Explanation

String f(int[]a){
  String P="0121213121213121214",                         // Both lines and rows are repeated according to this pattern.
         R[]={"╔═╤╦╗","║ │║║x","╟─┼╫╢","╠═╪╬╣","╚═╧╩╝"},  // Characters found on each line.
                                                          //   (note the 'x')
         r="";                                            // The string under construction
  for (int X: P.getBytes()) {                             // For each line,
    for (int x:                                           //  For each character in the pattern,
         P.replace("1",R[X-=48].length()>5?"151":"111")   //    *but* with a cell width of 3,
                                                          //    and with an optional character ('x')
         .getBytes())
      r+=R[X].charAt(x-48);                               //   append the real mapped character
    r+="\n";                                              //  then append a new line
  }
  for(int i:a)                                            // For each number in the input
    r = r.replaceFirst("x",i>0?""+i:" ");                 //  replace the first 'x' with that number.
                                                          //    (or space if zero)
  return r;                                               // Return the constructed string.
}

Olivier Grégoire

Posted 2017-06-16T16:11:34.557

Reputation: 10 647