So, the thing about all these principles is that they aren't just there so that code would have certain aesthetic appeal - they have a practical purpose. In particular, they are concerned making code maintainable, and with making it possible to change, extend or replace parts of it without too much hassle. Now, the SRP is about having your classes "do one thing", because if they do more then "one thing", then the code doing these different things will most likely become coupled in subtle ways, and as a result become resilient to change - in the sense that it will be difficult to change these parts separately. Which means you can't really tell what the separate responsibilities are just by looking at what classes and behaviors you have to implement (at best, you can make some educated guesses, but this requires experience).
Instead, you have to try and understand what's most likely to change and in what ways - and you will most likely not get this right on the first try, even if you have experience. Your code is a software model (a representation) of this logical concept that is the system you are trying to build (the concept that includes all the real-world forces that may affect what that system is, and how it will change), and what OO design is trying to do is capture what the different parts of that system are, in what ways will the system change, and how to put these different components together to accommodate all that. And there are always multiple ways to model such a system; some ways will work better then others in practice. It's you (or your team) who has to define what "single thing" or "single responsibility" means for the system you are trying to build and maintain (as well as how much work is not "too much hassle").
That said, there are often things that change at the method level and class level as we develop the code, as we're trying to figure out how to implement some functionality. So it's good to apply SRP and other principles somewhat preemptively at this level to the subproblem we're solving, especially because at this scope we can better predict what we may want to separate, or where we may want to change the implementation later. Similarly when it comes to closely related classes. So, at that level, since these are more or less the kinds of programming problems we are all familiar with, we can tentatively talk about SRP being violated or not, but at the system level, it requires a deeper understanding of the requirements and the system itself, as modeled. At that level, it's also important not to overdesign the system up front.
But, back to your particular case; generally, it seems like a good idea to separate these out. Now, you may have another class (like your
AI) that uses the others - its responsibility would be to coordinate what the other classes do. Just don't move the code from these other classes to the
AI class - keep each peace of code in a separate place, and let each do its own work. It's a hierarchy of responsibilities, in some sense.
Finally, the fact that you are doing this for practice, for the purpose of trying to understand the OOP principles, means, on one hand, that you have some freedom to explore, but on the other, that you won't get change requests and bug reports from clients that will ultimately be the test of how appropriate your design choices were. So try to compensate for that in some way. Take your current design and study it. When you design your classes in a certain way, it's always a tradeoff of some sort: maintainability vs complexity, performance vs clarity, modularity in some ways vs rigid structure in others, etc. Try to understand which parts of your code have become easier to change, and which have become harder. Try to change the implementation to test if your understanding is correct. Then try to come up with a different design and study it. What changed? What did you gain, and what did you loose? This will help you to understand the reasoning behind SRP and other principles, which is what really matters.