Product lines
Weekly challenge 267 — 29 April 2024
Week 267: 29 Apr 2024
You are given a string, $str, and a 26-items array @widths containing the width of each character from a to z. Write a script to find out the number of lines and the width of the last line needed to display the given string, assuming you can only fit 100 width units on a line.
Example 1 Input: $str = "abcdefghijklmnopqrstuvwxyz" @widths = (10,10,10,10,10,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10,10,10,10,10,10) Output: (3, 60) Line 1: abcdefghij (100 pixels) Line 2: klmnopqrst (100 pixels) Line 3: uvwxyz (60 pixels) Example 2 Input: $str = "bbbcccdddaaa" @widths = (4,10,10,10,10,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10,10,10,10,10,10) Output: (2, 4) Line 1: bbbcccdddaa (98 pixels) Line 2: a (4 pixels)
I can't think of a clever way to do this so have just done the obvious: take one
character a time from $str
, see if it will fit on the current line, if so add it
to that line or if not, start a new line.
It helps to first create a hash %pixels
such that $pixels{$ch}
is the
width of $ch
.
In the 1980s I did this for real as we had a daisy-wheel printer with characters of varying widths. It could 'print' spaces of any number of points width so that text could be right-and-left justified. Also, it could print left-to-right or right-to-left, and I fed it alternate lines in forward and reverse order to minimise the time the print head spent moving horizontally between lines.
And then laser printers and Microsoft Word came along and all that was redundant - until today.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2024-04-29 use utf8; # Week 267 - task 2 - Line counts use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; line_counts('abcdefghijklmnopqrstuvwxyz', [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]); line_counts('bbbcccdddaaa', [ 4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]); line_counts('thequickbrownfoxjumpsoverthelazydog', [15, 27, 12, 28, 16, 29, 33, 21, 14, 29, 36, 13, 14, 9, 18, 23, 22, 35, 27, 15, 25, 21, 19, 35, 23, 15]); sub line_counts { my ($str, @widths, $ch, $limit, %pixels, $lines, $chars, $j, $line, @lines, @line_length); $str = $_[0]; @widths = @{$_[1]}; $limit = 100; # set $pixels{$char} to the width of $char for $j (0 .. 25) { $pixels{chr(ord('a') + $j)} = $widths[$j]; } # loop over characters in $str $line = 0; $chars = $limit; while ($str =~ m|([a-z])|g) { # needs a new line $ch = $1; if ($chars + $pixels{$ch} > $limit) { $line ++; $chars = $pixels{$ch}; # fits on current line } else { $chars += $pixels{$ch}; } # save for explanation $lines[$line] .= $ch; $line_length[$line] += $pixels{$ch}; } # results say qq[\nInput: \@str = '$str']; say qq[ \$widths = (] . join(', ', @widths[0 .. 12]) . ','; say qq[ ] . join(', ', @widths[13 .. 25]) . ')'; say qq[Output: ($line, $chars)]; for $j (1 .. @lines - 1) { say qq[ Line $j: $lines[$j] ($line_length[$j] pixels)]; } }
Input: @str = 'abcdefghijklmnopqrstuvwxyz' $widths = (10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10) Output: (3, 60) Line 1: abcdefghij (100 pixels) Line 2: klmnopqrst (100 pixels) Line 3: uvwxyz (60 pixels) Input: @str = 'bbbcccdddaaa' $widths = (4, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10) Output: (2, 4) Line 1: bbbcccdddaa (98 pixels) Line 2: a (4 pixels) Input: @str = 'thequickbrownfoxjumpsoverthelazydog' $widths = (15, 27, 12, 28, 16, 29, 33, 21, 14, 29, 36, 13, 14, 9, 18, 23, 22, 35, 27, 15, 25, 21, 19, 35, 23, 15) Output: (9, 33) Line 1: thequ (99 pixels) Line 2: ickb (89 pixels) Line 3: rown (81 pixels) Line 4: fox (82 pixels) Line 5: jump (91 pixels) Line 6: sove (82 pixels) Line 7: rthel (100 pixels) Line 8: azydo (99 pixels) Line 9: g (33 pixels)
Any content of this website which has been created by Peter Campbell Smith is in the public domain