Commit 1ba347fc by 최애림

Merge branch 'issue/INNODEV-2902' into 'master'

INNODEV-2902 Seminar-프로그래밍 연습_야구 게임 객체 만들어보기

See merge request !2
parents 882087d2 699cf360
import pandas as pd
import pandas as pd
import json
import random
from programming_simulation_v2_5_최종 import *
# 이름
kor_name = pd.read_csv('kor_name.csv', header=None)
kor_name.columns = ['name', 'counts']
# 성
kor_surname_json = open('kor_surname.json', encoding='UTF8')
kor_surname_dict = json.load(kor_surname_json)['surnames']
kor_surname = pd.DataFrame(kor_surname_dict)
# 이름, 성 리스트화
last_name = list(kor_name['name'])
first_name = list(kor_surname['surname'])
def player_maker(n):
player_dict = {
'name': [random.choice(first_name) + random.choice(last_name) for _ in range(n)],
'num': random.sample(range(1, 200), n),
'age': [random.randint(20, 40) for _ in range(n)],
'height': [random.randint(170, 190) for _ in range(n)],
'weight': [random.randint(70, 100) for _ in range(n)],
'position': random.choices(['pitcher', 'batter'], weights=[1, 9], k=n)
}
return player_dict
def player_to_team(team_obj, player_dict, n):
for idx in range(n):
player_inform = [value[idx] for value in player_dict.values()]
if 'pitcher' in player_inform:
player = Pitcher(*player_inform[:-1])
else:
player = Batter(*player_inform[:-1])
team_obj.add_player(player)
print(Team.player_id)
print('\n선수 추가가 완료되었습니다.\n')
# 팀
kiwoom_heros = Team('키움', '서울')
ssg_landers = Team('SSG', '인천')
lg_twins = Team('LG', '서울')
kt_wiz = Team('KT', '수원')
kia_tigers = Team('기아', '광주')
nc_dinos = Team('NC', '창원')
samsung_lions = Team('삼성', '대구')
lotte_giants = Team('롯데', '부산')
doosan_bears = Team('두산', '서울')
hanwha_eagles = Team('한화', '대전')
Team_li = [kiwoom_heros, ssg_landers, lg_twins, kt_wiz, kia_tigers,
nc_dinos, samsung_lions, lotte_giants, doosan_bears, hanwha_eagles]
# 선수 인원
n = 100
for team in Team_li:
# 선수 생성
team_player_li = player_maker(n)
# 선수 추가
player_to_team(team, team_player_li, n)
# 선수 명단 확인
team.check_player()
# 선수 삭제
# hanwha_eagles.remove_player(901)
####### 시즌 시작 #######
season = Season(Team_li)
# 대전 정보 생성
match_iter = season.game_schedule()
####### 시즌 경기 시작 #######
for match_team in match_iter:
# 경기 팀 불러오기
team1, team2 = match_team[0], match_team[1]
print('*' * 10, f'"{team1}" vs "{team2}"', '*' * 60)
# 출전 선수 군단 선택
team1_players = team1.select_player()
team2_players = team2.select_player()
# 경기 시작 회초/말 공격 선택, 경기장 셋
game = Game(team1, team2)
# 선수군 선택
game.choice_players(team1_players, team2_players)
while game.inning_state():
print(f'\n\n{"=" * 10} {game.innings}이닝 {"=" * 80}')
print('-' * 20, match_team[game.team_idx].name, '-' * 70)
# 투수(수비), 타자(공격) 선수 셋팅
pitcher, batters = game.set_player()
for batter in game.batter_generator(batters):
# 3아웃 될 때 까지 경기 진행
output = game.batting_output(pitcher, batter)
if output == PlayerBatting.OUTS:
pitcher.update_records(output)
pitcher.out_avg
# 아웃 횟수 확인하고 3아웃인 경우, 타순 재배치
if game.out_state():
# 마지막 타자 기억 후 타순 재배치
game.save_order(batters.index(batter))
break
else:
game.move_base(batter, output)
# game.now_base()
batter.update_records(output)
batter.batting_avg
get_score = game.result_score(all = False)
print(f'\n\t점수: {get_score}점')
# 점수 정보 저장
game.save_score(get_score)
# 공수 교대
game.shift_attack_defense()
# 경기 결과 저장
result = game.result_score()
season.update_record(result)
# 시즌 전체 경기 순위 확인
season.rank()
import random
import random
from abc import ABC, abstractmethod
from enum import Enum
import numpy as np
from itertools import combinations
import pandas as pd
class PlayerType(Enum):
"""
선수의 타자/투수 여부를 열거형으로 나타냅니다.
"""
PITCHER = 0
BATTER = 1
class PlayerBatting(Enum):
"""
타석에 오른 선수가 취할 수 있는 액션을 열거형으로 나타냅니다.
"""
SINGLES = 1
DOUBLES = 2
TRIPLES = 3
HOMERUNS = 4
OUTS = 5
class PlayerSelected(Enum):
"""
1군, 2군, 랜덤 선수 여부를 열거형으로 나타냅니다.
"""
FIRST_PLAYERS = 0
SECOND_PLAYERS = 1
RANDOM_PLAYER = 2
class Player(ABC):
"""
선수 정보를 관리하는 클래스입니다.
"""
def __init__(self, name, num, age, height, weight, match_n):
"""
객체를 초기화하고 선수들의 정보를 입력하는 메소드입니다.
:param name: 선수 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param match_n: 대전 횟수
"""
self.name = name
self.num = num
self.age = age
self.height = height
self.weight = weight
self.match_n = match_n
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(선수 등번호)' 형태로 반환
"""
return f'{self.name}({self.num})'
@abstractmethod
def update_records(self, batting_output):
"""
선수의 전적을 업데이트할 추상함수를 구현합니다.
:return: None
"""
pass
class Batter(Player):
"""
Player 클래스를 상속 받아 타자 정보를 관리합니다.
"""
def __init__(self, name, num, age, height, weight, match_n=100, n_singles=25, n_doubles=10, n_triples=5, n_homeruns=5):
"""
객체를 초기화하고 타자 정보를 생성합니다.
:param name: 타자 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param match_n: 대전 횟수 (default = 100)
:param n_singles: 1루타 횟수 (default = 25)
:param n_doubles: 2루타 횟수 (default = 10)
:param n_triples: 3루타 횟수 (default = 5)
:param n_homeruns: 홈런 횟수 (default = 5)
"""
super(Batter, self).__init__(name, num, age, height, weight, match_n)
self.position = PlayerType.BATTER
self.n_singles = n_singles
self.n_doubles = n_doubles
self.n_triples = n_triples
self.n_homeruns = n_homeruns
def update_records(self, batting_output):
"""
선수 정보를 업데이트합니다.
:param batting_output: 경기 결과 객체(PlayerBatting Enum class)
:return: None
"""
self.match_n += 1
if batting_output == PlayerBatting.SINGLES:
self.n_singles += 1
elif batting_output == PlayerBatting.DOUBLES:
self.n_doubles += 1
elif batting_output == PlayerBatting.TRIPLES:
self.n_triples += 1
elif batting_output == PlayerBatting.HOMERUNS:
self.n_homeruns += 1
else:
pass
@property
def batting_avg(self):
"""
타자의 안타율을 계산해줍니다.
:return: 안타율
"""
return sum([self.n_singles, self.n_doubles, self.n_triples, self.n_homeruns]) / self.match_n
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(등번호, 안타율)' 형태로 반환
"""
return f'{self.name}({self.num}, {self.batting_avg:.3f})'
class Pitcher(Player):
"""
Player를 상속 받아 투수 정보를 관리합니다.
"""
def __init__(self, name, num, age, height, weight, match_n=100, n_outs=30):
"""
객체를 초기화하고 타자 정보를 생성합니다.
:param name: 타자 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param match_n: 대전 횟수 (default = 100)
:param n_outs: 아웃 횟수 (default = 30)
"""
super(Pitcher, self).__init__(name, num, age, height, weight, match_n)
self.position = PlayerType.PITCHER
self.n_outs = n_outs
def update_records(self, batting_output):
"""
선수 정보를 업데이트합니다.
:param batting_output: 경기 결과 객체(PlayerBatting Enum class)
:return: None
"""
self.match_n += 1
if batting_output == PlayerBatting.OUTS:
self.n_outs += 1
else:
pass
@property
def out_avg(self):
"""
타자의 아웃율을 계산해줍니다.
:return: 아웃률
"""
return self.n_outs / self.match_n
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(등번호, 안타율)' 형태로 반환
"""
return f'{self.name}({self.num}, {self.out_avg:.3f})'
class Team:
"""
구단 정보를 관리하는 클래스입니다.
"""
player_id = 0
def __init__(self, name, location):
"""
객체를 초기화하고 구단 이름, 연고지를 정보를 입력하는 메소드입니다.
:param name: 구단 이름
:param location: 구단 연고지
"""
self.name = name
self.location = location
self.player_pitcher = {}
self.player_batter = {}
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '구단명(연고지)' 형태로 반환
"""
return f'{self.name}({self.location})'
def check_player(self):
"""
구단 내 선수 번호와 선수 이름 목록을 반환합니다.
:return: None
"""
pitcher = [f'{id_num}:{player.name}' for id_num, player in self.player_pitcher.items()]
batter = [f'{id_num}:{player.name}' for id_num, player in self.player_batter.items()]
print(f'투수: {pitcher}\n타자: {batter}')
def add_player(self, player):
"""
구단 내 선수 객체 정보를 추가합니다.
:param player: 추가할 선수 객체
:return: None
"""
Team.player_id += 1
if player.position == PlayerType.PITCHER:
self.player_pitcher[Team.player_id] = player
else:
self.player_batter[Team.player_id] = player
print(f'"{player}" 선수가 선수 명단에서 추가 되었습니다.')
def remove_player(self, remove_id):
"""
구단 내 선수 이름을 파라미터로 받아 투수/타자 선수 목록에 해당 이름이 존재하는 경우 삭제합니다.
:param remove_player_id: 삭제할 선수 id
:return: None
"""
if remove_id in self.player_pitcher:
remove_player = self.player_pitcher[remove_id]
del self.player_pitcher[remove_id]
print(f'{remove_player}이/가 선수 명단에서 제거 되었습니다.')
elif remove_id in self.player_batter:
remove_player = self.player_batter[remove_id]
del self.player_batter[remove_id]
print(f'{remove_player}이/가 선수 명단에서 제거 되었습니다.')
else:
print('선수가 존재하지 않습니다.')
def select_player(self):
"""
연습 게임 횟수에 따른 1군, 2군, 랜덤 투수/타자 선수들을 선발하여 출력합니다.
:return: ((1군 투수/타자), (2군 투수/타자), (랜덤 투수/타자))
"""
sorted_pitchers = sorted(self.player_pitcher.values(), key=lambda x: x.out_avg, reverse=True)
selected_pitcher_1 = sorted_pitchers[0]
selected_pitcher_2 = sorted_pitchers[1]
selected_pitcher_random = random.choice(sorted_pitchers)
sorted_batters = sorted(self.player_batter.values(), key=lambda x: x.batting_avg, reverse=True)
selected_batters_1 = sorted_batters[:9]
selected_batters_2 = sorted_batters[9:18]
selected_batters_random = random.sample(sorted_batters, 9)
return ((selected_pitcher_1, selected_batters_1), (selected_pitcher_2, selected_batters_2),
(selected_pitcher_random, selected_batters_random))
class Game:
"""
두 팀의 경기 정보를 관리하는 클래스입니다.
"""
def __init__(self, team1, team2):
"""
객체를 초기화하고 대전할 두 팀에 관한 정보, 이닝 정보, 이닝별 득점 점수 기록 속성, 팀 인덱스를 생성하고 회초의 선공을 정합니다.
:param team1: 대전할 팀1 객체
:param team2: 대전할 팀2 객체
:return: None
"""
self.match_team = [team1, team2]
self.innings = 1
self.half_of_innings = 0
self.n_out = 0
self.base_board = {}
self.score = 0
self.score_board = {team: [] for team in self.match_team}
self.team_idx = self.match_team.index(random.choice(self.match_team))
print(f'\t{self.match_team[self.team_idx]} 선공!')
def choice_players(self, team_1_players, team_2_players):
"""
두 팀에서 선발된 선수군들(1군, 2군, 랜덤군) 중 랜덤하게 하나의 선수군을 뽑습니다.
:param team_1_players: 팀1에서 선발된 선수군(1군, 2군, 랜덤군)
:param team_2_players: 팀2에서 선발된 선수군(1군, 2군, 랜덤군)
:return: None
"""
selected_group = random.choice(
[PlayerSelected.FIRST_PLAYERS, PlayerSelected.SECOND_PLAYERS, PlayerSelected.RANDOM_PLAYER])
self.selected_team1 = team_1_players[selected_group.value]
self.selected_team2 = team_2_players[selected_group.value]
self.selected_pitchers = [self.selected_team1[PlayerType.PITCHER.value],
self.selected_team2[PlayerType.PITCHER.value]]
self.selected_batters = [self.selected_team1[PlayerType.BATTER.value],
self.selected_team2[PlayerType.BATTER.value]]
def set_player(self):
"""
두 팀에서 선발된 선수군에 대해 회초 수비 팀-> 투수, 회초 공격 팀-> 타자를 경기장에 셋팅합니다.
:return: 이번 경기 투수, 타자들
"""
self.temp_pitcher = self.selected_pitchers[(self.team_idx + 1) % 2]
self.temp_batters = self.selected_batters[self.team_idx]
print(f'\t투수: {self.temp_pitcher.name}')
print(f'\t타자: {[batter.name for batter in self.temp_batters]}')
return self.temp_pitcher, self.temp_batters
def out_state(self):
"""
아웃 카운트를 세고, 3-아웃 여부를 반환합니다.
:return: boolean
"""
self.n_out += 1
if self.n_out == 3:
return True
else:
return False
def inning_state(self):
"""
이닝 수를 확인하고 9이닝 이하 여부를 반환합니다
:return: boolean
"""
if self.innings > 9:
return False
else:
return True
def shift_attack_defense(self):
"""
두 팀의 공격/수비를 변환하고, 게임 정보들(팀 인덱스, 베이스 상황, 아웃 횟수, 점수, 회초/말 정보, 이닝 정보 등)을 초기화합니다.
:return: None
"""
print('공수 교대')
self.team_idx = (self.team_idx + 1) % 2
self.base_board = {}
self.n_out = 0
self.score = 0
self.half_of_innings += 1
if self.half_of_innings == 2:
self.half_of_innings %= 2
self.innings += 1
def batting_output(self, temp_pitcher, temp_batter):
"""
타자, 투수 각각 하나의 객체를 받아 선수 전적을 가중치로 두어 랜덤으로 결과(안타(1/2/3/홈런타), 아웃)를 산출합니다.
:param temp_pitcher: 공격팀 타자 객체
:param temp_batter: 수비팀 투수 객체
:return: 타자의 배팅 결과
"""
win_player = random.choices([PlayerType.PITCHER, PlayerType.BATTER],
weights=[temp_pitcher.out_avg, temp_batter.batting_avg], k=1)[0]
if win_player == PlayerType.BATTER:
batting_li = [PlayerBatting.SINGLES, PlayerBatting.DOUBLES, PlayerBatting.TRIPLES, PlayerBatting.HOMERUNS]
batting_n = [temp_batter.n_singles, temp_batter.n_doubles, temp_batter.n_triples,
temp_batter.n_homeruns]
output = random.choices(batting_li, weights=batting_n, k=1)[0]
if output.value < 4:
print(f'\t\t"{temp_batter.name}" {output.value}루타!')
else:
print(f'\t\t"{temp_batter.name}" 홈런!!!!')
else:
output = PlayerBatting.OUTS
print(f'\t\t"{temp_pitcher.name}" 수비 성공! "{temp_batter.name}" 아웃!')
return output
def save_order(self, batter_idx):
"""
타자들의 타순 인덱스를 받아와 현재 이닝의 타순을 기억하고, 다음 이닝의 타순을 바꿔줍니다.
:param batter_idx: 타자들의 타순 인덱스
:return: None
"""
batter_li = self.selected_batters[self.team_idx]
self.selected_batters[self.team_idx] = batter_li[batter_idx + 1:] + batter_li[:batter_idx + 1]
def save_score(self, score):
"""
이닝 내 회초/회말에 해당 팀의 득점 수를 기록합니다.
:param score: 팀의 득점 수
:return: None
"""
self.score_board[self.match_team[self.team_idx]].append(score)
print('\n\t득정 정보가 저장 되었습니다.\n')
def result_score(self, all = True):
"""
회초/회말의 최종 최종 득점 수 또는 9이닝 이후 팀당 득점 결과를 합산하여 최종 득점 수를 반환합니다.
:return: 최종 득점 수
"""
if all:
self.result = {team: sum(scores) for team, scores in self.score_board.items()}
print('-' * 100)
print('최종 스코어: \n\t', [f'{team.name}: {sum_score}' for team, sum_score in self.result.items()])
print('-' * 100)
return self.result
else:
return self.score
@staticmethod
def batter_generator(batters):
"""
타자 리스트를 받아서 제너레이터로 반환합니다.
"""
idx = 0
for _ in range(50):
yield batters[idx % 9]
idx += 1
def move_base(self, batter, output):
"""
타자 객체와 타자 배팅 결과 객체를 인자로 받아 타자의 베이스 위치 정보를 업데이트(이동)합니다.
:param batter: 타자
:param output: 타자의 배팅 결과
:return: None
"""
for player, base_n in list(self.base_board.items()):
point, moved = divmod(base_n + output.value, 4)
if point == 0:
self.base_board[player] = moved
else:
del (self.base_board[player])
self.score += point
self.base_board[batter] = output.value
def now_base(self):
"""
현재 베이스 내 타자 위치 정보를 보여줍니다.
:return: None
"""
base_board_visual = np.full((3, 3), '-')
base_board_visual[[0, 0, 2, 2], [0, 2, 2, 0]] = '○'
for value in self.base_board.values():
if value == 1:
base_board_visual[2, 2] = '●'
elif value == 2:
base_board_visual[0, 2] = '●'
elif value == 3:
base_board_visual[0, 0] = '●'
print(base_board_visual, '\n')
class Season:
"""
시즌 정보를 관리하는 클래스입니다.
"""
def __init__(self, team_list):
"""
객체를 초기화하고 시즌 경기 참전 팀 리스트와 팀들의 경기 결과를 기록을 생성합니다.
:param: 시즌 경기 참전 팀 리스트
"""
self.team_list = team_list
self.record_dict = {team: {'승': 0, '패': 0, '무승부': 0} for team in self.team_list}
def game_schedule(self):
"""
참전 팀들의 경기 일정 정보를 생성합니다.
각 팀들은 나머지 9개 팀들에 대하여 16번씩 총 144번씩 경기를 치루게 됩니다.
:return: 대전 정보 객체
"""
print('대전 정보를 생성합니다.')
self.one_game = list(combinations(self.team_list, 2))
self.all_game = iter(game for _ in range(16) for game in self.one_game)
return self.all_game
def update_record(self, game_result):
"""
한 경기 내 팀별 최종 득점 수 결과를 받아 최종 승/패/무승부 여부를 가리고 팀별 시즌 정보를 업데이트 합니다.
"""
(team1, team1_score), (team2, team2_score) = game_result.items()
if team1_score > team2_score:
self.record_dict[team1]['승'] += 1
self.record_dict[team2]['패'] += 1
elif team1_score < team2_score:
self.record_dict[team1]['패'] += 1
self.record_dict[team2]['승'] += 1
else:
self.record_dict[team1]['무승부'] += 1
self.record_dict[team2]['무승부'] += 1
def rank(self):
"""
시즌 내 순위대로 팀별 전적을 반환합니다.
return: 팀별 전적
"""
self.sorted_record_dict = dict(
sorted(self.record_dict.items(), key=lambda x: (x[1]['승'], x[1]['무승부'], x[1]['패']), reverse=True))
self.rank_df = pd.DataFrame(self.sorted_record_dict.values(), index=self.sorted_record_dict.keys())
print('*' * 10, '최종 시즌 결과', '*' * 80)
print(self.rank_df)
return self.rank_df
\ No newline at end of file
import random
from abc import ABC, abstractmethod
from enum import Enum
class PlayerType(Enum):
"""
선수의 타자/투수 여부를 열거형으로 나타냅니다.
"""
FIELDER = 1
PITCHER = 2
class PlayerBatting(Enum):
"""
타석에 오른 선수가 취할 수 있는 액션을 열거형으로 나타냅니다.
"""
SINGLES = 1
DOUBLES = 2
TRIPLES = 3
HOMERUNS = 4
OUTS = 5
class Player(ABC):
"""
선수 정보를 관리하는 클래스입니다.
"""
def __init__(self, name, num, age, height, weight, match_n):
"""
객체를 초기화하고 선수들의 정보를 입력하는 메소드입니다.
:param name: 선수 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param match_n: 대전 횟수
"""
self.name = name
self.num = num
self.age = age
self.height = height
self.weight = weight
self.match_n = match_n
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(선수 등번호)' 형태로 반환
"""
return f'{self.name}({self.num})'
@abstractmethod
def update_records(self):
"""
선수의 전적을 업데이트할 추상함수를 구현합니다.
:return: None
"""
pass
class Team:
"""
구단 정보를 관리하는 클래스입니다.
"""
def __init__(self, name, location):
"""
객체를 초기화하고 구단 이름, 연고지를 정보를 입력하는 메소드입니다.
:param name: 구단 이름
:param location: 구단 연고지
"""
self.name = name
self.location = location
self.player_pitcher = []
self.player_fielder = []
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '구단명(연고지)' 형태로 반환
"""
return f'{self.name}({self.location})'
def check_player(self):
"""
구단 내 선수 이름 목록을 반환합니다.
:return: 선수 이름 목록
"""
pitcher = [player.name for player in self.player_pitcher]
fielder = [player.name for player in self.player_fielder]
print(f'투수: {pitcher}\n타자: {fielder}')
return pitcher, fielder
def add_player(self, player):
"""
구단 내 선수 객체 정보를 추가합니다.
:param player: 추가할 선수 객체
:return: None
"""
if player.position == PlayerType.PITCHER:
self.player_pitcher.append(player)
else:
self.player_fielder.append(player)
print(f'"{player}" 선수가 선수 명단에서 추가 되었습니다.')
def remove_player(self, player_name):
"""
구단 내 선수 이름을 파라미터로 받아 투수/타자 선수 목록에 해당 이름이 존재하는 경우 삭제합니다.
:param player_name: 삭제할 선수 이름
:return: None
"""
player_list = self.player_pitcher + self.player_fielder
remove_player = [player for player in player_list if player.name == player_name][0]
if remove_player.position == PlayerType.PITCHER:
self.player_pitcher.remove(remove_player)
else:
self.player_fielder.remove(remove_player)
print(f'"{player_name}" 선수가 선수 명단에서 제거 되었습니다.')
def select_player(self, n_practice):
"""
연습 게임 횟수에 따른 1군, 2군, 랜덤 투수/타자 선수들을 선발하여 출력합니다.
:param n_practice: 연습 게임 횟수
:return: None
"""
self.n_practice = n_practice
for i in range(self.n_practice):
print(f'**** {i+1}번째 연습 게임 선발 ****')
selected_pitchers = random.sample(self.player_pitcher, 3)
selected_pitcher_1 = selected_pitchers[0]
selected_pitcher_2 = selected_pitchers[1]
selected_pitcher_random = selected_pitchers[2]
selected_fielders = random.sample(self.player_fielder, 27)
selected_fielders_1 = selected_fielders[:9]
selected_fielders_2 = selected_fielders[9:18]
selected_fielders_random = selected_fielders[18:]
print(f'\t1군 \n\t\t 투수:{selected_pitcher_1.name}, 타자:{ [player.name for player in selected_fielders_1]}')
print(f'\t2군 \n\t\t 투수:{selected_pitcher_2.name}, 타자:{[player.name for player in selected_fielders_2]}')
print(f'\t랜덤 \n\t\t 투수:{selected_pitcher_random.name}, 타자:{[player.name for player in selected_fielders_random]}')
def practice_game(self, pitcher_name, fielder_name):
"""
투수 1명과, 타자 1명의 전적을 비교해 안타 여부를 가리는 연습 게임입니다.
투수의 피안타율과 타자의 안타율을 가중치로 두고 랜덤하게 승리할 선수를 고릅니다.
만약, 타자가 선택된다면 타자의 1루/2루/3루/홈런 출타 횟수을 가중치로 두고 랜덤하게 output을 고르게 됩니다.
:param pitcher_name: 투수 1명의 이름
:param fielder_name: 타자 1명의 이름
:return: 연습 경기 결과(PlayerBatting Enum class)
"""
practice_pit_rate = [player.out_rate for player in self.player_pitcher if player.name == pitcher_name][0]
practice_fielder = [player for player in self.player_fielder if player.name == fielder_name][0]
practice_field_rate = practice_fielder.batting_rate
win_player = random.choices([PlayerType.PITCHER, PlayerType.FIELDER], weights=[practice_pit_rate, practice_field_rate], k=1)[0]
if win_player == PlayerType.FIELDER:
batting_li = [PlayerBatting.SINGLES, PlayerBatting.DOUBLES, PlayerBatting.TRIPLES, PlayerBatting.HOMERUNS]
batting_n = [practice_fielder.n_singles, practice_fielder.n_doubles, practice_fielder.n_triples, practice_fielder.n_homeruns]
output = random.choices(batting_li, weights=batting_n, k=1)[0]
if output.value < 4:
print(f'"{fielder_name}" {output.value}루타!')
else:
print(f'"{fielder_name}" 홈런!!!!')
return output
else:
print(f'"{pitcher_name}" 수비 성공! "{fielder_name}" 아웃!')
return PlayerBatting.OUTS
class Fielder(Player):
"""
Player 클래스를 상속 받아 타자 정보를 관리합니다.
"""
def __init__(self, name, num, age, height, weight, n_singles=25, n_doubles=10, n_triples=5, n_homeruns=5):
"""
객체를 초기화하고 타자 정보를 생성합니다.
:param name: 타자 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param n_singles: 1루타 횟수 (default = 25)
:param n_doubles: 2루타 횟수 (default = 10)
:param n_triples: 3루타 횟수 (default = 5)
:param n_homeruns: 홈런 횟수 (default = 5)
"""
super(Fielder, self).__init__(name, num, age, height, weight, 100)
self.position = PlayerType.FIELDER
self.n_singles = n_singles
self.n_doubles = n_doubles
self.n_triples = n_triples
self.n_homeruns = n_homeruns
self.batting_rate = sum([self.n_singles, self.n_doubles, self.n_triples, self.n_homeruns]) / self.match_n
def update_records(self, game_output):
"""
선수 정보를 업데이트합니다.
:param game_output: 경기 결과 객체(PlayerBatting Enum class)
:return: None
"""
if game_output == PlayerBatting.SINGLES:
self.n_singles += 1
elif game_output == PlayerBatting.DOUBLES:
self.n_doubles += 1
elif game_output == PlayerBatting.TRIPLES:
self.n_triples += 1
elif game_output == PlayerBatting.HOMERUNS:
self.n_homeruns += 1
else:
pass
self.match_n += 1
self.batting_rate = sum([self.n_singles, self.n_doubles, self.n_triples, self.n_homeruns]) / self.match_n
print(f'선수 정보가 업데이트 되었습니다. {self.batting_rate:.3f}')
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(등번호, 안타율)' 형태로 반환
"""
return f'{self.name}({self.num}, {self.batting_rate:.3f})'
class Pitcher(Player):
"""
Player를 상속 받아 투수 정보를 관리합니다.
"""
def __init__(self, name, num, age, height, weight, n_outs=30):
"""
객체를 초기화하고 타자 정보를 생성합니다.
:param name: 타자 이름
:param num: 등번호
:param age: 나이
:param height: 키
:param weight: 몸무게
:param n_outs: 아웃 횟수 (default = 30)
"""
super(Pitcher, self).__init__(name, num, age, height, weight, match_n=100)
self.position = PlayerType.PITCHER
self.n_outs = n_outs
self.out_rate = self.n_outs / self.match_n
def update_records(self, game_output):
"""
선수 정보를 업데이트합니다.
:param game_output: 경기 결과 객체(PlayerBatting Enum class)
:return:
"""
if game_output == PlayerBatting.OUTS:
self.n_outs += 1
else:
pass
self.match_n += 1
self.out_rate = self.n_outs / self.match_n
print(f'선수 정보가 업데이트 되었습니다. {self.out_rate:.3f}')
def __str__(self):
"""
객체를 문자열로 반환합니다.
:return: '선수 이름(등번호, 안타율)' 형태로 반환
"""
return f'{self.name}({self.num}, {self.out_rate:.3f})'
########################################### test ###################################################
import random
team_kiwoom = Team('키움','서울')
first_name = ['김', '이', '박', '임' ,'후','오', '노', '최', '안', '러']
last_name = ['이혁', '재명', '정후', '셀', '용규', '라도', '병욱', '윤', '병오', '도현', '현', '우진', '우주', '로하', '하하','윤하']
player_kiwoom_li = {
'name': [random.choice(first_name)+random.choice(last_name) for _ in range(60)],
'num': random.sample(range(1,99), 60),
'age': [random.randint(20,40) for _ in range(60)],
'height': [random.randint(170,190) for _ in range(60)],
'weight': [random.randint(70,100) for _ in range(60)],
'position': [random.choice(['pitcher','fielder']) for _ in range(60)]
}
# 선수 추가
for idx in range(60):
information = [value[idx] for value in player_kiwoom_li.values()]
if 'pitcher' in information:
player = Pitcher(*information[:-1])
player.update_records(random.randint(0, 3))
else:
player = Fielder(*information[:-1])
# player.update_records(*[random.randint(0,3) for _ in range(4)])
team_kiwoom.add_player(player)
# 선수 명단 확인
team_kiwoom.check_player()
# 선수 삭제
# team_kiwoom.remove_player('임병욱')
# 명단 확인
pitcher, fielder = team_kiwoom.check_player()
# 랜덤으로 투수, 타자 선수 한명씩 뽑아서 연습게임
team_kiwoom.practice_game(random.choice(pitcher), random.choice(fielder))
# 연습게임 횟수만큼 선수 뽑기
team_kiwoom.select_player(3)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment