[Snark] [Bash, Python, Ruby] not every submission needs a useless shell script in it

Felipe Bemfica submissions at badcode.rocks
Sat Apr 27 17:30:22 UTC 2019


Hi -- this is my submission to the April 2019 challenge.

It's one file, and it requires bash, python 3, and ruby.

The script assumes the python 3 command is "python3",
but if it's called something else, there's a constant in the file
called `PYTHON` that you can set to the proper command.

It was lots of fun to write -- hope you enjoy it.

== License ==

Licensed under CC BY-SA 4.0

== books.sh ==

#!/bin/bash

#     badcode.rocks April 2019
#     (c) Felipe Bemfica
#     Licenced under CC BY-SA 4.0
#
#    "[...] not every submission needs a useless shell script in it."
#
#     Really, it's the .py file that's redundant. It's way cleaner
#     to compact all the files into a single executable .sh file.

#Sets up config file
if [ ! -f config.conf ]
then
echo "2 0.95" >> config.conf
echo "3 0.90" >> config.conf
echo "4 0.80" >> config.conf
echo "5 0.75" >> config.conf
fi

PYTHON="python3"  #python version
args="$@"

bash -c "COMMENT() { cat -; }; IGNORELINE() { cat -; }; \
\
  cat $0 \
| COMMENT // Cat $0 \
\
\
| COMMENT // Isolate lines of python code \
| grep \"#py\" | IGNORELINE \
\
\
| COMMENT // Ignore lines containing IGNORELINE \
| grep -v \"IGNORELINE\" \
\
\
| COMMENT // Get rid of the leader \
| sed \"s/^#py //\" | IGNORELINE \
\
\
| COMMENT // Hygenic macro preprocessor \
  ------- // Permits for more pythonic syntax in code \
\
| COMMENT // config.get \
| sed \
\"s/config.get/\
(lambda x: float([i[1] for i in config if i[0] == str(x)][0]))/\" \
\
| COMMENT // bag.set_price \
          // added macros to give mutation syntax \
          // to immutable namedtuples -- more pythonic \
| sed \
\"s/\\(\w*\\).set_price(\\(.\\+\\?\\))/\
\\1 = Bookbag\\(\\1.finished, \\2, \\1.total, \\1.generation\\)/\" \
\
| COMMENT // bag.set_finished \
| sed \
\"s/\\(\w*\\).set_finished(\\(.\\+\\?\\))/\
\\1 = Bookbag\\(\\2, \\1.price, \\1.total, \\1.generation\\)/\" \
\
| COMMENT // bag.set_generation \
| sed \
\"s/\\(\w*\\).set_generation(\\(.\\+\\?\\))/\
\\1 = Bookbag\\(\\1.finished, \\1.price, \\1.total, \\2\\)/\" \
\
| COMMENT // Statically computing a list literal \
          // because it\'s faster than a dynamic python range \
          // Too complex for sed \
| ruby -e \"\
    a = STDIN.read
    def range(x, y)
        xi = x.to_i
        yi = y.to_i
        n = xi..yi
        str = \\\"\\\"
        n.each do |i|
            str += i.to_s + \\\", \\\"
        end
        return \\\"[#{str[0..-3]}]\\\"
    end
    while a.match(/static_range\((.*?), (.*?)\)/) do
        a = a.sub(/static_range\(.*?\)/, range(\\\$1, \\\$2))
    end
    STDOUT.write(a)\" \
\
| $PYTHON - arg $args"

#py #!/usr/bin/env python
#py
#py CONFFILE = "config.conf"
#py
#py from collections import namedtuple
#py Bookbag = namedtuple("Bookbag", "finished price total generation")
#py
#py def main():
#py
#py     global CONFFILE
#py     CONFFILE = open(CONFFILE)
#py     config = [thing for thing in map(lambda x: x.split(" "), CONFFILE.read().split("\n"))]
#py     CONFFILE.close()
#py     config.append(["1", "1"])
#py
#py     # Just-in-time imports speed up algorithm
#py     import sys
#py     books = map(lambda x: int(x)-1, sys.argv[2:])
#py
#py     total = [0, 0, 0, 0, 0]
#py
#py     for book in books:
#py         total[book] += 1
#py
#py     finished_already = 0
#py     for index, bit in enumerate((1, 2, 4, 8, 16)):
#py         if total[index] == 0:
#py             finished_already |= bit
#py
#py     full_bags = []
#py     unfull_bags = [Bookbag(finished_already, 0, total, 0)]
#py     current_generation = 0
#py
#py     for book_set in static_range(1, 31):
#py         for bag in unfull_bags:
#py             if bag.generation != current_generation:
#py                 continue
#py             import copy
#py             bag2 = copy.deepcopy(bag)
#py             bag2.set_generation(bag2.generation+1)
#py             unfull_bags.append(bag2)
#py
#py             while ((~(bag.finished & ~book_set) &
#py                    (bag.finished ^ book_set)) and
#py                    not  bag.finished & book_set):
#py
#py                 new_set_size = 0
#py                 for book, book_bit in enumerate((1, 2, 4, 8, 16)):
#py                     if book_set & book_bit:
#py                         bag.total[book] -= 1
#py                         new_set_size += 1
#py                         if bag.total[book] == 0:
#py                             bag.set_finished(bag.finished | book_bit)
#py
#py                 sale_price = bag.price + int(800*new_set_size*config.get(new_set_size))
#py                 bag.set_price(sale_price)
#py
#py                 if bag.finished == 31:
#py                     full_bags.append(bag)
#py                     break
#py                 else:
#py                     bag2 = copy.deepcopy(bag)
#py                     bag2.set_generation(bag2.generation+1)
#py                     unfull_bags.append(bag2)
#py         current_generation += 1
#py
#py     if not full_bags:
#py         print(0)
#py     else:
#py         print(min(full_bags, key=lambda x: x.price).price)
#py
#py (lambda: main())()


More information about the Snark mailing list