The circular buffer idea is how I had thought it was done.
In construct you would just have arrays with moves and one array with the current move.
Have a current index go through the current array and when comparing the moves array to the current array, start from the beginning of the moves array and from the current index in the current array, going all the way to the end, then another loop that goes from the start of the current array to just before the current index (thus scanning the whole buffer).
Each time a button or direction is registered, it's stuffed in the current move array and the index is moved. If the index goes out of bounds, it wraps around.
You could optimize this by having a separate indexer for the moves array, but that doesn't become really useful until you have a huge number of moves (like... 3 digits).
Oh and for timing, it would be better to timestamp each buffer entry. Then you could compare if the difference with the previous parsed move's timestamp fits within the move's allowed range and there you have timing.
You also could add parameters to each move, such as current distance to closest enemy to increase move variety without making them too difficult to perform.