Front Office Football Central  

Go Back   Front Office Football Central > Main Forums > Dynasty Reports
Register FAQ Members List Calendar Mark Forums Read Statistics

Reply
 
Thread Tools
Old 07-20-2014, 09:32 PM   #1
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Groundhog learns Python - Road to a Basketball Text Sim

For the longest time I’ve wanted to learn a programming language. Years ago I played around a little with VB6, but I struggled for a few reasons – the biggest was probably the fact that the ‘visual’ nature of VB6 had me so worried about creating pretty forms that I didn’t spend enough time actually learning the fundamental concepts of programming languages. This time around I’ve gone with Python as it’s free and has a lot of learning resources online.

And what better way to teach myself a language than to try and create a complex sports sim, right???

Although I have a grand/maybe-unrealistic vision of a web-based, multiplayer-focused basketball simulator, initially I’m looking to just put together a piece of code that simulates a game of basketball between two teams. Before that though, there’s the small matter of learning how to program!

This thread will chroncile my attempts to learn Python, as well as my attempts to convert that knowledge into the practical side of making a basketball sim.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce


Last edited by Groundhog : 07-21-2014 at 01:24 AM.
Groundhog is offline   Reply With Quote
Old 07-20-2014, 11:06 PM   #2
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
The Basics

The first resource I picked up was 'Learn Python in 24 Hours'. I made it through the basics - variables, variable types, performing calculations, if/elif/else statements - with ease. I remembered enough from my brief VB6 attempts to make these early chapters more of a lesson in Python-specific syntax.

Lists/dictionaries/tuples were next and, while also quite basic, keeping my basketball sim in mind these represented the first real useful bits of knowledge re: how I envision my sim would work. Of course, every time I think that, I go on to discover a better way to do things, but that's the whole point of starting from the basics!

I had wondered about the whole issue of pulling in user/team/coach info and ratings and assigning them to variables that could be used in PbP/functions etc. It seems so basic, but until I'd seen dictionaries I didn't know how I might achieve that.

At this point, it seems to make sense to have a dictionary created for each team, with a unique ID for each player as the key, and then a list attached to that key holding the various ratings etc.

I have no idea at this stage how I would go about pulling in that information from a database or file and building the dictionaries automatically, but it's a start!
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-20-2014, 11:22 PM   #3
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
While and For Loops

While and For Loops mark the next useful piece of information as far as envisioning a sim-type program, as opposed to a "run a bunch of lines and exit" type programs I'd been looking at in the text book examples.

I remembered loops from VB6, and prior to the reading the chapter I knew they'd be fundamental to the sim. I imagine the main "engine" of the sim would be a loop that first reads the various game variables like time on the clock, which quarter it is, type of possession (jump ball, steal in the back court, etc.), etc. - probably many more. Based on these variables the sim would launch a function or maybe even another nested loop to generate a possession, or if the game is over, to end the loop and output results/stats etc.

I don't want to get too stuck on any specific method at this point though as I still have a lot to learn.

It's at also at this point that I'm beginning to find the Sams book less useful. Brevity and lots of code examples is the books chosen method, and although it's still easy to follow at this stage, we're about to delve into some core object-orientated programming concepts. For someone with no real exposure to this previously (like me), more detail would work better.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-21-2014, 01:46 AM   #4
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Playing with Python - Opening Tip

After a couple of hours I theory, I like to give myself a break and try and create something based on what I know, to see if I really understand what I've been reading. It's one thing that make a quick little program that calculates the average of a range of numbers, but trying to apply what you've learnt to a real problem is much more useful.

So, the opening jumpball. This should be the single easiest aspect of the sim as far as on-court stuff goes. You have a situation where two players compete to gain possession of the ball to begin the game. There are no pre-play conditions to take into account other than who is jumping from each team and that it's the first possession of the game.

First Problem: Who is in the jump?
Most sims have this as being the C position for both teams. Often that is the case IRL, but not always. From what I observe, it's typically the best of the PFs and Cs, rarely other positions. There are exceptions to this, but it does not seem to be a situation that coaches strategise over like other aspects of the game, for a number of reasons. I'd like my sim to pick the most suitable jumper from the starting PFs and Cs.

Second Problem: Ratings?
Simply, height and jumping ability. I like a FM-style 1-20 rating system as I think it gives enough spread to cover lower-grade competitions right up to world-class. Although a 1-100 system is most common, I've always found it too granular - playing a guy with an 84 in three point ability over a guy with 81 just feels too spreadsheety to me. 1-20 also ties with the "d20" type system I have been toying with to determine contests between individuals - like hustle rebounds, charges vs blocks on drives, etc.

I had considered something like 'reach' as a rating that would be a modifier for various actions in the game, with a 10/20 basically meaning normal wingspan for a player's height. It's something that I'd probably include in the "final product".

Theory
First step is to work out how good the PFs and Cs of each team are at jumpballs. The players heights and jumping ability are added together (heights are stored as integers that treat 0 foot 1 inch as "1", and then count upwards, so 6'6 would be 78). The higher of the two frontcourt players for each team is deemed the best jumper, and variables are populated with their name and ratings to be used in the calculation for the tip. If it's a tie, it defaults to the C position.

Sticking with the d20 idea, the actual jumpball competition would be a random d20 result with the difference between the two players' height+jump ratings used as a modifier for that roll. Winning team gains possession, and on a tie, a random result is chosen. I'd like it to be clear in the PbP for all actions like this how the roll went - ie. if it's a tie, the text should be different to indicate a close result. Not as critical in a jumpball, but in other situations I think it would add some flavour to the sim.

Up next: the code...
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-21-2014, 08:18 AM   #5
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
...or not.

I had a lot of trouble pulling individual list items out of dictionaries - it just didn't seem to be the right way to go about it. I found some info online, but for something that must be a very common part of most programs, there had to be an easier way to do this.

Instead of cheating and creating individual variables for each rating, I would instead read on to the next chapter and find my solution: the mystical realm of "classes".

This is where the book really began to fail me. I read the chapter multiple times but I still didn't feel like I had a grasp on what a class actually is. What separates it from a function? It seems obvious now, but it took a few google searches for me to grasp the concept, and suddenly everything became much clearer.

THIS is how you would store attributes for a player and then recall them as required. Although I don't yet know how, it also seems like it would be quite simple to pull these attributes from a database or file.

So I created a simple class that would be used to store player information:

Code:
class Player(object): def __init__(self, playerid, name, height, jump): self.playerid = playerid self.name = name self.height = height self.jump = jump

This allows me to re-use this class as I keep going and add more attributes as required.

I then create a class to pull in the team information too - not really needed for this, but seemed simple enough and would make a neat little touch to the play-by-play:

Code:
class Team(object): def __init__(self, location, city, name, record, arena): self.location = location self.city = city self.name = name self.record = record self.arena = arena

Then I populate the classes with player and team attributes:
Code:
HomeTeam = Team(1, "Cleveland", "Cavaliers", "25-11", "Quicken Loans Arena") AwayTeam = Team(2, "Charlotte", "Hornets", "17-16", "Time Warner Cable Arena") PlayerHome5 = Player(1, "A. Varejao", 70, 10) PlayerHome4 = Player(2, "T. Thompson", 68, 12) PlayerAway5 = Player(14, "A. Jefferson", 70, 7) PlayerAway4 = Player(15, "N. Vonleh", 69, 13)

This allows me to easily call any attribute by using PlayerAway5.height for example to then pass these values on to functions etc.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 07-21-2014 at 08:20 AM.
Groundhog is offline   Reply With Quote
Old 07-21-2014, 08:37 AM   #6
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
My next problem was something called scope - which I am still getting my head around. I wrote a function that calculated the top jumper for each side and assigned it to a variable. The problem was that, after the function finishes, that variable is lost to me and I couldn't access it again.

One way around it was to use the 'global' statement as I did below. I was positive that that was not the best way to do this. I don't know a great deal about OOP, but I know that keeping objects separate and independent of each other is the fundamental 'best practice', and I think this approach violates that. Then I discovered the 'return' statement, which seems the better workaround.

I apologize in advance to anyone with any kind of programming experience as I'm sure the following is probably the least efficient way possible to generate these calculations:

Code:
def TopJumper(home_5_jump, home_5_hgt, home_4_jump, home_4_hgt, away_5_jump, away_5_hgt, away_4_jump, away_4_hgt): home_5_jump_abl = (home_5_jump + home_5_hgt) home_4_jump_abl = (home_4_jump + home_4_hgt) away_5_jump_abl = (away_5_jump + away_5_hgt) away_4_jump_abl = (away_4_jump + away_4_hgt) #global hometopjumper #global awaytopjumper if home_5_jump_abl > home_4_jump_abl: hometopjumper = "PlayerHome5" elif home_4_jump_abl > home_5_jump_abl: hometopjumper = "PlayerHome4" else: hometopjumper = "PlayerHome5" if away_5_jump_abl > away_4_jump_abl: awaytopjumper = "PlayerAway5" elif away_4_jump_abl > away_5_jump_abl: awaytopjumper = "PlayerAway4" else: awaytopjumper = "PlayerAway5" return hometopjumper, awaytopjumper

I then run the function, feeding into it the attributes stored in my player classes earlier, which gives me a variable named TopJumperResults with the best jumper for the home and road team:

Code:
TopJumperResults = TopJumper(PlayerHome5.jump, PlayerHome5.height, PlayerHome4.jump, PlayerHome4.height, PlayerAway5.jump, PlayerAway5.height, PlayerAway4.jump, PlayerAway4.height)

Now, to have them square off...
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 07-21-2014 at 08:38 AM.
Groundhog is offline   Reply With Quote
Old 07-21-2014, 01:26 PM   #7
SirBlurton
High School Varsity
 
Join Date: Feb 2007
Just wanted to chime in and say I'll be watching with great interest....a little embarrassed that you've seemingly done in one day what's taken me years to learn!

I am an absolute beginner in python, so take this with a grain of salt - but what I've done in some of my tinkering has been to collect players in a list (ie-homeTeam contains all of the player objects for the home team).

Just makes it a bit cleaner when managing the function call.
For example:
def TopJumper(homeTeam,awayTeam)...

You could then loop through those lists to find the players with the best jumping ability.

Anyway, very cool to see this on the forum! Good luck!
SirBlurton is offline   Reply With Quote
Old 07-21-2014, 02:24 PM   #8
GoldenEagle
Grizzled Veteran
 
Join Date: Dec 2002
Location: Little Rock, AR
Quote:
Originally Posted by SirBlurton View Post
Just wanted to chime in and say I'll be watching with great interest....a little embarrassed that you've seemingly done in one day what's taken me years to learn!

I am an absolute beginner in python, so take this with a grain of salt - but what I've done in some of my tinkering has been to collect players in a list (ie-homeTeam contains all of the player objects for the home team).

Just makes it a bit cleaner when managing the function call.
For example:
def TopJumper(homeTeam,awayTeam)...

You could then loop through those lists to find the players with the best jumping ability.

Anyway, very cool to see this on the forum! Good luck!

I haven't looked at Python in quite awhile and I just scanned through the problem but there is almost certainly a faster way to do this. Off the top of my head, you can just call a sort method on the list.

Remember that anytime you use a data structure, someone has already gone through the work of thinking about the fastest way to do things via algorithms.

But your suggestion is excellent to make the code more compact, which is critical for maintaining the code. A good philosophy to remember is DRY. Don't repeat yourself. Anytime you find yourself basically copying and pasting in programming, there is a better way to do it.

Anyways, cool thread. I will try to remember to follow long.
__________________
Xbox 360 Gamer Tag: GoldenEagle014
GoldenEagle is offline   Reply With Quote
Old 07-21-2014, 09:01 PM   #9
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Thanks for the responses guys. The first couple of posts covered a couple of days real time, so I didn't find it quite so simple.

I'll post the final part of what I came up with when I get a chance, but thanks for the tip re: sorts and lists. I'll investigate further!
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-24-2014, 12:02 AM   #10
nol
Banned
 
Join Date: Oct 2003
Haven't ventured over to the dynasties for quite some time, but I'll be following this one closely. Very cool!
nol is offline   Reply With Quote
Old 07-24-2014, 01:13 AM   #11
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Thanks!

I typed up a few posts offline, this weekend I should have some more updates.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-24-2014, 11:19 AM   #12
korme
Go Reds
 
Join Date: May 2001
Location: Bloodbuzz Ohio
Reading along and rooting for you, Groundhog.
korme is offline   Reply With Quote
Old 07-25-2014, 10:23 PM   #13
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Quote:
Originally Posted by SirBlurton View Post
I am an absolute beginner in python, so take this with a grain of salt - but what I've done in some of my tinkering has been to collect players in a list (ie-homeTeam contains all of the player objects for the home team).

Just makes it a bit cleaner when managing the function call.
For example:
def TopJumper(homeTeam,awayTeam)...

You could then loop through those lists to find the players with the best jumping ability.

Although I don't know yet how I would sort and loop through lists to automate this, this gave me the idea to fix a problem. What I had above was a function that determined who the best jumper was and returned those values in a variable. To run the actual jumpball I'd need to pass those variables and all the player ratings again to the next function and so on... Passing information between objects is something I need to work on.

What I did was create a list within the Team and Player classes, that builds a list from all the attributes that are stored in the class. I'm sure there's a better way to do this, but for now I manually enter them in as variables. To allow me to iterate through the created list, I had to define another function in the class. Team class is now as follows:

Code:
class Team(object): def __init__(self, location, city, name, record, arena): self.location = location self.city = city self.name = name self.record = record self.arena = arena self.list = [location, city, name, record, arena] #new list item def __getitem__(self,index): #magic that I don't understand, but it works. return self.list[index]

I don't quite understand how 'def __getitem__' works, but hey, Thanks Google! I can now pass a list of all attributes of a class through to a function by using, for example, the HomeTeam.list argument!

I don't think it makes sense either to have two separate functions to determine the best jumper and then the actual jumpball, so I combined them both in to one, using the lists created in the classes as follows.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 07-25-2014 at 10:25 PM.
Groundhog is offline   Reply With Quote
Old 07-25-2014, 11:53 PM   #14
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Code:
def jumpball(PlayerHome5, PlayerHome4, PlayerAway5, PlayerAway4, HomeTeam, AwayTeam): #Determine best jumper for both sides. My 1st attempt to make this #more clever didn't work: #home5jumpabl = sum(PlayerHome5[2:3]) #home4jumpabl = sum(PlayerHome4[2:3]) #away5jumpabl = sum(PlayerAway5[2:3]) #away4jumpabl = sum(PlayerAway4[2:3]) home5jumpabl = PlayerHome5[2] + PlayerHome5[3] home4jumpabl = PlayerHome4[2] + PlayerHome4[3] away5jumpabl = PlayerAway5[2] + PlayerAway5[3] away4jumpabl = PlayerAway4[2] + PlayerAway4[3] if home5jumpabl > home4jumpabl: homejumper = [PlayerHome5[1], home5jumpabl] elif home4jumpabl > home5jumpabl: homejumper = [PlayerHome4[1], home4jumpabl] else: homejumper = [PlayerHome5[1], home5jumpabl] if away5jumpabl > away4jumpabl: awayjumper = [PlayerAway5[1], away5jumpabl] elif away4jumpabl > away5jumpabl: awayjumper = [PlayerAway4[1], away4jumpabl] else: awayjumper = [PlayerAway5[1], away5jumpabl] #Jumpball calculations: homeplayerd20 = randrange(1,20) + homejumper[1] awayplayerd20 = randrange(1,20) + awayjumper[1] randomresult = 0 if homeplayerd20 > awayplayerd20: winner = [homejumper[0], HomeTeam[1], HomeTeam[2]] #this is where the other gamestate variables would be set. elif awayplayerd20 > homeplayerd20: winner = [awayjumper[0], AwayTeam[1], AwayTeam[2]] #as above - gamestate variables. else: randomresult = randrange(1,2) if randomresult == 2: winner = [AwayTeam[1], AwayTeam[2]] else: winner = [HomeTeam[1], HomeTeam[2]] #as above - gamestate variables. #Jumpball Commentary print "Welcome to {}, where tonight the {} {} are set to square off against the visiting {} {}.".format(HomeTeam[4], HomeTeam[1], HomeTeam[2], AwayTeam[1], AwayTeam[2], AwayTeam[2]) print "{} and {} are in the middle for the opening tip.".format(homejumper[0],awayjumper[0]) print "The ball is up..." if randomresult != 0: print "Both players get a hand to it, but the {} {} come up with possession.".format(winner[0],winner[1]) else: print "{} wins the tip, {} {} with the ball.".format(winner[0], winner[1], winner[2])

Running this from the Python shell returns:

Code:
>>> jumpball(PlayerHome5.list, PlayerHome4.list, PlayerAway5.list, PlayerAway4.list, HomeTeam, AwayTeam) Welcome to Quicken Loans Arena, where tonight the Cleveland Cavaliers are set to square off against the visiting Charlotte Hornets. A. Varejao and N. Vonleh are in the middle for the opening tip. The ball is up... A. Varejao wins the tip, Cleveland Cavaliers with the ball.

Woo hoo! Success! I took it out of the code above, but I was printing all the variables initially to confirm things were working as I expected them to. So there we have it, a simulated jump ball! I can already see a few ways to cut down on the amount of variables and lines of code I used above, but I was more keen to show I could make it work rather than make it work the most efficient way possible. Now, back to theory...
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 07-25-2014 at 11:56 PM.
Groundhog is offline   Reply With Quote
Old 07-26-2014, 05:32 PM   #15
Young Drachma
Dark Cloud
 
Join Date: Apr 2001
Ok this is awesome and inspiring. Keep it up.
__________________
Current dynasty: OOTP25 Blitz: RTS meets Moneyball | OOTP Mod: GM Excel Competitive Balance Tax/Revenue Sharing Calc | FBCB Mods on Github
Young Drachma is online now   Reply With Quote
Old 07-26-2014, 06:14 PM   #16
aston217
College Prospect
 
Join Date: Sep 2010
Awesome thread, keep up the work!
__________________
OSFL (join us!) CFL
Float likeabutterflysting likeabee.


aston217 is offline   Reply With Quote
Old 07-27-2014, 05:43 AM   #17
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
More Python Theory

Having finished the 'Python in 24 hours' book, I'd rate it a mediocre 2.5/5. It was an easy read for the fundamentals, but too often I found myself having to google after finishing a chapter to get a better explanation of the concepts it was trying to teach. I did find the very brief chapter on Developing for the Web with Flask to be interesting as far as my long-term goals go, and the SQL chapters were also pretty useful.

I moved on to an online course at Udemy - 'The Ultimate Python Programming Tutorial'. A series of short video tutorials, this has been a much better resource for me. I'm about 65% through and although it's covered a lot of the same ground as the book thus far, I've found it much easier to follow.

The lessons on functions and loops have given me an early idea on how the sim might actually function.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-27-2014, 06:17 AM   #18
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Initial Sim Concept

The sim itself would be a loop that continues to run until the game is over. That's the easy part. There are a collection of variables that are checked each time the loop is run - team with possession, type of possession, game situation, etc. - that then fire functions based on those conditions. These functions would be things like inbound plays, halfcourt sets, free throws etc. They would write commentary to a file, keep stats, etc.

The first issue I see with doing it that way would be the amount of info I need to pass between the main program and the individual functions. Each time a play is run, for example, I'd need to pass just about every variable containing player and team information through to each function every time it fires, and then once the function is finished a lot of data will need to be sent back too - stats being the prime example. Using global variables would cut back on some of this, although I'm trying to avoid using too global variables if I can. The advantage to this method would be that the main program would be more compact.

The other method would be reserving functions just for the calculations - for example, to use the jump ball experiment above, the loop would run and check the variable that calls for the opening tip. An 'If' statement then fires and runs the actual play, including the jumpball function. The function would simply return a couple of values to indicate who was in the jump and who won, and the main program then uses the values to build the commentary and adjusts any stats as required (none, in this case), as well as set the variables that will trigger the next event - a possession for the winning team.

The advantage would be less information being passed between the main program and the numerous functions. The main disadvantage is that the program is going to get very long, very fast!

Maybe I'm way off and there's a better way to do it that I don't know yet, but right now I'm leaning towards option #2.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 07-27-2014 at 06:28 AM.
Groundhog is offline   Reply With Quote
Old 07-27-2014, 07:57 PM   #19
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Proof of Concept - Running a Play

I decided to put my theory behind how an actual possession would work to the test, and put together a quick proof of concept for a possession. The theory would be that each play would be a loop. A variable would be used to progress through the play, with each step pointing to the next step that would be called... In the following example I use the 'o' variable to keep the play alive, and the 'i' variable to point the play at the next step each time the loop runs.

This is a simple play that sees the C set a high pick for the PG who, if the screen is a success, will either shoot, pass, or drive:

Code:
import random o = 0 i = "" while o != 1: if i == "": #first step of the play #offensive player's positions on the court set. print "5 man moves to set a high screen for the 1" #subtract time from game clock and shot clocks. i = 1 elif i == 1: #second step of the play #offensive player's positions on the court set. #calculate the success of the screen and/or any fouls. screensuccess = random.randrange(0,2) #subtract time from game clock and shot clocks. if screensuccess == 0: print "5 man sets a bad screen." i = 99 #set a game-state variable that would mean the next possession #is a 'broken play' with the ball in the PG's hands. else: print "1 runs off the pick by 5 man" i = 2 elif i == 2: #third step of the play #offensive player's positions on the court set. #check for turnover by ballhandler. #determine if ball handler goes to the basket, shoots, or passes. #subtract time from game clock and shot clocks. pgdecision = random.randrange(0,3) if pgdecision == 0: #final step of play. #offensive player's positions on the court set. #check for turnover by ballhandler. #subtract time from game clock and shot clocks. print "1 drives to the basket." i = 99 #set a game-state variable that would mean the next possession #is a drive by the current ballhandler. elif pgdecision == 1: #final step of play. #offensive player's positions on the court set. #check for turnover by ballhandler. #subtract time from game clock and shot clocks. print "1 pulls up for the long jumper" i = 99 #set a game-state variable that would mean the next possession #is a jumpshot by the ballhandler. elif pgdecision == 2: #final step of play. #offensive player's positions on the court set. #check for turnover by ballhandler. #subtract time from game clock and shot clocks. print "1 passes to a teammate" i = 99 #set a game-state variable that would mean the next possession #is a 'broken play'. elif i == 99: o = 1 i = ""

The end result:
Code:
5 man moves to set a high screen for the 1 1 runs off the pick by 5 man 1 pulls up for the long jumper

I run it a bunch of times to make sure the results are random, and it looks good! Obviously there would be a lot more complexity involved in the final version - ie. not straight random decisions, but based on tactics and attributes. But it's a start.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-27-2014, 08:01 PM   #20
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
If you'd like to test for yourself: Execute Python Script Online

Paste the above code directly in there and click 'Execute script'.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-28-2014, 01:39 AM   #21
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
I started work on a function to decide the outcome of the screen in my play above. As a screen is a fundamental part of many plays, the screen function could be used in this simple pick and roll play, or could be called during a longer set play, like a Triangle for example, which would then decide which step the play moves to.

One concept I'd like to build into my sim is that of good plays and bad plays. For example, a player runs off a screen, and the defender goes under the screen, leaving the ball handler with some space. The player has options here - he could shoot the long jump shot, try to drive past the sagging defender, or pass the ball. The sim should be able to look at a player's attributes and determine the best option, and then whether the player follows that option. An offensive awareness rating would be used to check this.

Down the other end of the court, the defensive awareness rating would apply in a similar fashion. The coach would decide defensive settings for each opponent on the court - depending on a coach's attributes, he may have a set philosophy that is applied to all players, or individual assignments for each. If the coach has decided that the "right play" for defending a particular player with the screen is to go under, the player's defensive awareness rating checks whether he acts as he was supposed to. Mistakes like this could be tracked against a player, and lead to coaches subbing off guys who continue to get it wrong. The settings chosen by the coach as "good plays" on this end of the court might not neccessarily be the optimal settings - that's where the coach's attributes would come into play.

It's all good and well calculating this, but it really should be in the PbP too. If a guy makes a bad decision, it should be clear in the PbP. If a guy gets yanked for making 3 or 4 mistakes, we fire up the RageSub function to get some commentary about the coach giving it to him on the sideline.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 07-29-2014, 07:51 PM   #22
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
I made a lot of progress the past few days. I started with the screen in my play above - a simple high screen from the C for the PG. What could happen on a play like this, before the point where we've even decided what the PG does next?

1) Defender commits a foul fighting through the screen.
2) Illegal/moving screen from the C.

Then I thought about how to test each of these conditions. For #1 I set a percentage of this occuring - just plucked a figure of 5% out of the air - and then took the opposing PG's foul rating, which is a rating of 1-20, and 'rolled a d20'. If the result equals or beats the foul rating, an extra 5% is added on top. These are all just arbitary figures at this stage that would need to be tweaked.

For 2 I do something similar, using the offensive awareness rating of the screener as a modifier, along with the defensive awareness of the defender.

If no fouls are triggered by either player, we progress with the actual screen. For the offense some of the factors I want to simulate are the quality of the screen, the use of that screen by the ballhandler (some guards are much better than others in this area IRL), and the creativity of the ballhandler. For the defense it's mainly about reacting to the ballhandler, as well as applying the team strategy - going under screens on fast players who can't shoot, over for good shooters, etc.

Although it's fairly complicated calculating all of the above, the advantage is that once I'm happy with it, I have a function named 'screen' that I can call whenever a screen is required from any play. I feed the required attributes - ball handler, the screener, the defender, team strategy - to the function, and it will give me a result that can then be used to determine the next step of the play.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-01-2014, 12:28 AM   #23
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
High 1-5 Pick and Roll


Above is first play I'm attempting to model, a simple high pick and roll with the 1 and 5 man. The first thing I did was map out the play sequence, as well as the different options that it can branch into. Each step of the play has calculations that determine the next step, as well as situations like turnover & foul opportunities.

