what i do is have a module game that contains all the important variables of the game, and return the methods needed to access or modify them.
about your play() factory function
maybe the problem is that you cant use the garbage colector. When a function, variable or object isnt referencied in the code the garbage collector takes care of it deleting it.
But inside of your play() factory function you asign an eventListener the play() factory function is always referencied.
When you call another time play, it adds eventListeners to the element that already have eventListeners. Adding multiple eventListeners with the same name is posible, so you elements reference the first and the second factory function, so the garbage collector cant delete the first object play() returned.
Also if the function is running you the garbage colector doesnt work, and pressing the button counts as calling another function.
I supose the factory function mission is only define methods and variables to return them.
This is because you can do
let factory= play();
and the next time you run this line factory will be a new object and the proevios goes to the gabage collectior. If play is runing some code when you call this line probably the garbage collector won’t work.
If any part of this is confusing or isnt what you are searching ask again.
Hope this will help.