#!/usr/bin/env python3
'''
Check for direct and associative cache efficiency
'''
import sys


def dircache(nblocks, bsize, addresses, verbose=False):
    cache = [-1] * nblocks
    hit, miss = 0, 0
    for addr in addresses:
        tag = addr // (bsize * 4)
        if cache[tag % nblocks] == tag:
            hit += 1
        else:
            cache[tag % nblocks] = tag
            miss += 1
    return hit, miss


def a2dcache(nblocks, ssize, bsize, addresses, verbose=False):
    nbanks = nblocks // ssize
    banks = [[] for c in range(nbanks)]
    hit, miss = 0, 0
    for addr in addresses:
        tag = addr // (bsize * 4)
        cache = banks[tag % nbanks]
        if tag in cache:
            c = cache.pop(0)
            cache.append(c)
            hit += 1
        else:
            if len(cache) >= ssize:
                cache.pop(0)
            cache.append(tag)
            miss += 1
    return hit, miss


def asscache(nblocks, bsize, addresses, verbose=False):
    cache = []
    hit, miss = 0, 0
    for addr in addresses:
        tag = addr // (bsize * 4)
        if tag in cache:
            c = cache.pop(0)
            cache.append(c)
            hit += 1
        else:
            if len(cache) >= nblocks:
                cache.pop(0)
            cache.append(tag)
            miss += 1
    return hit, miss


if __name__ == "__main__":
    import os
    global verbose
    nblocks = int(os.environ.get("NBLOCKS", 8))
    bsize = int(os.environ.get("BSIZE", 4))
    ssize = int(os.environ.get("SSIZE", 2))
    verbose = bool(os.environ.get("VERBOSE", False))

    with open(sys.argv[1]) as f:
        f.readline()
        idx = int(f.readline()) + 1
    data = [int(n, 16) for n in open(sys.argv[2])]
    hdir, mdir = dircache(nblocks, bsize, data, verbose)
    hass, mass = asscache(nblocks, bsize, data, verbose)
    ha2d, ma2d = a2dcache(nblocks, ssize, bsize, data, verbose)
    print(f"Dir: {hdir}/{mdir}; Ass: {hass}/{mass}; AssDir; {ha2d}/{ma2d}")
    R = hdir / (hdir + mdir), ha2d / (ha2d + ma2d), hass / (hass + mass)
    if R.index(max(R)) == idx:
        sys.exit(0)
    else:
        sys.exit(5)
