Compare commits

...

10 Commits

Author SHA256 Message Date
05e219ad18 Merge pull request 'bug solved in event picker' (#6) from green/battle_royale_sim:master into master
Reviewed-on: #6
2025-08-11 22:14:05 +02:00
0d36f1dd52 bug solved in event picker 2025-08-10 15:32:47 +02:00
13bb11eb8c event picket to be tested but im lazy 2025-08-05 21:03:20 +02:00
af7f0019ec initial event picker 2025-08-04 21:10:12 +02:00
804a3961c9 Update README.md 2025-08-02 11:18:38 +02:00
andrea
cdb69699ab replace print with log_debug 2025-08-02 10:04:30 +02:00
andrea
6c3fe6326f restore map size 2025-08-02 09:55:16 +02:00
andrea
2550f0b262 fix movements 2025-08-02 09:52:20 +02:00
andrea
3cc6966d86 fix merge regression and exlude death player from attackable players 2025-08-02 09:33:06 +02:00
62c7c7f2c2 Update README.md 2025-08-02 09:06:07 +02:00
10 changed files with 172 additions and 62 deletions

View File

@@ -7,7 +7,9 @@ You can find the Official Bot here:
Feel free to fork the project and make your own Bot
# Bot Instrictions
This game is inspired to this Hunger Games Simulator: https://brantsteele.net/hungergames/reaping.php
# Bot Instructions (Telegram)
1. start a chat with the bot: https://t.me/Brsimgen_Bot
2. open the bot keyboard
@@ -24,6 +26,13 @@ Feel free to fork the project and make your own Bot
- Get Alive Players: (list of alive players)
- Get Death Players: (list of death players)
- Get Ranking Players: (this is the leaderboard, based on number of kills)
- Show Map UTF8 or Show Map Image (show Players/Items position on the map)
# Bot Instructions (CLI)
1. open a python shell
2. `import debug`
3. `debug.init_debug_simulation()`
# Fork Instructions
@@ -45,6 +54,8 @@ TOKEN = 'your-bot-token'
BOT_PATH= '/the/path/of/the/project'
LOG_PATH= '/the/path/where/you/want/put/game/daily/logs'
BOT_EXEC_CMD= 'python3 bot.py' # or any other way you start the bot
SUPER_USERS= [ your_chat_id ]

View File

@@ -7,8 +7,21 @@ EVENTS = [
'success_percentage' : 80,
'fail_percentage' : 19,
'extreme_fail_percentage' : 1,
'required_items' : [],
'requirements' : {},
'weight' : 1,
'number_of_players' : 2,
'affected_players' : 1,
},
{
'id' : 'BOMB_EXPLOSION',
'text' : '{Player1} ha attacato {player2}',
'resolve_text' : '{Player1} ha causato {effetto_collaterale}',
'fail_text' : '{Player1} ha fallito, {player2} è indenne',
'success_percentage' : 80,
'fail_percentage' : 19,
'extreme_fail_percentage' : 1,
'requirements' : {
'weapons' : ['BOMB']
},
'affected_players' : [2,3,4],
},
]

View File

@@ -1,4 +1,5 @@
import os as _os
from utils import logs as _logs
_MISSING_LOCAL_SETTINGS= """
=============== ERROR ===============
@@ -20,7 +21,7 @@ _MISSING_LOCAL_SETTINGS= """
try:
from local_settings import TOKEN as _token
TOKEN= _token
except: print(_MISSING_LOCAL_SETTINGS)
except: _logs.log_debug(_MISSING_LOCAL_SETTINGS)
try:
from local_settings import BOT_PATH as _bot_path
BOT_PATH= _os.path.expanduser(_bot_path)
@@ -86,13 +87,13 @@ MAP_UTF8_DEATH_PLAYER= '💀'
MAP_UTF8_ITEM= '📦'
MAP_UTF8_LEGEND= f"""*Legenda*:
\- *{MAP_UTF8_FIELD}*: Cella *libera* per muoversi
\- *{MAP_UTF8_MOUNTAIN}*: Bordo della mappa, *non raggiungibile*
\- *{MAP_UTF8_PLAYER_MALE}*: Posizione di un *giocatore Maschio*
\- *{MAP_UTF8_PLAYER_FEMALE}*: Posizione di una *giocatorice Femmina*
\- *{MAP_UTF8_PLAYER_NONBINARY}*: Posizione di un *giocatore non binario*
\- *{MAP_UTF8_DEATH_PLAYER}*: Posizione di un *giocatore morto*
\- *{MAP_UTF8_ITEM}*: Posizione di un *oggetto* \(non ancora implementato\)
- *{MAP_UTF8_FIELD}*: Cella *libera* per muoversi
- *{MAP_UTF8_MOUNTAIN}*: Bordo della mappa, *non raggiungibile*
- *{MAP_UTF8_PLAYER_MALE}*: Posizione di un *giocatore Maschio*
- *{MAP_UTF8_PLAYER_FEMALE}*: Posizione di una *giocatorice Femmina*
- *{MAP_UTF8_PLAYER_NONBINARY}*: Posizione di un *giocatore non binario*
- *{MAP_UTF8_DEATH_PLAYER}*: Posizione di un *giocatore morto*
- *{MAP_UTF8_ITEM}*: Posizione di un *oggetto* (non ancora implementato)
"""
MAP_IMAGE_FIELD= (0, 255, 0) # green
@@ -104,11 +105,11 @@ MAP_IMAGE_DEATH_PLAYER= (160, 160, 160) # grey
MAP_IMAGE_ITEM= (255, 255, 255) # white
MAP_IMAGE_LEGEND= r"""*Legenda*:
\- *Verde*: Cella *libera* per muoversi
\- *Nero*: Bordo della mappa, *non raggiungibile*
\- *Blue*: Posizione di un *giocatore Maschio*
\- *Rosso*: Posizione di una *giocatorice Femmina*
\- *Giallo*: Posizione di un *giocatore non binario*
\- *Grigio*: Posizione di un *giocatore morto*
\- *Bianco*: Posizione di un *oggetto* \(non ancora implementato\)
- *Verde*: Cella *libera* per muoversi
- *Nero*: Bordo della mappa, *non raggiungibile*
- *Blue*: Posizione di un *giocatore Maschio*
- *Rosso*: Posizione di una *giocatorice Femmina*
- *Giallo*: Posizione di un *giocatore non binario*
- *Grigio*: Posizione di un *giocatore morto*
- *Bianco*: Posizione di un *oggetto* (non ancora implementato)
"""

View File

