This is possible because the engine is much more open than in video games, for example, and because it is relatively simple: an at-bat is determined by two rolls of a 20-sided die, one for the pitch and one for the swing. Therefore, we have a total of 20x20 = 400 possible outcomes of an at-bat between a given batter and a pitcher. By figuring out every possible outcome, we can calculate expected stats for that at-bat.
I designed a simple tool in Google Sheets that will do this calculation and calculate some of the basic hitting stats. I included a link to the tool at the bottom of this blog.
The tool has three parts, each on their own sheet: