Task: Decision tables




Go: package main

import (
    "errors"
    "fmt"
    "os"
)

type dtText struct {
    rules, text string
}

var ptText = []dtText{
    {"YYYYNNNN", "Printer does not print"},
    {"YYNNYYNN", "A red light is flashing"},
    {"YNYNYNYN", "Printer is unrecognised"},
    {"--------", ""},
    {"  X     ", "Check the power cable"},
    {"X X     ", "Check the printer-computer cable"},
    {"X X X X ", "Ensure printer software is installed"},
    {"XX  XX  ", "Check/replace ink"},
    {" X X    ", "Check for paper jam"},
}

type dtMap map[string][]string

func compileDT(t []dtText) (dtMap, error) {
    if len(t) == 0 {
        return nil, errors.New("Empty decision table")
    }
    var conditions, actions []dtText
    ruleColumns := len(t[0].rules)
    for i, row := range t {
        if len(row.rules) != ruleColumns {
            return nil, errors.New("Inconsistent number of rule columns")
        }
        if len(row.text) == 0 {
            if conditions != nil {
                return nil, errors.New("Multple separator lines")
            }
            if i == 0 {
                return nil, errors.New("No conditions specified")
            }
            if i == len(t)-1 {
                return nil, errors.New("No actions specified")
            }
            conditions = t[:i]
            actions = t[i+1:]
        }
    }
    if conditions == nil {
        return nil, errors.New("Missing separator line")
    }
    m := make(map[string][]string, ruleColumns)
    kb := make([]byte, len(conditions))
    for col := 0; col < ruleColumns; col++ {
        for i, c := range conditions {
            kb[i] = c.rules[col]
        }
        key := string(kb)
        for _, a := range actions {
            if a.rules[col] != ' ' {
                m[key] = append(m[key], a.text)
            }
        }
    }
    return m, nil
}

func init() {
    var err error
    if ptMap, err = compileDT(ptText); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

var ptMap dtMap

func main() {
    for _, a := range ptMap["NYY"] {
        fmt.Println(a)
    }
}




Python: 

def dt_creator():
    print("\n\nCREATING THE DECISION TABLE\n")
    conditions = input("Input conditions, in order, separated by commas: ")
    conditions = [c.strip() for c in conditions.split(',')]
    print( ("\nThat was %s conditions:\n  " % len(conditions))
           + '\n  '.join("%i: %s" % x for x in enumerate(conditions, 1)) )
    print("\nInput an action, a semicolon, then a list of tuples of rules that trigger it. End with a blank line")
    action2rules, action = [], ' '
    while action:
        action = input("%i: " % (len(action2rules) + 1)).strip()
        if action:
            name, _, rules = [x.strip() for x in action.partition(';')]
            rules = eval(rules)
            assert all(len(rule) == len(conditions) for rule in rules), \
                   "The number of conditions in a rule to trigger this action is wrong" 
            action2rules.append((name, rules))
    actions = [x[0] for x in action2rules]
    
    rule2actions = dict((y,[]) for y in set(sum((x[1] for x in action2rules), [])))
    for action, rules in action2rules:
        for r in rules:
            rule2actions[r].append( action )
    return conditions, rule2actions

def dt_user(dt, default=['Pray!']):
    conditions, rule2actions = dt
    print("\n\nUSING THE DECISION TABLE\n")
    rule = tuple(int('y' == input("%s? (Answer y if statement is true or n): " % c)) for c in conditions)
    print("Try this:\n  " + '\n  '.join(rule2actions.get(rule, default)))

if __name__ == '__main__':
    dt = dt_creator()
    dt_user(dt)
    dt_user(dt)
    dt_user(dt)