@@ -1,6 +1,7 @@
import time as _time
import random as _rand
import main as _main
from utils import logs as _logs
from bot_libs import syms as _syms
def _debug_data():
@@ -15,7 +16,7 @@ def _debug_data():
def _end_game_debug(alive_players, day):
last_player= alive_players[0]
msg= f'{last_player.get_name()} sopravvive e vince dopo {day} lunghi Giorni, conquistando l\'amore eterno di Guarino'
print(msg)
_logs.log_debug(msg)
return msg
def _random_action(Arena, Player_one):
@@ -23,18 +24,22 @@ def _random_action(Arena, Player_one):
1: 'attack',
2: 'move',
}
action= _rand.randint(1, len(_RANDOM_ACTIONS))
Map= Arena.get_map()
avail_actions= Map.get_player_available_actions(Player_one)
_logs.log_debug(f'{Player_one.get_name()}:{Player_one.get_coordinates()}, avail_actions: {avail_actions}')
msg= ''
if action == 1:
if 1 in avail_actions:
# XXX maybe in future this action is available only if you are near to another player
# so Player_two is no more random, but will be a random near player
Player_two= _rand.sample(Arena.get_alive_players(), 1)[0]
while Player_one.get_id() == Player_two.get_id():
Player_two= _rand.sample(Arena.get_alive_players(), 1)[0]
preys= avail_actions[1]
Player_two= _rand.sample(preys, 1)[0]
while Player_one.get_id() == Player_two.get_id() and not Player_two.is_alive():
Player_two= _rand.sample(preys, 1)[0]
_dmg, msg= Player_one.attack(Player_two)
elif action == 2:
elif 2 in avail_actions:
Map= Arena.get_map()
available_movements= Map.get_player_available_directions(Player_one)
_logs.log_debug(f'{Player_one.get_name()}:{Player_one.get_coordinates()}, avail_movements: {available_movements}')
if not available_movements:
# XXX probably should skip this action and look for another action
return f'{Player_one.get_name()} Pensa a Guarino tutto il giorno'
@@ -42,14 +47,14 @@ def _random_action(Arena, Player_one):
x, y, direction= available_movements[0]
Player_one.move(x, y)
Map.init_map_matrix()
print(Map.get_renderized_map())
_logs.log_debug(Map.get_renderized_map())
msg= f'{Player_one.get_name()} Si muove verso »»» {direction}'
return msg
def play_one_day_debug(Arena):
if not Arena.get_players(): return
print(f'Giorno #{Arena.day}')
_logs.log_debug(f'Giorno #{Arena.day}')
alive_players= Arena.get_alive_players()
if len(alive_players) == 1:
day= Arena.day
@@ -77,13 +82,13 @@ def init_debug_simulation():
Arena= _debug_data()
while (len(Arena.get_alive_players()) > 1):
events= play_one_day_debug(Arena)
print('#################')
print('#################')
print('#################')
print(events)
print('#################')
print('#################')
print('#################')
_logs.log_debug('#################')
_logs.log_debug('#################')
_logs.log_debug('#################')
_logs.log_debug(events)
_logs.log_debug('#################')
_logs.log_debug('#################')
_logs.log_debug('#################')
_time.sleep(0.3)
def init_debug_loop():
@@ -101,14 +106,14 @@ def init_debug_loop():
#End of day
last_player= Arena.get_alive_players()[0]
print(f'{last_player.get_name()} sopravvive e vince dopo {Arena.day} lunghi Giorni, conquistando l\'amore eterno di Guarino')
_logs.log_debug(f'{last_player.get_name()} sopravvive e vince dopo {Arena.day} lunghi Giorni, conquistando l\'amore eterno di Guarino')
def debug_random_map():
from entities import map as _map;
from entities import player;
M= _map.BrSimMap(players= [player.BrSimPlayer(i) for i in range(20)]);
res= M.get_renderized_map()
print(res)
_logs.log_debug(res)
if __name__ == '__main__':
init_debug()

View File

@@ -2,6 +2,7 @@ from entities import player as _player
from entities import event_picker as _events
from entities import gamemap as _map
from entities.items import weapons as _weapons
from utils import logs as _logs
class BrSimArena():
@@ -30,13 +31,13 @@ class BrSimArena():
def next_day(self):
self.day+= 1
print(f'Giorno: {self.day}')
_logs.log_debug(f'Giorno: {self.day}')
alive_players_str= ', '.join([p.get_name() for p in self.get_alive_players()])
print(f'Giocatori vivi: {alive_players_str}')
_logs.log_debug(f'Giocatori vivi: {alive_players_str}')
death_players= self.get_death_players()
if (death_players):
death_players_str= ', '.join([p.get_name() for p in death_players])
print(f'Giocatori morti: {death_players_str}')
_logs.log_debug(f'Giocatori morti: {death_players_str}')
def get_alive_players(self):
res= []

5
entities/event.py Normal file
View File

@@ -0,0 +1,5 @@
class Event():
def __init__(self, event_settings, the_player, affected_players = []):
# this will be the class that manage the event, so the result and what ahppens to the players
# will do it later
pass

View File

@@ -7,7 +7,75 @@ class ArenaEventPicker():
self.event_list = EVENTS
self.already_picked_players = []
def pick_event():
pass
def pick_a_player():
the_player = _random.choice(self.players)
the_player_id = the_player.get('id')
self.players = list(filter(lambda x : x.get('id') != the_player_id))
self.already_picked_players.append(the_player)
return the_player
def pick_event(the_player):
player_inventory = the_player.get('inventory') or []
status = the_player['health']
reputation = the_player['reputation']
elegible_events = []
for event in EVENTS:
requirements = event['requirements']
keys_to_check = ['item', 'weapon', 'status', 'reputation', 'affected_players']
for check in keys_to_check:
if requirements.get(check) and check == 'item':
needed_items = requirements.get('check')
if needed_items in player_inventory:
elegible_events.append(event)
if requirements.get(check) and check == 'weapon':
needed_weapons = requirements.get('check')
if needed_items in player_inventory:
elegible_events.append(event)
if requirements.get(check) and check == 'status':
needed_health = requirements.get('check')
if '>' in requirements.get(check) and requirements.get(check) > needed_health:
elegible_events.append(event)
if '<' in requirements.get(check) and requirements.get(check) < needed_health:
elegible_events.append(event)
if requirements.get(check) and check == 'reputation':
needed_reputation = requirements.get('reputation')
if '>' in requirements.get(check) and requirements.get(check) > needed_reputation:
elegible_events.append(event)
if '<' in requirements.get(check) and requirements.get(check) < needed_reputation:
elegible_events.append(event)
if check == 'affected_players':
needed_players = event.get('affected_players')
if needed_players < len(self.players):
elegible_events.append(event)
the_event = _random.choice(elegible_events)
return the_event
def pick_targets(number_of_targets):
random.shuffle(self.players)
return list(self.players[0:number_of_targets])
def resolve_event():
playing_player = self.pick_a_player()
assigned_event = self.pick_event(playing_player)
affected_players = assigned_event['affected_players']
if isinstance(affected_players,list):
affected_players = _random.choice(affected_players)
targeted_players = self.pick_targets(affected_players)
event_instance = _event.Event(assigned_event, playing_player)

View File

@@ -6,6 +6,7 @@ from PIL import ImageDraw as _ImageDraw
from utils import logs as _logs
from bot_libs import syms as _bot_syms
from entities import resource as _resource
from utils import logs as _logs
class BrSimMap():
@@ -78,7 +79,7 @@ class BrSimMap():
x= _random.randint(0, self.world_width -1)
y= _random.randint(0, self.world_height -1)
resource= self.get_map_matrix()[y][x]
print(f'{target.get_name()} >>> ({x},{y})')
_logs.log_debug(f'{target.get_name()} >>> ({x},{y})')
target.set_coordinates(x, y)
self.get_map_matrix()[y][x]= target
@@ -105,14 +106,18 @@ class BrSimMap():
coord_x, coord_y= Player.get_coordinates()
avail_directions= []
#XXX for now move only on available cells, no over other players/items
if coord_x > 0 and not self.get_map_matrix()[coord_x - 1][coord_y]:
avail_directions.append((-1, 0, 'sinistra'))
if coord_x < self.world_width -1 and not self.get_map_matrix()[coord_x + 1][coord_y]:
avail_directions.append((1, 0, 'destra'))
if coord_y > 0 and not self.get_map_matrix()[coord_x][coord_y - 1]:
avail_directions.append((0, -1, 'su'))
if coord_y < self.world_height -1 and not self.get_map_matrix()[coord_x][coord_y + 1]:
avail_directions.append((0, 1, 'giu\''))
for shift in [-1, 1]:
x= coord_x + shift
if x < 0 or x > self.world_width -1: continue
resource= self.get_map_matrix()[coord_y][x]
direction= shift == -1 and 'sinistra' or 'destra'
if not resource: avail_directions.append((shift, 0, direction))
for shift in [-1, 1]:
y= coord_y + shift
if y < 0 or y > self.world_height -1: continue
resource= self.get_map_matrix()[y][coord_x]
direction= shift == -1 and 'su' or 'giu\''
if not resource: avail_directions.append((0, shift, direction))
return avail_directions
def check_near_players(self, Player):
@@ -126,12 +131,12 @@ class BrSimMap():
x= coord_x + shift
if x < 0 or x >= self.world_width -1: continue
resource= self.get_map_matrix()[coord_y][x]
if resource and resource.is_player(): attackable_players.append(resource)
if resource and resource.is_player() and resource.is_alive(): attackable_players.append(resource)
for shift in [-1, 1]:
y= coord_y + shift
if y < 0 or y >= self.world_height -1: continue
resource= self.get_map_matrix()[y][coord_x]
if resource and resource.is_player(): attackable_players.append(resource)
if resource and resource.is_player() and resource.is_alive(): attackable_players.append(resource)
return attackable_players
@@ -146,7 +151,7 @@ class BrSimMap():
attack= self.check_near_players(Player)
if attack:
print(f'{Player.get_name()} can attack {[a.get_name() for a in attack]}')
_logs.log_debug(f'{Player.get_name()} can attack {[a.get_name() for a in attack]}')
#avail_actions.append(1) #XXX replace with attack action (or maybe other actions on players)
avail_actions[1]= attack #XXX replace with attack action (or maybe other actions on players)
if self.get_player_available_directions(Player):

View File

@@ -1,6 +1,7 @@
import random as _random
import uuid as _uuid
from entities import resource as _resource
from utils import logs as _logs
class BrSimPlayer(_resource.BrSimResource):
@@ -137,11 +138,11 @@ class BrSimPlayer(_resource.BrSimResource):
self.health= 0
if self.player_gender_is_male():
print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morto x.x')
_logs.log_debug(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morto x.x')
elif self.player_gender_is_female():
print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morta x.x')
_logs.log_debug(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono morta x.x')
else:
print(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono mort* x.x')
_logs.log_debug(f'[{self.get_name_and_stats()}]: Guarino, perdonami se sono mort* x.x')
return damage
def attack(self, target):
@@ -166,11 +167,11 @@ class BrSimPlayer(_resource.BrSimResource):
def get_item(self, item):
if self.get_inventory_weight() + item.get_weight() >= self.get_max_weight():
if self.player_gender_is_male():
print(f'Sono sovraccarico, {self.get_name_and_stats} non puo\' prendere questo oggetto')
_logs.log_debug(f'Sono sovraccarico, {self.get_name_and_stats} non puo\' prendere questo oggetto')
elif self.player_gender_is_female():
print(f'Sono sovraccarica, {self.get_name_and_stats} non puo\' prendere questo oggetto')
_logs.log_debug(f'Sono sovraccarica, {self.get_name_and_stats} non puo\' prendere questo oggetto')
else:
print(f'Sono sovraccaric#, {self.get_name_and_stats} non puo\' prendere questo oggetto')
_logs.log_debug(f'Sono sovraccaric#, {self.get_name_and_stats} non puo\' prendere questo oggetto')
return False
self.inventory.append(item)

View File

@@ -19,17 +19,16 @@ def get_log_name():
def _create_file_handler():
global file_handler
print('### create file handler')
current_log_file = get_log_name()
file_handler = _logging.FileHandler(current_log_file, encoding='utf-8')
formatter = _logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.setLevel(_logging.INFO)
#logger.setLevel(_logging.INFO)
logger.setLevel(_logging.DEBUG)
return file_handler
def _setup_logging_file():
print('### setup logging')
current_log_file = get_log_name()
if not file_handler: return _create_file_handler()
@@ -40,6 +39,7 @@ def _setup_logging_file():
_create_file_handler()
def log_debug(txt):
print(txt)
_setup_logging_file()
logger.debug(txt)