The halfcourt is broken down into 14 logical slices - the standard sections you see on a shot chart - and the sim keeps track of player's positions on the floor each step on offense. It may seem like overkill for a text sim, but I think it will prove handy later, and opens up the possibilities of including things like shot charts, play diagrams etc. down the track........... much, much later down the track.

On defense I'm currently plotting out the play assuming man defense, but I have a good idea how zone will work, with defenders being responsible for an area of the court (using the same slices as above). I've also made it easy to assign defenders to specific players rather than matched with the same position for when I get to working on strategy.

For the actual play, despite being pretty simple, there are still a total of 6 scoring possibilities from the play itself - a 3pt/long 2 from the PG off the screen, a drive from the PG off the screen, a corner three from the 2, a baseline jumpshot for the 4, the rolling 5 cutting to the basket, and finally the 4 man cutting to the FT line for a possible jumpshot.

There are also multiple opportunities for fouls, turnovers, and "broken play" situations.

Right now I have each step of the play coded and running with (very) simple commentary being generated, more just to show me that it's flowing correctly. About half the choices being made are still purely random. My goal this weekend is to have every choice generated from attributes, and hopefully be able to switch out the man defense for a 2-3 zone.

My goal is to have this one play working completely - ie. complete strategy implemented for both offense and defense. Once I'm happy that the play works entirely as I'd like, I'll feel fairly safe moving on without the fear of needing a massive re-write of everything down the track...
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-02-2014, 03:27 AM   #24
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Some Progress...

Another productive day of (trying to) code! I revamped the intro to give the starting lineups. Simple, but had to write a quick function to translate the heights as they are stored into "English" - for example, 6'9 is stored as 69:

Code:
Welcome to Quicken Loans Arena where the Cleveland Cavaliers (25-11) are up against the visiting Charlotte Hornets (17-16). Starting Lineups: Cleveland Cavaliers: -------------------- C: A. Varejao, 6'11 PF: T. Thompson, 6'9 SF: L. James, 6'8 SG: A. Wiggins, 6'8 PG: K. Irving, 6'3 Charlotte Hornets: -------------------- C: A. Jefferson, 6'10 PF: N. Vonleh, 6'9 SF: L. Stephenson, 6'5 SG: G. Henderson, 6'5 PG: K. Walker, 6'1

Up next is the opening tip, which has changed only slightly from what I posted earlier in the thread - mainly due to the amount of times I've changed from lists to dictionaries for storing and passing around information:

Code:
A. Varejao and N. Vonleh are in the middle for the opening tip. The ball is up. N. Vonleh wins the tip, possession is with Charlotte.

This result now sets Charlotte as the attacking team and Cleveland on defense. I setup a variable, either 0 (home team) or 1 (away) that is relational and used by all functions and calculations to reference the right information for the team on offense and defense. It took me a few days to work out the best way to do this, and resulted (of course) in having to rewrite a bunch of lines, but I'm really happy with how it turned out.

Code:
K. Walker brings the ball up the court for Charlotte. K. Walker has the ball at the top of the arc, and signals the play. A. Jefferson moves up to set the high screen for K. Walker. K. Irving goes under the screen.

For these 4 statements there's a lot of calculations that took place behind the scenes. We checked who was defending Kemba Walker based on the strategy of the team - Cleveland are playing man defense, and Irving is assigned to guard the opposing PG. The screener and defender had a chance of committing a foul. We then checked the screen strategy for Walker, and it's set to go under the screens. We checked his defender (Kyrie) to see if he made the right decision based on that strategy. He did.

That's as far as I've got with the commentary, but the next few steps of the play are also finished.

A few more examples of what can be generated from what I've completed so far:

Code:
A. Varejao and N. Vonleh are in the middle for the opening tip. The ball is up. A. Varejao wins the tip, possession is with Cleveland. K. Irving brings the ball up the court for Cleveland. K. Irving has the ball at the top of the arc, and signals the play. A. Varejao moves up to set the high screen for K. Irving. A. Varejao wipes K. Walker out with a great pick! K. Irving reaches the right side elbow with some space.

Varejao had a quality screen here, which gets Kyrie open off the pick, which will affect the next step of the play, opening up the jumpshot or drive.
Code:
K. Irving brings the ball up the court for Cleveland. K. Irving has the ball at the top of the arc, and signals the play. A. Varejao moves up to set the high screen for K. Irving. A. Varejao is called for the illegal screen on K. Walker.

An offensive foul.

Code:
A. Varejao and N. Vonleh are in the middle for the opening tip. The ball is up. A. Varejao wins the tip, possession is with Cleveland. K. Irving brings the ball up the court for Cleveland. K. Irving has the ball at the top of the arc, and signals the play. A. Varejao moves up to set the high screen for K. Irving. K. Irving moves into the high pick, but K. Walker fights through the screen.

Similar to the quality screen above, this gives Kemba Walker an opportunity to disrupt the play and make a play on the ball in the next step of the play.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 08-02-2014 at 03:29 AM.
Groundhog is offline   Reply With Quote
Old 08-03-2014, 10:41 PM   #25
CraigSca
Pro Starter
 
Join Date: Jul 2001
Location: Not Delaware - hurray!
Groundhog - will be following this and will be rooting you on.

I love programming, but I know I'm not a very good one. Have dabbled in a lot of languages and, like you, focusing on Python now since I can actually use this for work. I've always dreamed of writing a lot if sports simulations (originally baseball, but focusing on college football now since TCY has gone away). Watching you learn the language has been a pleasure - and it reminds me if my early years when programming was pure joy as it was a series of discoveries like the ones you're making. Good luck with this as I will be an avid follower.

As far as Python is concerned - know that almost ANYTHING you're thinking if doing there's either a library or code for it already. Google search exactly what you're trying to do - examples will be out there.

As far as advice - I would also crest a game class whose parameters include the teams and the current state if the game. This way you can cycle through each game in a single loop - allowing you to play all the games for that days schedule concurrently (you can add a start time and a time if day parameter to determine if the game has started or not). Later down the road, but just something to think about.

Also - another thing I've found is all these classes and lists may be better serviced as a database (I've been told mongoDB is a good, free one). You'll be able to search on all data, run calculations, etc. Again, probably not something you want to think about now.

Awesome stuff - good luck!
.
__________________
She loves you, yeah, yeah, yeah, yeah!
She loves you, yeah!
how do you know?
how do you know?

CraigSca is offline   Reply With Quote
Old 08-03-2014, 10:43 PM   #26
nol
Banned
 
Join Date: Oct 2003
Quote:
Originally Posted by Groundhog View Post
I don't quite understand how 'def __getitem__' works, but hey, Thanks Google! I can now pass a list of all attributes of a class through to a function by using, for example, the HomeTeam.list argument

Quote:
Originally Posted by Groundhog View Post
Having finished the 'Python in 24 hours' book, I'd rate it a mediocre 2.5/5. It was an easy read for the fundamentals, but too often I found myself having to google after finishing a chapter to get a better explanation of the concepts it was trying to teach.

Yep, sounds like programming to me
nol is offline   Reply With Quote
Old 08-04-2014, 12:40 AM   #27
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Quote:
Originally Posted by CraigSca View Post
Groundhog - will be following this and will be rooting you on.

I love programming, but I know I'm not a very good one. Have dabbled in a lot of languages and, like you, focusing on Python now since I can actually use this for work. I've always dreamed of writing a lot if sports simulations (originally baseball, but focusing on college football now since TCY has gone away). Watching you learn the language has been a pleasure - and it reminds me if my early years when programming was pure joy as it was a series of discoveries like the ones you're making. Good luck with this as I will be an avid follower.

As far as Python is concerned - know that almost ANYTHING you're thinking if doing there's either a library or code for it already. Google search exactly what you're trying to do - examples will be out there.

As far as advice - I would also crest a game class whose parameters include the teams and the current state if the game. This way you can cycle through each game in a single loop - allowing you to play all the games for that days schedule concurrently (you can add a start time and a time if day parameter to determine if the game has started or not). Later down the road, but just something to think about.

Also - another thing I've found is all these classes and lists may be better serviced as a database (I've been told mongoDB is a good, free one). You'll be able to search on all data, run calculations, etc. Again, probably not something you want to think about now.

Awesome stuff - good luck!
.

Thanks, glad to have you following along!

In terms of the scheduler I guess that's kind of what I was thinking - it would be a class of team IDs and dates, and when a game is scheduled the two team IDs would be fed into the main sim engine as the primary key reference used to populate all the in-game classes/list/dictionaries etc. It's all very vague in my mind at this stage until I actually try and do it.

Right now I've just typed up the dictionaries, and have created the two NBA teams from above as well as a few teams from lower quality leagues to check the affect of lower rating players competing against similar competition.

Thanks also for the mongoDB tip. I covered Sqllite3 in the "Python in 24 hours" book very briefly, but I really, really hate SQL... maybe mongoDB is a better choice for me!
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-04-2014, 10:02 PM   #28
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
I was looking for a web scraper for work, when I stumbled upon a really good online one that makes the automation of capturing names and other info from a site like Yahoo sports simple.

I setup an automated web scrape to capture the roster info of every division 1 college team roster, which gives me a list of names I could use to generate players, as well as some name-related stats - like the fact that 0.2% of players are a "John Doe, II" (0.08% are a IV), and 1.01% have hyphenated names. I very quickly generated a random hyphenated name, and naturally it came out 'T.J. Williams-Williams'.

About 7-8 years ago I extended the FBCB names list by manually copying and pasting every player from every roster...... The above took me about a minute to setup, and a few hours to run in the background.

Also in the "interesting but not really related to my sim" category, the top 5 most popular jersey numbers in college basketball - 5, 1, 2, 3, 11.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 08-05-2014 at 01:59 AM.
Groundhog is offline   Reply With Quote
Old 08-05-2014, 02:25 AM   #29
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Spent some time last night trying to work out the best way to calculate a few of the steps of my play. If a player comes to help on defense and leaves his man, the ballhandler has to decide to either attack himself, or look for the open man. To make the decision, I use the court location of the offensive player as well as his attributes to determine whether it's a good option to pass to that player.

To use this pick and roll play as an example, if the PG comes off the screen and finds himself open, the defenders of the 2 and 4 man have to decide whether to leave their man to hedge the ballhandler. This decision is based on strategy - there is a hedge setting for each player on the court - vs defensive awareness to see if the player correctly acts on that strategy. If either defender hedges, a check is made on the 3pt ability of the 2 man on offense, and the 4 mans inside ability from the low post to determine the "best" decision - then the players offensive awareness rating is used to determine if he makes the best decision.

I currently have the sim functioning as above, but I'm trying to add some more complexity to it. I'd like the defender to take into account the guy he is defending when deciding to hedge - for example, you probably wouldn't leave Ray Allen to pickup the ballhandler in this situation. I'd also like the ballhandler's decision to not be so simple, because maybe the guy in the corner is a good shooter, but the PG might still be better served using his own abilities to attack.

Again, the advantage to making this as complex as possible is that, once I'm happy with it, I can reuse it every posession that requires similar decisions. It's just getting it right that first time that has me pulling my hair out.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-10-2014, 06:51 PM   #30
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Haven't been a lot of updates the past week because I decided I needed my first and hopefully only major re-do. The issue I had was that I'd stored all the player attributes in a list, which meant referencing them as a number value in the order they were listed.

For example, initially the player information was held as follows:
Code:
[id#, "A. Varejao", 70, 15, 14, 7, 7, 0, etc]
I had a key of what each attribute related to - offaware, 2pt, etc. And when I called the player's rating to use it in a calculation, I would reference it by the order it appears in the list - height would be 'player[2]' for example (counting starts from 0). Although it may not sound overly complicated, once the number of attributes hits the 20 mark it starts to get a bit messy, especially when I'm going back and reading code a few days later.

I wanted to change everything to dictionaries. Dictionaries are a kind of database that allows you to store a value against a key that can be used to reference that value. This makes it a lot easier to read. To use the example above:
Code:
{"name": "A. Varejao", "height": 70, "jump": 9, "offaware": 14, "defaware": 14, etc}
If I'm then passing a value to a calculation, say Varejao's heigh and jump ratings for a jump ball, I'm simply passing 'player["jump"]' and 'player'["height"]'.

Seems simple, but it meant rewriting nearly every function I had put together, which was also a good opportunity to clean up a few things using methods I'd learned since I began.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-10-2014, 07:00 PM   #31
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
I should also add that the actual player information is a dictionary within a dictionary that's within another dictionary... Hence the "kind of database" comment.

The top level of the dictionary is a value for '0' - home team, and '1' - road team. There is a variable that tracks whether the home or road team has possession - 0 or 1 - which is then used to automatically reference either the offense or defense roster and attributes when required.

So to use another example, when the high screen is called by the function, the values sent to the function will looked like:
Code:
rosterdictionary[pos][playerid]["offaware"], rosterdictionary[defteam][playerid]["defaware"]
'pos' is the variable that is either 0 or 1 for possession, and that will point the function to the desired offensive player. 'defteam' is the opposite value of 'pos', and thus points to the defensive roster.

Playerid is calculated using another dictionary which tracks the 5 players on the court for each team. It includes the positions on the court as the keys, and the the id # of the player in that position as the value. Substitutions are a long way out yet, but this is how they will work.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-10-2014, 10:43 PM   #32
BYU 14
Coordinator
 
Join Date: Jun 2002
Location: The scorched Desert
Really cool and impressive with the progress you have made in a short time.

Good luck with this, and when can we pre-order?
BYU 14 is offline   Reply With Quote
Old 08-12-2014, 10:26 AM   #33
Neuqua
Pro Rookie
 
Join Date: Oct 2000
Location: Chicago, Ill
As someone who is also trying to learn Python, this thread is fascinating to me. Best of luck to you!
__________________
Our Deepest fear is not that we are inadequate. Our deepest fear is that we are powerful beyond measure. It is our light, not our darkness that most frightens us. We ask ourselves, 'Who am I to be brilliant, gorgeous, talented, fabulous?' Actually, who are you not to be?
Neuqua is offline   Reply With Quote
Old 08-14-2014, 07:08 PM   #34
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Spent a good 2 hours tracking my first bug last night. It ended up being related to a change I made a few days ago, which was to split all common sequences like screen calculations (success, fouls, etc.), shots, passes, etc. - basically things that will occur in a majority of plays - into their own sections of my sim's loop. This means I need to code them exactly once, and then direct the loop to that sequence when required. I do this using two variables, one is "gamestate" which is a sequence of decimal numbers that is used to point the loop to the correct segment of code. Whenever the loop is sent to one of these other sequences, a variable named "returnstate" is used to point the loop back to the next sequence of the play.

A non-code example of how the loop looks:
Code:
Loop 1.0 - jump ball run jump, set possession ... 50.0 - pick n roll send loop to "101.1" to set common variables for the play then point it to return. actions a, b 50.1 - pick n roll actions c, d send loop to "103.1" for screen and point it to return. ... 101.1 - common variables generate possession-specific variables, then return to play. 103.1 - action the screen/calc fouls calculate screen results, then return loop to pick n roll.
The bug was to do with a variable named "isopen", which tracks whether the ballhandler is open during the each step of the play. I set the defensive strategy to go under screens, which is supposed to lead to the ballhandler being open for one step of the play. This was working fine, but once I split everything out into it's own gamestate "elif" block, the player was open coming off the screen but, if they attempted the 3, the PbP was displaying a contested shot rather than open.

The issue was that I had a small block of code that checked the defender's reaction to the screen (over, under, etc) that then determined the "isopen" value. With all the cutting/pasting I'd gone through the last couple of days, I'd sliced this function in half, which was resetting the value of "isopen" just prior to calculating the shot. This meant that the ball handler was making the decision to shoot based on the fact that they were open, but the shot itself was being calculated as a contested shot.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 08-14-2014 at 07:10 PM.
Groundhog is offline   Reply With Quote
Old 08-14-2014, 07:26 PM   #35
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Quote:
Originally Posted by BYU 14 View Post
Really cool and impressive with the progress you have made in a short time.

Good luck with this, and when can we pre-order?

Thanks, at this rate, 2018.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 08-24-2014, 08:16 PM   #36
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Spent a good 6 hours coding this past weekend, working mainly on the passing logic. A few weeks ago I wrote an elif block that handled the hedge sequence if the PG comes off the screen with space. Basically it determined if the defender of the SG or PF's defenders leave their man, based on the defensive strategy (and whether they follow that strategy), and the PG then decides if he will pass to the open SG or PF if they do - based on the PGs ratings and the PF or SGs skill scoring from the position they are in. The actual pass action was in this elif block too - it could sail out of bounds, be picked off, or make it to the player.

This was great and it all worked as planned, but it was very specific to the one play. Instead, I wanted to build the logic of these two actions into more generic pass and hedge code blocks that could be called whenever they are required for any play.

For this I created an elif block and a function. The function is fed a number of variables about the current possession and uses these to determine if the player receiving the pass is open. It looks at the defensive strategy of the team so if the team is playing man-to-man defense for example, it will check if the ball handler is open and based on the location of that player and the defender, if the defender hedges in to pick up the ballhandler. If the team is playing zone, it uses the pass receiver's position on the court vs the type of zone being played to determine if the player is open. In a zone each defender is assigned different areas of the court to defend, and some slices - the mid-range baselines in the 1-3-1 for example - have a better chance of causing a player to be open than others. The defender's defensive awareness rating gives him a chance to recover to the player.
Anytime a pass action is required, I created an elif block that is called from within the play being run. The play moves the loop to the pass state, actions the pass, and based on the result (turnover, completed pass, etc) will then either return the loop to the play, or action a shot, etc.

If the pass is made to an open player around the basket, there is also a chance of the pass being an alley-oop play. The advantage of this is that it allows for alley-oops to happen outside of the scripted play being run - if a player passes to a guy near the basket who is open, there is a chance that this would be an alley-oop. The sim takes into account the ratings of the passer and the guy near the basket to determine if it's a good decision to throw the alley-oop, as well as the success of the pass and finish.

I also created a settings.ini file which stores some default values that can be tweaked to adjust frequency of things like fouls, open shot attempt %s, blocks, turnovers, alley-oop attempts, etc. Gameplay sliders I guess you could call them! They aren't raw % of events occurring because player ratings factor in as modifiers, but should hopefully allow me to tweak things easier down the track.

Next on my to-do list is an elif block to handle a ballhandler's isolation decision. It will factor in whether the player is open, the defense being faced, and based on the players ratings determine whether they attack the basket, shoot a jumpshot, or pass the ball - basically, it's an isolation play that could be called once a play breaks down, or in a play designed to get a skilled scorer the ball in a particular location. Once that's done, I want to go back and adjust a few calculations against different zone defenses, code a post play elif block, begin work on shot clock/game clocks, and then add stat recording. After that's done, much of the core "basketball" stuff will be coded and creating additional plays for the most part should be fairly straight forward.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 09-08-2014, 03:06 AM   #37
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Quote:
Originally Posted by Groundhog View Post
After that's done, much of the core "basketball" stuff will be coded and creating additional plays for the most part should be fairly straight forward.

Yeah, so, not quite.

The further I got along in my coding, and the more decisions/outcomes I had to come up with, the less happy I got with the direction I was going in.

One of the real drivers for me to make this sim is to develop a strategy-focused sim that simulates a real(ish) game of basketball. I'm a huge fan of Brian's Fastbreak sims and I think they do a great job of generating realistic results and stats. I'm looking to approach it from the other side - a sim that attempts to accurately model a game of basketball. I think the disadvantage to doing it this way is that, the more complex it gets, the harder it's going to be to get realistic results.

From watching a lot of FIBA basketball at the world cup and thinking about it from a sim perspective, I had some more ideas about how I would like my sim to work. Most teams have basic sets they run with a number of options they are specifically looking for, but a lot of the time they make a play based on what the defense gives them - ie. if a team throws a 2-3 zone at them they'll find the three point shot is there if they want it, regardless of what set they are running (often to their own detriment), etc.

Currently my sim has been built very play-specific. Obviously plays and sets will still be an important part of any strategy-focused sim, but I wanted the ability to break from a play at any given moment when a scoring opportunity presents itself.

To do this, I created a function that defines where the defenders are on the court, and another that checks both this as well as the team defensive strategy to determine which offensive players are open.

For the defender's court position, for m2m it's an easy calculation, but for zone - 2-3 and 3-2 only at this stage - I defined where each defender should be relative to the ballhandler as well as what area on the court they are responsible for on the pass. For example, in a 3-2 zone the 4 and 5 man might be covering the low post if the ball is at the top of the key, but on a pass to either corner 3, they would be expected to rotate out and pick up the shooter. The defender's speed and defensive awareness determines if they make it to the player in time to prevent him being flagged as "open", with it being more difficult the further the player is from the shooter - in this case, he would be required to move across 3 zones to reach the shooter.

Each step of a play the sim calculates where the offensive and defensive players are, and if the offensive players are open. Taking into account whether a player off the ball is open, for example against a zone or a defender hedging off his man, the play could break, and a pass be actioned to the open man. The sim takes into account the skill of the player in scoring from the position he is in and determines if it's a good play to make the pass - the offensive awareness rating then determines if the player makes the good or bad play.

Right now this is 50% coded and 50% scribbled onto my notepad, but I'm putting a lot of effort into making this part of the game as "smart" as possible - also taking into account the ease of passing from each point on the court to another - ie. if a guy has the ball in the left corner, it's much more difficult to complete the pass to the opposite corner than it is to dump it inside.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 09-14-2014, 08:25 PM   #38
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
A quick rundown on the work I've been doing re: court positions. Each step of a play, I define where the offensive players are on the court. As I've said above, the half-court is divided into 14 slices, and the below dictionary has the players position as a string - ie. "5" for the C - followed by his location on the court - ie. 6. I use strings for the player positions to make it easier for me to spot them in the code. PG/SG/etc. would've been even easier, but hey, hindsight :
Code:
offpos = {"pos": {"5": 6, "4": 3, "3": 14, "2": 10, "1": 12}}
To work out the defender's location, the sim first checks the defensive strategy, which is also stored in a dictionary, this is an excerpt of the home team's strategy:
Code:
strategydict = {"0": {"strategy": "m2m", "individualstrat": {100014: {"hedge": 0, "screen": 0, "insided": 1, "2ptd": 0, "3ptd": 0}, 100015: {"hedge": 0, "screen": 0, "insided": 1, "2ptd": 1, "3ptd": 0}, 100016: {"hedge": 1, "screen": 0, "insided": 0, "2ptd": 0, "3ptd": 0}, 100017: {"hedge": 1, "screen": 0, "insided": 0, "2ptd": 1, "3ptd": 0}, 100018: {"hedge": 1, "screen": 1, "insided": 0, "2ptd": 1, "3ptd": 1}}, "guard": {"1": "1", "2": "2", "3": "3", "4": "4", "5": "5"}, "threeonly": 0, "focus": 0, "tempo": 0, "autofoul": 0},
"Strategy": "m2m" and, as it's man-to-man, "guard" are the entries that will now dictate the defensive player's positions on the court, which builds the defpos dictionary (basically, identical to offpos above, but with an entry that dictates who is defending the ballhandler). It will then take the "individualstrat" entries - the 100014 are primary keys for the players on the other team - and check each offensive players position on the court and determine whether the player is being left open or guarded based on the "insided"/"2ptd"/"3ptd" entries - the defender's defensive awareness rating is also checked to see if a guy follows the defined strategy or not. An additional "isopen" dictionary is created and (not yet coded) a check will be made each step of a play to see if a pass is made to an open player, which would break from the scripted play.

If a team is playing zone defense it's a bit trickier. The method I came up with was to script the defense's court positions relative to the ballhandler. It took some work, but I'm pretty happy with how it turned out. The sim will check the location of the ball handler, then look that up in a function that returns the defender's position on the court, the player defending the ball, and then for each of the 14 spots on the court it tracks: 1) the player responsible for that location, 2) a secondary player responsible for the position too (for some zones it could be the 4 and 5 in front of the basket, etc.), and 3) how many areas removed from that space is the defender if he has to recover to a pass - ie. in the below example from the 3-2 zone with the ball in position 14 (left corner 3), the 5 man is responsible for the right corner 3 (position 10), but he would be 3 zones removed from that location, making him unlikely to recover to that spot if the ballhandler made a miraculous pass from one corner to the other.
Code:
elif ballpos == 14: {defpos: {"5": 1, "4": 9, "3": 3, "2": 7, "1": 8}, "ballhandler": "4"} {1: ("5", 0, 0), 2: ("5", 0, 1), 3: ("3", 0, 0), 4: ("5", 0, 1), 5: ("5", 0, 2), 6: ("2", 0, 1), 7: ("2", 0, 0), 8: ("1", 0, 0), 9: ("4", 0, 0), 10: ("5", 0, 3), 11: ("2", 0, 1), 12: ("2", 0, 1), 13: ("1", 0, 1), 14: ("4", 0, 1)}
I also didn't want guys throwing unrealistic passes to open players - ie. the example above, a pass from one corner to the other is very difficult. I created another dictionary that again takes a player's position on the court and assigns a rating of 0, 1, 2 to each area on the court with 0 being an easy pass, 1 difficult, and 2 very difficult. This effects both the player's decision to make the pass as well as the success of that pass.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce

Last edited by Groundhog : 09-14-2014 at 08:27 PM.
Groundhog is offline   Reply With Quote
Old 09-29-2014, 03:14 AM   #39
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
I was really dreading learning databases. It's an unescapable fact that I need to get my SQL-fu up to scratch though, as it's going to be a huge part of my sim.

I played around with a few different database types before settling on sqlite. It's free, it's installed already with Python, and it uses the SQL language, which I'd rate my current level of understanding just above "infant".

After a lot of stackoverflow and google searches, I stumbled upon an ebook - SQLite Python tutorial

It was worth the money. After 30 mins of reading I Was creating database tables and inserting/retrieving data. It's very basic stuff I know, but looking a database full of tables for teams/players/countries/coaches etc. populated with data from main engine was the first big "Wow, I can actually do that..." moment I've had.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 10-09-2014, 08:28 PM   #40
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
The last couple of weeks have been another big rewrite, this time purely around loop control. The basic structure of my sim was a whole bunch of "elif" blocks for each action - jump ball, pass, shot, etc. - with each block pointing the loop to the next, so a foul would lead to an inbound, etc. Apart from being messy, it's also harder to troubleshoot and to reuse elif blocks for similar actions.

I closed my text editor down and started mapping out a more structured loop control in excel, and came up something much cleaner. I have a sub-loop to the main game loop which I title the "logic_block". This is just an elif block but it controls the flow of the main game loop. Based on the game situation, which is a sub-loop to the 'logic_block', and this elif block points the loop to the correct action - action_shot_attempt, action_turnover, etc - and tells that action where to go next. What I really like about this layout is that each action is standalone - it just calculates what it needs to, and leaves everything else up to the logic_block. This makes it really easy to re-use these actions in different situations.

It probably doesn't sound exciting, but I'm very happy with how it's turned out.

In more basketball-ey coding, related to my post above, I have finished up the logic around non-structured offense. Every step of a play, the sim will check the offensive and defensive players positions on the court, determine if a guy is open (intentionally or not), his ability to score from where he is, and his location in comparison to the ballhandler to determine pass difficulty. All of these factors make up a "pass value" score from 1 to 4, with 1 being "Shaq open from 3" to 4 being "Shaq open in front of the basket" - ie. a must-pass. A player's offensive awareness determines how many player's pass values are checked, and the higher the value the more chance that the player will break from the scripted offense to make the pass to that player - again, offensive awareness helps aid the right decision here.

I have also put some work into mapping out distances between court positions to help with defensive recovery - if a guy is open with the ball at a particular location, this will be used to determine if the defender is able to recover from his position in time, or if the offensive player will get a chance at an open shot/drive etc. It will also allow for logic around defenders hedging off their man to pick up the ballhandler. Still lots to be done here, but I have a plan on how to implement it.

This is a text sim, but I am putting a lot of effort into tracking player positions on the court and the distance/relation between the areas on the court, because, while it's taken some work, it makes it easier to have "natural" events occur - open shots, backdoor cuts, etc.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 10-09-2014, 10:33 PM   #41
nol
Banned
 
Join Date: Oct 2003
Quote:
Originally Posted by Groundhog View Post
In more basketball-ey coding, related to my post above, I have finished up the logic around non-structured offense. Every step of a play, the sim will check the offensive and defensive players positions on the court, determine if a guy is open (intentionally or not), his ability to score from where he is, and his location in comparison to the ballhandler to determine pass difficulty. All of these factors make up a "pass value" score from 1 to 4, with 1 being "Shaq open from 3" to 4 being "Shaq open in front of the basket" - ie. a must-pass. A player's offensive awareness determines how many player's pass values are checked, and the higher the value the more chance that the player will break from the scripted offense to make the pass to that player - again, offensive awareness helps aid the right decision here.

This is very cool. There was a big Kirk Goldsberry paper that came out a few months ago and it also had some measure for the relative value of passing to each player on the court (or shooting) at each "frame" of the possession. My pet peeve with it was that it didn't take prior actions into account (e.g. that based on the position of everyone on the court, Player X is only "open" for a corner three because the player with the ball is driving baseline in the opposite direction and could only get him the ball with some extremely difficult pass). That's hard to code for, but having that value for awareness (I suppose the FM equivalent would be flair) is definitely key.

Last edited by nol : 10-09-2014 at 10:56 PM.
nol is offline   Reply With Quote
Old 10-10-2014, 12:05 AM   #42
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Yeah, sometimes I think I'm relying on "offensive awareness" for things like the above too much, when maybe something like "flair" or "court vision" might be more specific. The way I have envisioned it though is that off/def awareness bundle these type of court awareness attributes up and are very important - maybe the most important rating in the game. I want the development (or lack of) of these two ratings to end up being a key indicator of young guy's ceilings after a couple of years.

A guy might have strong ratings in other areas and still put up good or great stats, but over the course of a season there will be a lot of good things on the court that won't happen for his team if he has low awareness on either end.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 11-07-2014, 12:30 AM   #43
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Been awhile since I last posted, but I've still been working away. The actual game engine is coming along nicely. I've designed a nice little code block that steps the sim through each step of a play. Each step has court positions for the offense, an attribute that determines roughly how long the step would take to run, and things like screens/passes/cuts etc.

Example:
Code:
{"playid": "quick_1_pnr", "step": 001, "offpos": {"pos": {"1": 12, "2": 14, "3": 10, "4": 4, "5": 12}}, "passtarget": 0, "shottarget": 0, "screen": ("5", "1"), "step_duration": 1, "possession_ballhandler": "1", "cut": (0,0)}
I've edited it a little as it's actually one dictionary entry embedded in a much bigger dictionary, but that should give you a fairly good idea of how it works. It may seem weird that position numbers are strings rather than integers, but it's due to something I coded while still a n00b and I actually like it now because it helps me easily pick numbers that refer to basketball positions as opposed to variable values.

The code block iterates through each value and actions anything required. The coolest thing about this is that, by storing the steps of a play in this format and separately from the main code of the game engine, in theory it opens up the door as far as allowing people to design their own plays. Obviously that's a "long term" thing, but it's something that would be cool to do if I could do it right.

Outside of that, I've been dabbling in other, more long-term, areas of the sim, especially when I get stuck on something or burnt out tracking loop control issues. I've put a lot of work into the generation side of things as far as players and teams go. After a lot of website text scrapping (thank god for rabid football-loving fans worldwide and their wiki site updating skills!) I have name files and country/city files for about 120 countries.

My idea is that you will be able to enable/disable any country's national league. Enabling it will generate a league randomly, at this stage made up of the same number of teams that the country has IRL in it's national league, as well as up to two divisions. It would assign a team to a weighted random city from that country based on population. Turning off a country would mean that there is no national league, but each country would still have a pool of players generated to make up national teams etc. Of course I would also plan on including the ability to manually edit a league to match reality, but I need to figure out how that will work for teams located in cities not included in the initial file - I have a hacky method of weighting the random choices that is quicker than the standard way to do it (given the size of the numbers that make up populations), but does not lend itself to easily allowing a user to simply append a city to a csv file.

On the player side, each country has 3 attributes that directly effects player generation - talent (1-5, from poor to NBA), height(1-short, 2-normal, 3-tall), and athleticism (similar, 1-3). So, for example, USA would be a 533 national, while China might be a 232, Australia a 322, South Korea, Spain a 422, etc. I have coded real early generators for all of the above, but until I'm at the stage where I can start simulating entire games, let alone seasons, it hasn't really been possible to judge how balanced it is.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 11-09-2014, 04:31 AM   #44
LastWhiteSoxFanStanding
College Starter
 
Join Date: Jun 2003
Wanted to let you know I am following with great interest. Keep it up!
LastWhiteSoxFanStanding is offline   Reply With Quote
Old 12-08-2014, 06:18 PM   #45
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
No updates in a while, but I'm still plugging away. On the sim-side of things, it's largely just finishing off event blocks and then tying everything together via loop control to make sure the transitions between events happen as they should. I'm pretty happy with everything I've got coded so far, and I've started forcing myself to K.I.S.S. a number of times, leaving comments of '#TODO: "Insert crazy idea here"' throughout my code for things I can come back and look at trying once I've got more of the sim done. I spent about 4 days working on rebounds - tipped rebounds, FT rebounds, airballs, etc. - when I decided it was probably time to scale it back a bit until I've got more done!

One of the key features of my sim is that it will be very easy to tweak just about every calculation. I have a function called "base10" that sets the chances of an event happening for a player with the rating of 10 for the skill to be tested, and a "base10_mod" to be used as a +/- modifier applied for each point the player is rated over/under a 10. All the base10 percentages and mods are stored in an ini file with the sim pulling in the values each time it runs. This applies for every main calculation - from shooting %, alley-oop pass success, spotting open players, etc.

I did like Nol's 'flair' mention above, which led me to incorporate a court awareness rating in addition to off/def aware. At this stage it's solely related to checking for players via the pass value work I mentioned above.

I've made the switch from sqlite to SQLAlchemy for my database stuff. SQLAlchemy makes database queries more python-esque and, though I haven't yet "mastered" it for the basic stuff I'll be using it for, I find it easier to work with than using SQL statements.

I spent a bit of time the past couple of days working on player generation. I mentioned earlier that each nation has a set of attributes that affect player generation. What I worked on yesterday was generating base values for speed and strenght based on a player's height and weight. Each height has a base set of characteristics, and then a point where penalties/bonuses can apply to speed or strenght attributes following that.

I don't have the actual settings handy, by for example a 6'10 player might default to 245lbs with a rating of 11 for strength and 6 for speed. If the player in question is generated weighing 285lbs, there is a 50% chance his strength will increase and speed will decrease by 1 for each multiple of 10 over a limit - say 260lbs. So in this case there's a chance the 6'10 guy will have a 4 for speed, and 13 for strength. This is all just to create the base ratings of the guy, which would change once a template is layed over his ratings - 'outside shooter', 'rebounder', etc. so there's a chance they could jump/drop further.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 12-08-2014, 10:04 PM   #46
CraigSca
Pro Starter
 
Join Date: Jul 2001
Location: Not Delaware - hurray!
Always love seeing these updates - I'll have to check out SQLAlchemy, never heard of it.

Interesting to hear about your use of templates - in earlier days creating attributes for me was essentially a series of independent variables, which obviously doesn't happen in real life.

Keep it up!
__________________
She loves you, yeah, yeah, yeah, yeah!
She loves you, yeah!
how do you know?
how do you know?

CraigSca is offline   Reply With Quote
Old 12-08-2014, 10:29 PM   #47
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Thanks!

It's early days with the templates, but similar to height/weight there's a base template for each position - such as say 7 for offensive rebounds for a PF. Then there's a random range it can vary based on the nation's talent score - so a low talent country might range from -6 to +2 for that rating, while an American player might be -4 to +10. This would give some variety already, but I'd like to have a chance of additional templates to be laid over players - both positive and negative. A 'gunner' template might raise the 2point/3point aggression ratings well above the 2point/3point ability ratings etc.

The main thing I want to strive for is generated players have attributes that make sense for their position and heights/weights, but also provide variety and allow for some interesting styles of play.

Re: SQLAlchemy I'd definitely recommend it if you are more comfortable with Python than you are with SQL. Creating dbs and tables and the like is no more complex than creating Python classes.

A good tutorial:
http://www.pythoncentral.io/introduc...on-sqlalchemy/
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 12-10-2014, 12:07 AM   #48
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Another quick update...

Finished the logic for dunks today. I'd put this one off - the other "shooting related" code was some of the first I finished off - because I had to work out the requirements for a player being able to dunk.

Initially I had a 'dunk' rating that I was going to use, which at player creation would factor in the player's jumping ability/height/athleticism etc. to come up with the rating, but I decide to scrap that and just use a mapping of height to jumping ability to determine a player's ability to dunk.

I mapped out a list of requirements for a player to be able to dunk in different situations - wide open, in traffic, alley-oop - in 3 categories of "chance" - minimum, average, and easy. I don't have the figures handy, but for example a 6'2 guy in the key might need a jump rating of 7 to dunk at all, a rating of 9 to dunk averagely, and a rating of 12 or more to dunk easily.

This is also used not just to determine the success of the dunk, but also the player's decision to attempt the dunk at all. A guy just hitting the minimum dunk requirements probably shouldn't be trying too many, and his 'offensive awareness' rating is checked to see if he lays it in instead. It's also checked by the passer in the decision whether to throw an alley-oop pass or not, again following an 'offensive awareness' check.

This is all done within the main "shot" code - a player takes his position into account and if he's at the basket, it checks to see whether to action the dunk or a regular shot. Similarly, the "pass" code factors in the recipient's position and will action an "alley oop pass" if the conditions are met.

I haven't completed the code for the alleyoop dunk finish as yet, but it will be a minor adjustment to the code I have for regular dunks.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Old 12-12-2014, 01:53 PM   #49
GoldenEagle
Grizzled Veteran
 
Join Date: Dec 2002
Location: Little Rock, AR
Sounds like you are having a lot of fun writing this plus getting better at programming.
__________________
Xbox 360 Gamer Tag: GoldenEagle014
GoldenEagle is offline   Reply With Quote
Old 12-15-2014, 05:39 PM   #50
Groundhog
Coordinator
 
Join Date: Dec 2003
Location: Sydney, Australia
Quote:
Originally Posted by GoldenEagle View Post
Sounds like you are having a lot of fun writing this plus getting better at programming.

Yeah, it's made learning programming 'fun', that's for sure. I bought the roughly 1,400 page 'Learning Python' by Mark Lutz and worked my way through it, and I was surprised to see how much of the book I'd already picked up through a couple of other more basic books and from just Googling. Outside of some of the mathematical stuff that I don't have much interest in, it was really only the chapters on classes that I found a lot of new content.
__________________
Politics, n. Strife of interests masquerading as a contest of principles.
--Ambrose Bierce
Groundhog is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is On
Forum Jump


All times are GMT -5. The time now is 07:11 PM.



Powered by vBulletin Version 3.6.0
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.