1- from collections import Counter
2- from typing import Literal
3- import json
4- import time
5- import sys
6- import os
1+ from collections import Counter #counter for counting resources
2+ from typing import Literal #type hinting for literals
3+ import time #time for sleep
4+ import sys #sys for clearing console
5+ import ast #ast for parsing a python dict
6+ import os #os for clearing console
77
88players = {}
99nextprint = ""
1010
11- def get_numbers (input : str ):
11+ def clear (): #clear console
12+ if sys .platform .startswith ("win" ):
13+ os .system ("cls" )
14+ else :
15+ os .system ("clear" )
16+
17+ def get_numbers (input : str ): #get list of numbers from input
1218 user_input = input
1319 numbers = [int (num .strip ()) for num in user_input .split ("," )]
1420 return numbers
1521
16- def num_to_resource (num : int ):
22+ def num_to_resource (num : int ): #convert number to resource name
1723 if num == 1 :
1824 return "Wood"
1925 elif num == 2 :
@@ -24,19 +30,28 @@ def num_to_resource(num: int):
2430 return "Sheep"
2531 elif num == 5 :
2632 return "Ore"
27-
28- def add_player (name : str ):
33+
34+ def get_amount_of_resources (name : str , resource : int ): #get amount of specific resource a player has
35+ global players
36+ resources = players [name ].get ("resources" , [])
37+
38+ if resource is None :
39+ return 0
40+ else :
41+ return resources .count (int (resource ))
42+
43+ def add_player (name : str ): #add player to game
2944 global players
3045 players [name ] = {"order" :len (players )+ 1 }
3146
32- def get_player_order (order : int ):
47+ def get_player_order (order : int ): #get player name by order
3348 global players
3449 for name , info in players .items ():
3550 if info .get ("order" ) == order :
3651 return name
3752 return None
3853
39- def get_player_resources (name : str ):
54+ def get_player_resources (name : str ): #get list of resources a player has
4055 global players
4156 if name not in players :
4257 raise ValueError (f"Player { name } does not exist." )
@@ -45,22 +60,23 @@ def get_player_resources(name: str):
4560 else :
4661 return players [name ]["resources" ]
4762
48- def format_resources (name : str , resources : list ):
63+ def format_resources (name : str , resources : list ): #format resources for printing
4964 global players
5065 counts = Counter (resources )
5166 formatted = " " .join (f"{ num } :{ num_to_resource (num )} = { counts [num ]} ," for num in sorted (counts ))
5267 return f"{ name } : { formatted } "
5368
54- def add_resource (name : str , resources : list ):
69+ def add_resource (name : str , resources : list , dontshow = False ): #add resources to player
5570 global players
71+ global nextprint
5672 processed = []
5773 for r in resources :
5874 if r > 6 or r < 1 :
59- raise ValueError ( "Invalid resource" )
75+ print ( f "Invalid resource { r } . Skipping. " )
6076 elif r == 6 :
6177 choice = input (f"Resource '(6) gold' for { name } detected! Enter choice: " )
6278 if not choice or choice == 6 :
63- raise ValueError ( "Invalid replacement " )
79+ print ( "No valid choice made. Skipping. " )
6480 processed .append (int (choice ))
6581 else :
6682 processed .append (r )
@@ -69,22 +85,36 @@ def add_resource(name: str, resources: list):
6985 players [name ]["resources" ] = processed .copy ()
7086 else :
7187 players [name ]["resources" ].extend (processed )
88+ if not dontshow :
89+ nextprint += f"Added { processed } to { name } \n "
7290
73- def remove_resource (name : str , resource : list ):
91+ def remove_resource (name : str , resource : list ): #remove resources from player
7492 global players
7593 if name not in players :
76- raise ValueError (f"Player { name } does not exist." )
94+ print (f"Player { name } does not exist." )
7795 elif "resources" not in players [name ]:
78- raise ValueError (f"Player { name } has no resources." )
96+ print (f"Player { name } has no resources." )
7997 else :
8098 for r in resource :
8199 if r > 0 and r < 7 :
82100 players [name ]["resources" ].remove (r )
83101 else :
84- raise ValueError ( "Invalid resource" )
102+ print ( f "Invalid resource { r } . " )
85103
86- def trade (name1 : str , name2 : str , resource1 : list , resource2 : list ):
104+ def trade (name1 : str , name2 : str , resource1 : list , resource2 : list ): #trade resources between players
87105 global players
106+ global nextprint
107+ try :
108+ name1 = int (name1 )
109+ except ValueError :
110+ pass
111+ try :
112+ name2 = int (name2 )
113+ except ValueError :
114+ pass
115+ if type (name1 ) == int and type (name2 ) == int :
116+ name1 = get_player_order (name1 )
117+ name2 = get_player_order (name2 )
88118 if name1 not in players or name2 not in players :
89119 print ("Player does not exist." )
90120 return
@@ -99,13 +129,13 @@ def trade(name1: str, name2: str, resource1: list, resource2: list):
99129 if r not in players [name2 ]["resources" ]:
100130 print (f"{ name2 } does not have resource { r } . Trade canceled." )
101131 return
102- add_resource (name1 , resource2 )
132+ nextprint += f"Traded { resource1 } from { name1 } to { name2 } for { resource2 } \n "
133+ add_resource (name1 , resource2 , dontshow = True )
103134 remove_resource (name2 , resource2 )
104- add_resource (name2 , resource1 )
135+ add_resource (name2 , resource1 , dontshow = True )
105136 remove_resource (name1 , resource1 )
106137
107-
108- def add_source (name : str , number : Literal [2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ], resource : Literal [1 ,2 ,3 ,4 ,5 ,6 ]):
138+ def add_source (name : str , number : Literal [2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ], resource : Literal [1 ,2 ,3 ,4 ,5 ,6 ]): #add resource source to player
109139 global players
110140 if resource > 0 and resource < 7 and number > 1 and number < 13 and name in players :
111141 if "sources" not in players [name ]:
@@ -116,7 +146,7 @@ def add_source(name: str, number: Literal[2,3,4,5,6,7,8,9,10,11,12], resource: L
116146
117147 players [name ]["sources" ][number ].append (resource )
118148
119- def new_roll (p , number ):
149+ def new_roll (p , number ): #process new roll and add resources to players
120150 global players
121151 global nextprint
122152 number = int (number )
@@ -125,20 +155,21 @@ def new_roll(p, number):
125155 sources = data .get ("sources" , {})
126156 if number in sources :
127157 resources_to_add = sources [number ].copy ()
128- add_resource (name , resources_to_add )
129- nextprint = nextprint + f"Added { resources_to_add , num_to_resource (resources_to_add ) } to { name } for roll { number } \n "
158+ add_resource (name , resources_to_add , dontshow = True )
159+ names_to_add = []
160+ for i in range (len (resources_to_add )):
161+ names_to_add .append (num_to_resource (resources_to_add [i ]))
162+ nextprint = nextprint + f"Added { resources_to_add } :{ names_to_add } to { name } for roll { number } \n "
130163 else :
131164 pass
132- def main ():
165+
166+ def main (): #main game loop
133167 global players
134168 turn = 1
135169 while True :
136170 nextturn = 0
137171 while nextturn == 0 :
138- if sys .platform .startswith ("win" ):
139- os .system ("cls" ) #
140- else :
141- os .system ("clear" )
172+ clear ()
142173 print (nextprint )
143174 player = 0
144175
@@ -157,16 +188,23 @@ def main():
157188 2 - Trade
158189 3 - Steal
159190 4 - Split
160- 5 - Add source
161- 6 - Add resources
162- 7 - remove latest source
191+ 5 - Play action card
192+ 6 - Add source
193+ 7 - Add resources
163194 8 - Next turn
164- 9 - Input full data \n """ )
195+ 9 - Advanced options \n """ )
165196
166197 print ("Debug (full list of players and data):" )
167198 print (players )
168199
169- choice = int (input ("Enter choice (1-8): " ))
200+ choice = input ("Enter choice (1-9): " ).strip ()
201+ try :
202+ choice = int (choice )
203+ except ValueError :
204+ print ("Invalid choice. Please try again." )
205+ time .sleep (0.75 )
206+ continue
207+
170208 if choice == 1 : #build
171209 buildingchoice = input ("Enter building (VI, CI, CA, ST, SH or 1-5): " )
172210 if buildingchoice == "q" :
@@ -183,34 +221,69 @@ def main():
183221 remove_resource (player , [1 ,4 ])
184222 else :
185223 remove_resource (player , [buildingchoice ])
224+
186225 elif choice == 2 : #trade
187226 trade (input ("Enter player 1: " ), input ("Enter player 2: " ), get_numbers (input ("Enter resources 1 (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )), get_numbers (input ("Enter resources 2 (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )))
227+
188228 elif choice == 3 : #Steal
189229 victim = input ("Enter victim: " )
190230 if victim == "q" :
191231 continue
192232 else :
193233 card = input ("Enter card (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )
194234 remove_resource (victim , [card ])
235+
195236 elif choice == 4 : #split
196237 player_a = input ("Enter amount of players: " )
197238 if player_a == "q" :
198239 continue
199240 else :
200241 for i in range (int (player_a )):
201242 remove_resource (input ("Enter player name: " ), get_numbers (input ("Enter resources (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )))
202- elif choice == 5 : #add source
243+
244+ elif choice == 5 : #play action card
245+ card_a = input ("Enter card (1:mon,2:inv): " )
246+ if card_a == "q" :
247+ continue
248+ elif card_a in ("1" , "mon" , "mo" , "monopoly" ):
249+ card_chosen = input ("Enter card (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )
250+ total_amount = 0
251+ for name in players :
252+ amount_of_card_chosen = get_amount_of_resources (name ,int (card_chosen ))
253+ total_amount += amount_of_card_chosen
254+ for i in range (amount_of_card_chosen ):
255+ remove_resource (name , [int (card_chosen )])
256+ add_resource (player , [int (card_chosen )] * total_amount )
257+
258+ elif card_a in ("2" , "inv" , "in" , "invention" ):
259+ player_name = input ("Enter player name: " )
260+ add_resource (player_name , input ("Enter resources (1:wood 2:stone 3:wheet 4:sheep 5:ore): " ))
261+ add_resource (player_name , input ("Enter resources (1:wood 2:stone 3:wheet 4:sheep 5:ore): " ))
262+
263+ elif choice == 6 : #add source
203264 source_a = input ("Enter amount of sources: " )
204265 if source_a == "q" :
205266 continue
206267 else :
207268 source_a = int (source_a )
208269 for i in range (source_a ):
209- add_source (player , int (input (f"Enter source ({ i + 1 } /{ source_a } ) number (2-12): " )), int (input ("Enter resource (1:wood 2:stone 3:wheet 4:sheep 5:ore 6:custom): " )))
210- elif choice == 6 : #add resources
270+ source_n = str (input (f"Enter source ({ i + 1 } /{ source_a } ) number (2-12): " ))
271+ if source_n == "q" or source_a == "q" :
272+ continue
273+ source_r = str (input ("Enter resource (1:wood 2:stone 3:wheet 4:sheep 5:ore 6:custom): " ))
274+ if source_r == "q" :
275+ continue
276+ else :
277+ source_n = int (source_n )
278+ for i in range (len (source_r )):
279+ if source_r [i ] == "," :
280+ pass
281+ else :
282+ add_source (player , source_n , int (source_r [i ]))
283+
284+ elif choice == 7 : #add resources
211285 add_resource (player , get_numbers (input ("Enter resources (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )))
212- elif choice == 7 : #remove latest source
213- players [player ]["sources" ].popitem ()
286+
214287 elif choice == 8 : #next turn
215288 roll = input ("Enter roll (2-12): " )
216289 if roll == "q" :
@@ -219,29 +292,62 @@ def main():
219292 new_roll (player , roll )
220293 turn += 1
221294 nextturn = 1
295+
222296 elif choice == 9 : #input custom data
223- data = input ("Enter full data (The data must me in the correct format):" )
224- if data == "q" :
225- continue
297+ clear ()
298+ if turn == 1 :
299+ player = get_player_order (1 )
300+ print ("Starting player:" , player )
226301 else :
227- players = json .loads (data )
302+ player = get_player_order ((turn - 1 ) % len (players ) + 1 )
303+ print ("Current player:" , player )
304+
305+ for name in players :
306+ print (format_resources (name , get_player_resources (name )))
307+ print ("""\n Advanced options:
308+ 1. Remove resources
309+ 2. Remove latest source
310+ 3. Import full data (Python dict format)\n """ )
311+ choice_a = input ("Enter choice (1-3): " ).strip ()
312+ if choice_a == "q" :
313+ continue
314+ elif choice_a == "1" :
315+ remove_resource (player , get_numbers (input ("Enter resources (1:wood 2:stone 3:wheet 4:sheep 5:ore): " )))
316+ elif choice_a == "2" : #remove latest source
317+ if "sources" not in players [player ] or len (players [player ]["sources" ]) == 0 :
318+ print ("No sources to remove." )
319+ else :
320+ players [player ]["sources" ].popitem ()
321+ elif choice_a == "3" :
322+ data = input ("Enter full data (The data must me in the correct format):" )
323+ if data == "q" :
324+ continue
325+ else :
326+ try :
327+ parsed = ast .literal_eval (data )
328+ if not isinstance (parsed , dict ):
329+ print ("Parsed value is not a dict." )
330+ else :
331+ players = parsed
332+ print ("Imported players successfully." )
333+ except Exception as e :
334+ print ("Failed to parse input as Python literal:" , e )
335+
228336 else :
229- print ("Invalid choice." )
230- time .sleep (0.5 )
337+ print ("Invalid choice. Please try again." )
338+
339+ time .sleep (0.75 )
231340
232- def init_game ():
341+ def init_game (): #initialize game and players
233342 print ("""╔═╗╔═╗╔╦╗╔═╗╔╗╔ ┌┬┐┬─┐┌─┐┌─┐┬┌─┌─┐┬─┐
234343║ ╠═╣ ║ ╠═╣║║║ │ ├┬┘├─┤│ ├┴┐├┤ ├┬┘
235- ╚═╝╩ ╩ ╩ ╩ ╩╝╚╝ ┴ ┴└─┴ ┴└─┘┴ ┴└─┘┴└─ V2 .0
344+ ╚═╝╩ ╩ ╩ ╩ ╩╝╚╝ ┴ ┴└─┴ ┴└─┘┴ ┴└─┘┴└─ V3 .0
236345──────────────────────────────────────
237346A simple irl Settlers of Catan card and player tracker. (With the seafarers gold resource)\n """ )
238347 amount_of_players = int (input ("Enter the amount of players: " ))
239348 for i in range (amount_of_players ):
240349 name = input (f"Enter player name ({ i + 1 } /{ amount_of_players } ): " )
241350 add_player (name )
242351
243-
244-
245-
246352init_game ()
247- main ()
353+ main ()
0 commit comments