코 데몬, 나는 당신을 선택합니다!


55

당신의 친절한 이웃 인 닥터 트리는 방금 코 데몬이라는 3 가지 마법의 생물을주었습니다. 근처의 Colorville 마을에서 전투 토너먼트가 있습니다. 아무도 없었던 것처럼 당신은 최고입니까?

개요

이것은 전투 토너먼트입니다. 각 플레이어는 3 명의 몬스터로 구성된 팀을 통제하며, 목표는 다른 팀을 제압하는 것입니다. 100 라운드가 있으며 승리와 동점에 대한 포인트가 부여됩니다. 가장 많은 점수를 얻은 팀이 승리합니다!

몬스터

코 데몬은 복잡한 작은 생물입니다. 선택할 수있는 5 가지 유형 (요소), 3 가지 능력치 및 3 가지 이동 슬롯이 있습니다.

종류

각 Codémon에는 하나의 유형 이 지정됩니다 . 다섯 가지 유형은 보통, 심령, 불, 물 및 잔디입니다. 각각의 장단점이 있습니다. 피해는 다음 차트를 기준으로합니다.

타입 차트

숫자는 피해 승수입니다. 예를 들어, 화염 공격수는 0.5 수 정치 (반 손상)를 가지며 화염 공격 잔디는 두 배가됩니다 (2).

통계

각 몬스터에는 전투 능력을 결정하는 3 가지 능력치가 있습니다. 공격시받는 피해가 증가합니다. 방어는받는 피해를 줄입니다. 속도는 속도가 느린 사람들보다 먼저 움직입니다.

각 몬스터는 각 스탯의 시작 값이 50이고 최대 100입니다. 몬스터를 만들 때 추가로 스탯 포인트 80 개 를 할당 할 수 있습니다 . 개별 통계는 100을 넘을 수 없습니다. 따라서 100/80/50, 90/80/60 또는 65/65/100 분포를 가질 수 있지만 120/50/60은 불법입니다. 불법 통계를 가진 팀은 실격됩니다. 80 포인트를 모두 사용할 필요 는 없지만 최소 50/50/50을 초과해서는 안됩니다.

HP를 스탯으로 간주 할 수도 있지만 각 Codémon에는 수정할 수없는 100 HP가 있습니다. HP가 0으로 떨어지면 계속 싸울 수 없습니다. 매 전투마다 HP가 100으로 재충전됩니다.

이동

각 몬스터는 세 번의 전투 동작을 알고 있습니다. 선택한 세 개는 고유해야하므로 펀치 / 펀치 / 펀치가 없습니다.

각 유형의 3 개씩 15 개의 동작이 있습니다. 각 유형에는 직접 공격, 약한 공격 효과, 단독 효과 이동이 있습니다.

id  name        type    power   uses    usable  effect

0   Punch       N       20      -       NFWG
1   Heal        N        0      3       NFWG    Heals 50 HP
2   Slow        N       10      5       NFWG    Enemy speed x0.8
3   Pain        P       20      -       PFWG
4   Sleep       P        0      3       PFWG    No enemy action until wake
5   Weaken      P       10      5       PFWG    Enemy Atk x0.8
6   Fireball    F       20      -       NPFW
7   Burn        F        0      3       NPFW    Enemy -10 HP each turn
8   Sharpen     F       10      5       NPFW    Own Atk x1.25
9   Watergun    W       20      -       NPWG    
10  Confuse     W        0      3       NPWG    Enemy may strike itself (10 power)
11  Shield      W       10      5       NPWG    Own Def x1.25
12  Vine        G       20      -       NPFG
13  Poison      G        0      3       NPFG    Enemy -5xTurns HP each turn
14  Sap         G       10      5       NPFG    Enemy Def x0.8

type이동 유형을 나타냅니다. power그 놀라운 힘입니다. uses전투 당 ​​몇 번 사용할 수 있는지 나타냅니다 ( -무제한). usable사용할 수있는 유형을 표시합니다 (예 : 펀치가 Psychic 유형에 제공 될 수 없으므로 P). effect움직임이 어떤 영향을 미치는지 보여줍니다. 항상 효과가있는 치유를 제외하고 각 효과가 75 % 확률로 작용합니다.

몬스터의 능력치를 변경하는 효과의 경우 효과가 누적 될 수 있습니다 . 예를 들어, Weaken을 두 번 사용하면 상대방의 공격력이 0.64로 낮아질 수 있습니다. 몬스터의 능력치 (수면, 번 등)를 변경하지 않은 효과는 쌓이지 않습니다 .

수면 은 매 턴 시작시 60 %의 확률로 깨어날 수 있습니다. 잠자는 몬스터는 행동을 취하지 않습니다.

번에 불이 붙을 마다 매번 적의 공격력이 10 HP가 됩니다 . 은 비슷하게 작동하지만 매 턴마다 더 많은 양을 소비합니다. 첫 번째 턴에서는 5이며, 그 후 매 턴마다 5를 얻습니다. 따라서 네 번째 턴에는 20의 피해를줍니다. 이들은 몬스터의 유형이나 보너스 대상이 아닌 플랫 데미지입니다.

혼란 은 지시대로 행동하지 않고 몬스터를 공격 할 수 있습니다. 이 공격은 10의 파워를 가지며 주어진 턴에 30 %의 확률로 발생합니다.

분명히 말하면, 효과는 전투가 끝날 때까지 지속됩니다 (위에서 언급 한 것처럼 수면 제외).

해당 유형의 몬스터가 사용하면 이동 속도가 20 % 증가합니다. 예를 들어, 포도 나무를 사용하는 잔디 괴물은 강화되지만 펀치는 사용하지 않습니다.

비밀 통계

통계 및 유형 (하지만 하지 몬스터의 이동) 공공 지식이다. 상대방은 최선의 행동을 선택하기 위해 싸우고있는 것을 볼 수 있습니다. 그러나 숨겨진 보너스도 있습니다.

구체적으로, 번의 전투 마다 팀의 각 몬스터마다 "보너스"스탯 포인트가 하나씩 주어집니다. 포인트는 모든 몬스터, 사망 또는 생존, 승자 또는 패자에게 제공됩니다. 이 통계를 선택한 세 가지 통계 중 하나에 할당 할 수 있습니다. 하나의 몬스터에 쌓을 수 없습니다. 각 몬스터는 매번 하나를 얻는다 . 이 포인트는 100 제한에 영향을받지 않습니다. 100 개의 전투 라운드가있을 것이기 때문에 모든 보너스를 할당하면 최대 149까지 단일 스탯을 얻을 수 있습니다. 다시 말하지만, 상대방은 "기본"통계 만 볼 수 있으므로 토너먼트에서 멀어 질수록 그들의 지식은 진실과 다릅니다.

전투

한 번에 한 팀씩 하나씩 활동하며 3 명으로 구성된 팀간에 전투가 벌어집니다. 시작시, 상대 팀이 표시되고 첫 번째 "활성"플레이어가 될 몬스터를 선택하라는 메시지가 표시됩니다.

그 후 다음 단계로 회전합니다.

  • 스위치 : 필수 몬스터 스위치가 발생합니다 (있는 경우)
  • 전투 행동을 선택하십시오
  • 스위치 : 모든 옵션 몬스터 스위치 (전투 행동으로 선택)
  • 수면 점검 : 수면에서 일어날 확률
  • 공격 1 : 가능하다면, 더 빠른 몬스터는 선택된 이동을 사용합니다
  • 공격 2 : 가능하다면, 다른 몬스터는 선택된 이동을 사용합니다
  • 효과 피해 : 살아있는 몬스터에게 화상 / 중독 피해를 입 힙니다.

"빠른 속도"는 더 빠른 속도의 몬스터를 의미합니다. 두 속도 통계가 동일하면, 매 회전마다 PRNG 코인 플립으로 선택됩니다.

당신의 활성 몬스터가 죽는 턴이 끝날 때마다 새로운 활성을 선택하라는 메시지가 나타납니다. 당신은 또한 당신이 어떤 턴을 위해 당신의 이동으로 활성 몬스터를 전환하도록 선택할 수 있습니다 (둘 이상의 생존을 한 경우). 다시, 당신이 당신의 이동으로 전환한다면, 당신은 그 차례에 전투 이동을하지 않을 것입니다.

비활성 상태에서는 몬스터를 "처리"하지 않습니다. 이것은 화상 / 독 피해, 독 카운터가 축적되지 않음 , 잠에서 깨어나지 않음 등을 의미 합니다. 전환시 효과가 제거되거나 변경되지 않습니다 . 이것은 다른 괴물과 싸우는 게임 이 아닙니다 . 공격을 제기하고 태운 상태로 전환하면 다시 전환해도 여전히 그대로 유지됩니다.

당신의 활동 상대를 죽일 지 여부에 관계없이 피해가 발생합니다. 이런 식으로 두 팀의 멤버는 한 차례에 죽을 수 있습니다.

한 팀에 사용 가능한 몬스터가 떨어지면 패합니다. 두 팀이 같은 차례에 뛰면 동점입니다. 전투가 1000 턴 동안 지속되면 넥타이입니다.

손상을 결정하는 공식은 다음과 같습니다.

floor((effAttack / effDefense) * movePower * typeMultiplier * moveBoost)

effAttackeffDefense있는 효과적인 괴물에 대한 통계. 효과적인 공격은 공격과 보너스 공격을 더한 다음 효과가 변경되면 0.8 또는 1.25를 곱하여 얻습니다. 이러한 효과는 쌓일 수 있습니다.

유형 수정자가 0 (정상 <-> Psychic)이거나 이동의 힘이 0 (치유, 번 등) 인 경우에만 피해를 입을 수 있습니다. 그렇지 않으면 최소값은 1로 시행됩니다.

토너먼트

토너먼트는 100 라운드 동안 지속됩니다. 각 라운드에서 팀은 무작위로 섞여 서로 섞입니다. 홀수의 팀이있는 경우 남은 사람은 한 명 (타이로 점수)을받습니다. 전투에서 승리하면 팀이 2 점을 얻고 관계는 1 점을 얻습니다 . 마지막에 가장 많은 점수를 얻은 팀이 승리합니다!

팀이 묶인 경우 첫 번째 팀에 묶인 팀과의 토너먼트가 순위 결정 순서를 결정하기 위해 진행됩니다.

실험 계획안

컨트롤러는 프로그램에 네 가지 명령 중 하나를 보냅니다. 첫 번째 문자는 필요한 경우 데이터를 따라 명령 유형을 결정합니다.

프로그램은 명령을 인수로 승인하고 1 초 내에 STDOUT에 응답합니다 . STDIN을 들으면서 살아 있지 마십시오. 각 명령은 새로운 프로세스를 생성합니다.

데이터 / 상태를 디스크에 쓸 수 있습니다. 팀과 이름이 같은 하위 폴더에 파일을 넣습니다. 32 킬로바이트 이상의 데이터를 쓰지 마십시오. 자격이 박탈됩니다. 데이터는 라운드간에 유지되지만 토너먼트 간에는 지워집니다.

명령

팀 데이터

토너먼트 시작시 팀을 등록하기 위해 한 번 전송됩니다. 답장은 일정 해야하며 토너먼트마다 다르지 않아야합니다 .

질문:

T

응답:

name|member0|member1|member2

name팀 이름이 포함 된 문자열입니다. 구문 분석을 쉽게하려면 영숫자 만 사용하십시오. memberN각 몬스터의 세부 정보를 제공하는 멤버 문자열입니다.

회원 문자열 :

name:typeid:attack:defense:speed:moveid0:moveid1:moveid2

다시, 'name'은이 몬스터의 이름을 가진 문자열입니다. typeid유형입니다. 유형 ID는 위의 차트에 표시된 순서대로 Normal = 0 및 Grass = 4입니다.

다음 3 개의 필드는 기본 통계입니다. 위의 통계 섹션에 설명 된 한도를 명심하십시오.

마지막 3 개는 몬스터의 움직임입니다. 위의 이동 차트에 ID가 표시되어 있습니다.

팀 데이터 응답 예는 다음과 같습니다.

DummyTeam|DummyA:0:50:60:70:0:1:2|DummyB:0:50:60:70:0:1:2|DummyC:0:50:60:70:0:1:2

가비지, 형식이 잘못된 데이터 또는 불법 데이터를 여기로 보내는 팀은 수정 될 때까지 참여하지 않습니다.

활성을 선택하십시오

이것은 전투가 시작될 때마다, 그리고 몬스터가 죽고 전환해야 할 때 보내집니다.

질문:

C#battleState

battleState현재 전투 상태를 보여줍니다. 여기 나와 함께, 그것은 못생긴 :

yourTeamState#theirTeamState

XteamState다음과 같은 곳 :

name:activeSlot|member0state|member1state|member2state

activeSlot현재 활성화 된 몬스터를 표시합니다 (0-2). 회원국은 두 가지 맛이 있습니다. 그것은 만약 당신의 팀이, 그것은 추가 정보를 제공합니다. 그래서,

귀하의 memberXstate :

name:id:attack:defense:speed:hp:typeid:poisonedturns:moveCount0:moveCount1:moveCount2:bonusAttack:bonusDefense:bonusSpeed:effectid:effectid:effectid

그들의 memberXstate :

name:id:attack:defense:speed:hp:typeid:poisonedturns:effectid:effectid:effectid

id는 사용을 원하지 않는 경우 몬스터를 추적하는 데 사용할 수있는 정수 식별자 name입니다.

attack:defense:speed당신의있는 기본 통계.

poisonedturns 중독 된 턴 수를 알려줍니다.

moveCountX각 움직임에 남은 사용량을 알려줍니다. 0이면 사용할 수 없습니다. 무제한 이동의 경우 음수가됩니다.

bonus(stat) 각 스탯에 할당 한 보너스 포인트입니다.

effectid몬스터에게 적용된 다양한 크기의 효과 목록입니다. 이 것 없는 후행 할 :존재 여부를 활성 효과가 있는지, 문자열에. 누적 효과가 있으면 목록에 여러 효과로 표시됩니다.

효과 ID는 다음과 같습니다.

0  NONE           (should not appear, internal use)
1  POISON
2  CONFUSION 
3  BURN 
4  SLEEP 
5  HEAL           (should not appear, internal use)
6  ATTACK_UP
7  ATTACK_DOWN
8  DEFENSE_UP
9  DEFENSE_DOWN
10 SPEED_DOWN

응답:

memberSlot

필요한 유일한 응답은 하나의 숫자 0,1,2이며 활성화하려는 멤버를 알려줍니다. 싸울 수있는 회원이어야합니다. 1멤버 1이 사망 한 경우 다시 보내지 마십시오 .

배틀 액션

매 턴마다해야 할 일을 결정해야합니다.

질문:

A#battleState

battleState전술 한 바와 같이 여기 정확히이다.

응답:

이동을 사용하려면 이동이있는 슬롯을 다시 보내십시오. 예를 들어, 펀치를 슬롯 0에 할당 한 경우 전송 0은 펀치 를 수행합니다.

다른 멤버로 전환하려면 멤버의 슬롯 에 10을 더하십시오 . 멤버 2로 전환하려면을 보내십시오 12.

[0,1,2,10,11,12]에없는 것은 무효로 간주되며 이번 차례에는 아무런 조치도 취하지 않습니다.

보너스 통계

두 번의 전투가 끝나면 각 팀원마다 비밀 보너스 포인트를받습니다.

질문:

B#yourTeamState

귀하의 팀 상태는 위에 표시된 것과 같습니다. 반복하지 마십시오.

응답:

stat0:stat1:stat2

귀하의 답변은 각 팀원에 대해 어떤 스탯을 증가시킬 것인지 나타냅니다. 공격은 0, 방어는 1, 속도는 2입니다.

따라서 멤버 1의 속도, 멤버 2의 공격 및 멤버 3의 방어를 높이려면 다음과 같이 응답하십시오.

2:0:1

제어 장치

컨트롤러는 BitBucket에서 찾을 수 있습니다 : https : //Geobits@bitbucket.org/Geobits/codemon.git

컴파일 된 모든 클래스 파일, 제출 및 players.conf를 폴더에 넣고 실행하기 만하면됩니다.

컨트롤러의 메인 클래스는이라고 Tournament합니다. 사용법은 :

java Tournament [LOG_LEVEL]

0-4의 로그 수준은 증가하는 정보를 제공합니다. 레벨 0은 토너먼트를 자동으로 실행하고 결과를 제공하며, 레벨 3은 단계별 설명을 제공합니다. 레벨 4는 디버그 출력입니다.

players.conf프로그램을 실행하는 데 필요한 명령 줄 문자열을 한 줄에 하나씩 추가 하면 토너먼트에 제출물을 추가 할 수 있습니다 . 로 시작하는 줄 #은 주석입니다.

귀하의 게시물에 추가해야 할 명령 players.conf및 모든 컴파일 단계 (필요한 경우)를 포함하십시오.

3 명의 노멀 동작으로 모든 노멀 멤버로 구성된 더미 팀이 포함됩니다. 그들은 무작위로 이동을 선택하고 통계가 끔찍합니다. 그들에게 치는 재미.

기타 규칙

  • 외부 리소스를 읽거나 쓸 수 없습니다 (자신의 하위 폴더, 위에서 언급 한대로 최대 32kB 제외).

  • 당신의 팀은 토너먼트 "맹인"에 들어가야합니다. 즉, 특정 상황에서 특정 팀 / 몬스터가 무엇을하는지 파악하기 위해 다른 사람들의 출처를 분석 할 수 없습니다. 당신은 할 수 없는 하드 코딩에게이 정보를 상대의 움직임 / 통계를 분석하지 않으며 대회 진행을 추적하지만.

  • 다른 프로세스 / 제출을 방해하지 마십시오. 리플렉션을 사용하여 데이터를 얻는 등의 작업을 수행하지 않습니다. 내 컴퓨터를 엉망으로 만들지 마십시오. 시도하지 마십시오. 이것은 나의 재량에 달려 있습니다. 위반자는 향후 입장이 금지 될 수 있습니다.

  • 참가자는 최대 항목 으로 제한됩니다 . 더 제출하면 제출 한 처음 두 개만 채점합니다. 취소하려면 삭제하십시오.

  • 다른 출품작을 홍보하기위한 출품작 만 존재할 수는 없습니다. 또한 다른 참가자를 간접적으로 실격 처리하려고하지 않을 수 있습니다 (예 : 디스크에 쓰려고하는 DQ 플레이어에게 27M 캐릭터 팀 이름 사용). 각 제출물은 자체 장점을 얻기 위해 재생되어야합니다.

  • 프로그램은 한 번에 최대 하나의 자식 프로세스를 생성 할 수 있습니다 (직접적인 것이 아닌 전체 자손). 기본 프로세스와 하위 프로세스는 모두 출력을 제공 한 후 바로 종료해야합니다. 어느 쪽이든, 시간 초과를 피하지 마십시오.

  • 토너먼트는 Intel i7 3770K 프로세서가 장착 된 Ubuntu를 실행하는 컴퓨터에서 진행됩니다.

결과

이것은 현재 플레이어의 결과입니다. 그것은이다 매우 최고 경쟁자 간의 긴밀한, 나는 500까지 라운드의 수를 해주 (및 보너스 포인트의 간격이 일치하도록 조정)에 대해 생각하고 있어요. 의견이나 의견이 있으십니까?

------- Final Results -------

158     Happy3Campers
157     LittleKid
71      InsideYourHead
68      HardenedTrio
46      BitterRivals

Google 드라이브 에서 전체 재생 별 결과


62
나는 최고가되고 싶다 / 코드가 없었던 것처럼 / 충돌하지 않는 것은 나의 테스트이다 / 디버그하는 것이 나의 원인이다! / 나는 LAN을 가로 질러 여행 할 것이다 / 멀리 넓은 스크립팅 / 이해하려고 노력하는 이유 / BIOS가 왜 빠졌는가! / Codémon, 그것은 당신과 나 / 모든 눈을 볼 수있는 골프 / Codémon, 당신은 내 가장 친한 친구입니다 / 프로그램이 끝난 후! / Codémon, lang so true / segfaults는 우리를 끌지 않을 것입니다 / 당신은 저를 가르쳐 줄 것입니다 / Codémon, 모든 골프를 줘야합니다!
Kaz Wolfe

1
한 라운드를 500으로 늘리는 대신 한 라운드가 모든 사람과 싸우는 것으로 구성되는 것이 좋습니다. 따라서 더 이상 bye고르지 않은 수의 경쟁자에게도 적합 하지 않으며 경기 쌍이 공정하고 고르게 분포되어 있는지 확인합니다.
foobar

@foobar 나는 n^2대신에 전투를 확장하기 때문에 그것을 피하고 싶었다 n. 현재 7 개의 경쟁자와 100 개의 라운드 만 있으면 2100 번의 전투 (300 대 그대로, 1500 번의 500 회)입니다. 더 많은 참가작이 들어 오면 더 나빠집니다. 라운드 수를 줄일 수는 있지만 고유 한 변동성 (상태 esp 관련)으로 인해 50 배 (보너스 포인트)가 더 쉬워집니다.
Geobits

이 도전에 업데이트가 필요하지 않습니까? :)
GholGoth21

@ GholGoth21 네, 그렇습니다. 나는 오늘 그것을 얻을 수 없지만 아마 내일이나 다음날에 갈 수 있습니다. 목요일까지 업데이트하지 않으면 채팅으로 핑 (Ping)합니다.
Geobits

답변:


16

행복한 3 명의 야영 자-PHP

쇠약 한 주문으로 야당을 망치고 썩어가는 것을 지켜보고자하는 겁쟁이들.

편집 : Lumpy 씨는 심하게 겁에 질려 더 이상 나쁜 말을하지 않습니다


능숙한능숙한Grass - atk:50 def:99 spd:81 Confuse Poison Heal

문제가있는 핸드 셰이크와 사람들을 혼동하는 것을 좋아하는 악의없는 무기 비버


플리 피플리 피Water - atk:50 def:99 spd:81 Confuse Burn Heal

어리석은 대화와 화염 전쟁을위한 부드러운 장소가있는 게시판 베테랑.


멋진멋진Fire - atk:50 def:99 spd:81 Burn Poison Heal

대량 살상 무기는 그의 가장 좋아하는 사탕이다.


울퉁불퉁울퉁불퉁Php - lines:500 clarity:05 spd:01 Gather Guess Store

거의 2 자리의 IQ와 경이로운 기억 덕분에 Lumpy는 적의 움직임을 추측 할 수 있습니다. 글쎄요.


전략

이 전략은 가능한 빨리 적을 독살하고 태우고 혼란스럽게하는 것입니다.
수면은 위의 3 가지 주문보다 덜 강력 해 보였으므로 사용되지 않았습니다.
혼돈은 장기적으로 치명적입니다. 공격은 공격을 30 % 줄이며 (손상 처리와 주문 시전 모두) 치유자가 스스로 치유하지 못하도록하고 무거운 타자를 심하게 손상시킵니다. ).

적을 완전히 붙인 후, 야영 자들은 단순히 그를 지글 거리고 부패하며 죽임을당하는 모습을 본다.

높은 방어력과 치유력은 고통 중에 들어오는 피해를 완화하는 데 사용됩니다.

나의 3 명의 야영자가 싸우고있는 동안, Lumpy 마술 사슴은 매 움직임마다 적을 감시하고 때때로 그들을 식별 할 수 있습니다. 정보는 전투기를 이용하기 위해 최선을 다하는 전투기에게 피드백됩니다.

방어 후 속도는 가장 중요한 스탯입니다.
이니셔티브는 다음 타격이 다가 오기 전에 치유를 적용하는 데 중요합니다.

공격은 전혀 사용되지 않습니다.

주문은 최고의 무기입니까?

독, 번 및 혼동과 같은 주문은 다른 공격의 전체적인 암석 / 종이 / 가위 논리를 피합니다.

몬스터가 영향을 받으면, 주문 캐스터가 죽은 후에도 계속 HP를 잃습니다. 마치 캐스터의 유령이 계속 그를 공격하는 것처럼 보입니다.
게다가 독은 완전히 강화 된 대규모 공격 (5 턴 후 50 포인트 이상)보다 빠르게 강력 해집니다.

중독되고 탄 몬스터의 평균 수명은 3 번의 치유로도 8 턴을 넘지 않습니다.

으로 마틴의 봇 을 시사, 게임 밸런스가 아주 좋은 것입니다.
기본적으로 순수한 주문 캐스터와 순수한 공격자 사이의 균형을 유지하는 이니셔티브입니다.

코드

호출 php campers.php

그것은 추악한 혼란이지만 솔직히 인터페이스가 도움이되지 않습니다.

적절하게 공격적인 경쟁이 나타 났으므로, 나는 오랫동안 계획된 적의 움직임 추측을 구현했습니다.
공격을 분석하려면 다양한 곡예 비학 추론과 마지막 회전 상태를 지속적으로 저장해야합니다. 이는 편집증 컨트롤러 인터페이스와의 대규모 전쟁을 의미합니다.
그것은 좋은 물건도 아니고 6 다리 잭 래빗도 아니지만 적절한 작업을 수행합니다.

<?php

// ============================================================================
// Game
// ============================================================================
class G {
    static $code_type = array ("Normal", "Psychic", "Fire", "Water", "Grass", "?", "self"); 
    static $code_move = array    ("Punch", "Heal", "Slow", "Pain", "Sleep", "Weaken", "Fireball", "Burn", "Sharpen", "Watergun", "Confuse", "Shield", "Vine", "Poison", "Sap", "?", "self", "pass");
    static $move_uses = array (1000,3,5,1000,3,5,1000,3,5,1000,3,5,1000,3,5,   2000,2000);
    static $move_type      = array (0,0,0,1,1,1,2,2,2,3,3,3,4,4,4, 5,5,5);
    static $move_dmg       = array (20,0,10,20,0,10,20,0,10,20,0,10,20,0,10,  20,10,0);
    static $move_forbidden = array (1,1,1,0,0,0,4,4,4,2,2,2,3,3,3);
    static $code_effect = array ("N", "Poison", "Confuse", "Burn", "Sleep", "H", "Sharpen", "Weaken", "Shield", "Sap", "Slow"); 
    static $decode_type, $decode_move, $decode_effect;
    static $damage_multiplier = array (
        array (2, 0, 1, 1, 1, 0),
        array (0, 2, 1, 1, 1, 0),
        array (1, 1,.5, 2,.5, 0),
        array (1, 1,.5,.5, 2, 0),
        array (1, 1, 2,.5,.5, 0),
        array (2, 2, 2, 2, 2,-1),
        array (9, 9, 9, 9, 9, 9, 1));
    static $atk_score = array ("Poison"=> 1002, "Confuse"=>1001, "Burn"=>1000);
    static $status_field = "atk:def:spd:hp:type:Pturns";
    static $all_moves, $strong_moves, $medium_moves, $effect_moves, $possible_moves;

    function init()
    {
        self::$status_field = explode (":", self::$status_field);
        foreach (array ("type", "move", "effect") as $table) self::${"decode_$table"} = array_flip (self::${"code_$table"});
        foreach (self::$code_move as $c=>$m)
        {
            if ($m == "?") break;
            self::$all_moves[] = new Move($m);
            if (self::$move_uses[$c] >  5) self::$strong_moves[] = $m;
            if (self::$move_uses[$c] == 5) self::$medium_moves[] = $m;
            if (self::$move_uses[$c] == 3) self::$effect_moves[] = $m;
            for ($type = 0 ; $type != 5 ; $type++) if ((self::$move_uses[$c] >  5) && (self::$move_forbidden[$c] != $type)) self::$possible_moves[$type][] = $m;
        }
    }

    function __construct ($name, $team)
    {
        $this->turn = 0;
        $this->name = $name;
        $this->team = $team;
        $this->results_pending = false;
    }

    function parse_team ($tpack, $own_team)
    {
        $pack = explode ("|", $tpack);
        list ($name,$active) = explode (":", array_shift($pack));
        if ($own_team)
        {
            $team = $this->team;
        }
        else
        {
            if (!isset($this->enemies[$name])) $this->enemies[$name] = new Team(array (new Monster (), new Monster (), new Monster ()));
            $team = $this->foes = $this->enemies[$name];
        }
        $team->active = $active;
        foreach ($pack as $i=>$mpack) $team->monster[$i]->parse_monster ($own_team, $mpack);
    }

    function choose_active ()
    {
        // detect start of round
        $team = $this->team;
        $foes = $this->foes;
        foreach ($team->monster as $i=>$m) if ($m->hp > 0) $candidate[$i] = $m;
        if (count ($candidate) == 3)
        {
            $this->results_pending = false;
            $this->round++;

            // reinitialize all monsters
            foreach (array($team, $foes) as $t)
            foreach ($t->monster as $m)
                $m->start_round();

            // guess initial opponent
            $opponent = $foes->initial_opponent();
        }
        else
        {
            $this->analyze_last_round();
            $opponent = $foes->active();
        }
        return $this->do_switch ($opponent);
    }

    function choose_attacker ($foe)
    {
        foreach ($this->team->monster as $i=>$m) if ($m->can_attack($foe)) $candidate[$i] = $m;
        if (isset($candidate))
        {
            uasort ($candidate, function ($a,$b) use ($foe) { return ($a->atk_score != $b->atk_score) ? $b->atk_score - $a->atk_score : $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            return key($candidate);
        }
        return -1;
    }

    function do_switch ($foe)
    {
        $replacement = $this->choose_attacker ($foe);
        if ($replacement < 0)
        {
            $candidate =  $this->team->monster;
            uasort ($candidate, function ($a,$b) use ($foe) { return $b->life_expectancy($foe) - $a->life_expectancy($foe); });
            $replacement = key($candidate);
        }

        $this->old_own = $this->team->monster[$replacement];
        $this->old_own->attack = "pass";
        return $replacement;
    }

    function choose_action ()
    {
        $this->analyze_last_round();
        $own = $this->team->active();
        $foe = $this->foes->active();
        $this->old_own = $own;

        if ($own->hp <= $own->max_damage($foe) && $own->can_do ("Heal")) return $own->execute("Heal");
        if ($attack = $own->can_attack($foe)) return $own->execute($attack);
        if ($own->hp <= 50 && $own->can_do ("Heal")) return $own->execute("Heal");

        return 10 + $this->do_switch ($foe);    
    }

    function choose_bonus()
    {
        foreach ($this->team->monster as $m)
        {
            if ($m->spd_b == 0) { $m->spd_b++; $res[] = 2; }
            else                { $m->def_b++; $res[] = 1; }
        }
        return implode (":", $res);
    }

    function parse ($parts)
    {
        self::parse_team ($parts[1], true);
        self::parse_team ($parts[2], false);    
    }

    function analyze_last_round()
    {
        if ($this->results_pending)
        {
            $this->results_pending = false;

            $foes = $this->foes;
            $foe = null;
            foreach ($foes->monster as $m) if ($m->hp != $m->old->hp) $foe = $m;
            if ($foe === null) $foe = $foes->monster[$foes->active];

            $this->old_own->guess_attack($foe);
        }
    }

    function process ($line)
    {
        $parts = explode ("#", $line);
        switch ($parts[0])
        {
        case "T": // register for tournament
            echo "$this->name|$this->team";
            break;
        case "C": // designate active monster
            $this->parse ($parts);
            echo $this->choose_active();
            break;
        case "A": // choose round action
            $this->parse ($parts);
            echo $this->choose_action();

            // save current state
            foreach (array($this->team, $this->foes) as $t)
            foreach ($t->monster as $m)
            {
                unset ($m->old);
                $m->old = clone ($m);
            }
            $this->results_pending = true;
            break;
        case "B": // distribute stat bonus
            echo $this->choose_bonus();
            break;
        }

    }
}
G::init();

// ============================================================================
// Move
// ============================================================================
class Move {
    function __construct ($move)
    {
        $this->register($move);
    }

    function register ($move)
    {
        $this->type = G::$decode_move[$move];
        $this->reinit();
    }

    function reinit()
    {
        $this->uses = G::$move_uses[$this->type];
    }

    function __tostring() { return G::$code_move[$this->type]."($this->uses)"; }
}

// ============================================================================
// Monster
// ============================================================================
class Monster { 
    function __construct ($name="?", $type="?", $atk=100, $def=100, $spd=100, $m0="?", $m1="?", $m2="?")
    {
        $this->name = $name;
        $this->type = G::$decode_type[$type];
        $this->atk  = $atk;
        $this->def  = $def;
        $this->spd  = $spd;
        $this->hp   = 100;
        $this->move = array (new Move($m0), new Move($m1), new Move($m2));
        $this->atk_b = 0;
        $this->def_b = 0;
        $this->spd_b = 0;
        foreach (G::$code_effect as $e) $this->$e = 0;
    }

    function __tostring ()
    {
        return implode (":", array (
            $this->name,
            $this->type,
            $this->atk,
            $this->def,
            $this->spd,
            $this->move[0]->type,
            $this->move[1]->type,
            $this->move[2]->type));
    }

    function start_round()
    {
        foreach ($this->move as $m) $m->reinit();
    }

    function parse_monster ($own_team, $spack)
    {
        $pack = explode (":", $spack);
        $name = array_shift ($pack); // get name
        array_shift ($pack); // skip id
        if ($this->name == "?") $this->name = $name; // get paranoid
        else if ($this->name != $name) die ("expected $this->name, got $name");

        // store updated values
        foreach (G::$status_field as $var) $this->$var = array_shift ($pack);
        if ($own_team)
        {
            foreach ($this->move as $m) $m->new_count = array_shift($pack);
            $pack = array_slice ($pack, 3); // these are maintained internally
        }
        $var = array();
        foreach ($pack as $e) @$var[G::$code_effect[$e]]++; 
        foreach (G::$code_effect as $e) $this->$e = @$var[$e]+0;
    }

    function damage_recieved ($attack, $foe=null)
    {
        if ($attack == "self") $foe = $this;
        $a = G::$decode_move[$attack];
        $type = G::$move_type[$a];
        $dmg = g::$move_dmg[$a];

        if ($dmg == 0) return 0;

        $atk = ($foe ->atk+$foe ->atk_b) * pow (.8, ($foe ->Weaken - $foe ->Sharpen));
        $def = ($this->def+$this->def_b) * pow (.8, ($this->Sap    - $this->Shield ));

        $boost = ($foe->type == $type) ? 1.2 : 1;
        return max (floor ($dmg * $atk / $def * $boost * G::$damage_multiplier[$this->type][$type]), 1);
    }

    function guess_attack_from_effect ($attacks)
    {
        foreach ($attacks as $status) if ($this->$status != $this->old->$status) return $status;
        return "?";
    }

    function guess_attack_from_damage ($foe, $damages)
    {
        $select = array();
        foreach (G::$possible_moves[$foe->type] as $attack)
        {
            $dmg = $this->damage_recieved ($attack, $foe);
            foreach ($damages as $damage) if ($damage != 0 && abs ($dmg/$damage-1) < 0.1) $select[$attack] = 1;
        }
        $res = array();
        foreach ($select as $a=>$x) $res[] = $a;
        return $res;
    }

    function guess_attack ($foe)
    {
        $attempt = G::$decode_move[$this->old->attack];
        $success = ($this->old->attack == "pass");
        foreach ($this->move as $m)
        {
            if ($m->type == $attempt)
            {
                if ($m->new_count == $m->uses-1)
                {
                    $m->uses--;
                    $success = true;
                }
                break;
            }
        }

        $possible = array();
        $attack = $this->guess_attack_from_effect (array("Burn", "Confuse", "Poison", "Sleep", "Slow", "Weaken", "Sap"));
        if ($attack == "?") $attack = $foe->guess_attack_from_effect (array("Sharpen", "Shield"));
        if ($attack == "?")
        {
            $foe_damage = $this->old->hp - $this->hp - (10 * $this->Burn + 5 * $this->Pturns*$this->Poison);
            if ($this->old->attack == "Heal" && $success) $foe_damage += 50;
            $possible_dmg[] = $foe_damage;
            //;!;if ($this->Confuse) $possible_dmg[] = $foe_damage + $this->damage_recieved ("self");
            $possible = $this->guess_attack_from_damage ($foe, $possible_dmg);
            if (count ($possible) == 1) $attack = $possible[0];
        }
        if ($attack == "?")
        {
            $own_damage = $foe->old->hp - $foe->hp 
                        - (10 * $foe->Burn + 5 * $foe->Pturns*$foe->Poison)
                        + $foe->damage_recieved ($this->attack);
            if (abs ($own_damage/50+1) < 0.1) $attack = "Heal";
        }
        if ($attack != "?")
        {
            $type = G::$decode_move[$attack];
            if ($attack != "?")
            {
                foreach ($foe->move as $m) if ($m->type == $type) goto found_old;
                foreach ($foe->move as $m) if ($m->type == 15) { $m->register($attack); goto found_new; }
            }
            found_new:
            found_old:
        }
    }

    function max_damage($foe)
    {
        $dmg = 0;
        foreach ($foe->move as $m) $dmg = max ($dmg, $this->damage_recieved (G::$code_move[$m->type], $foe));
        return $dmg;
    }

    function expected_damage ($foe)
    {
        return $this->max_damage($foe) + 10 * $this->Burn + 5 * ($this->Pturns+1);
    }

    function life_expectancy ($foe)
    {
        $hp = $this->hp;
        $poison = $this->Pturns;
        $heal = $this->can_do ("Heal");
        $dmg = $this->max_damage($foe);
        for ($turn = 0 ; $hp > 0 && $turn < 10; $turn++)
        {
            $hp -= 10 * $this->Burn + 5 * $poison;
            if ($poison > 0) $poison++;
            $hp -= $dmg;
            if ($hp <= 0 && $heal > 0) { $hp+=50; $heal--; }
        }
        return 100 * $turn + $this->hp;
    }

    function can_attack ($foe)
    {
        $attack = false;
        if ($this->hp > 0)
        {
            if      (!$foe->Poison  && $this->can_do ("Poison" )) $attack = "Poison";
            else if (!$foe->Confuse && $this->can_do ("Confuse")) $attack = "Confuse";
            else if (!$foe->Burn    && $this->can_do ("Burn"   )) $attack = "Burn";
        }
        $this->atk_score = ($attack === false) ? 0 : G::$atk_score[$attack];
        return $attack;
    }

    function can_do($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $m) if ($m->type == $type && $m->uses > 0) return $m->uses;
        return false;
    }

    function execute($move)
    {
        $type = G::$decode_move[$move];
        foreach ($this->move as $i=>$m) if ($m->type == $type) 
        { 
            if ($m->uses > 0)
            {
//;!;               $m->uses--;
                $this->attack = $move;
            }
            else $this->attack = "pass";
            return $i; 
        }
        die ("$this asked to perform $move, available ".implode(",", $this->move));
    }
}

// ============================================================================
// Team
// ============================================================================
class Team {
    function __construct ($members)
    {
        $this->monster = $members;
    }

    function __tostring()
    {
        return implode ("|", $this->monster);
    }

    function active ()
    {
        return $this->monster[$this->active];
    }

    function initial_opponent()
    {
        return $this->monster[0];
    }
}

// ============================================================================
// main
// ============================================================================
$input = $argv[1];

$team_name = "H3C";
$mem_file = "$team_name/memory.txt";
$trc_file = "$team_name/trace.txt";
if (!file_exists($team_name)) mkdir($team_name, 0777, true) or die ("could not create storage directory '$team_name'");
if ($input == "T") array_map('unlink', glob("$team_name/*.txt"));

if (file_exists($mem_file)) $game = unserialize (file_get_contents ($mem_file));
else
{
    $team = new Team (
        array (
            new Monster ("Handy" , "Grass" , 50, 99, 81, "Confuse", "Poison", "Heal"),
            new Monster ("Nutty" , "Fire"  , 50, 99, 81, "Burn"   , "Poison", "Heal"),
            new Monster ("Flippy", "Water" , 50, 99, 81, "Confuse" , "Burn" , "Heal")));
    $game = new G($team_name,$team);
}

$game->process ($input);
file_put_contents ($mem_file, serialize($game));

결과

LittleKid는 여전히 위협적이지만, 내 트리오는 그의 악의적 인 괴물을 상당히 능가했습니다.

Martin의 봇은 이니셔티브가 부족하여 운명에 처해 있으며, 속도를 높이려면 공격력을 낮추어야합니다.

플래닛 JavaScript의 새로운 경쟁자들은 일대일로 팀과 동등한 수준이지만 다른 경쟁자 들과는 더 나빴습니다. 실제로 LittleKid의 점수를 낮추는 데 도움이됩니다. :).

내 귀여워 친구들이 언덕의 왕으로 남아있는 것 같습니다-지금은 ...

170             H3C
158             Nodemon
145             LittleKid
55              InsideYourHead
42              HardenedTrio
30              BitterRivals

그리고 나도 PHP를 가지고 있지 않습니다. 나는 메타 포드로 바닥을 걸레질 할 것을 기대합니다. 왜냐하면 그들은 느린 걸음을 내딛고 죽음에 중독 될 것이기 때문입니다.
Sp3000

... * 그리고 *는 바삭 바삭 : D. 복잡한 규칙의 문제입니다. 지배적 인 전략이 등장 할 가능성이 높습니다. 이 주문들에 대한 보호는 없기 때문에 코 데몬의 뚱뚱한 남자와 어린 소년 일 수 있습니다.

가위, 종이, 바위와 같은 비 과도적인 게임과
비교해 보았습니다.

2
그렇습니다. Poison and Burn에 대한 치료법이 보이지 않는 즉시 상상했던 것입니다. 내 꿈을 실현시켜 주셔서 감사합니다.
justhalf

1
Lumpy는 같은 적으로부터 3 가지 이상의 다른 공격을 감지했을 때 의아해를 표현합니다. :) 나는 거의 완전한 고정 버전을 가지고 있지만, 나는 지금 다른 어떤 것의 한가운데에 있으므로 수정은 하루 정도에 게시 될 것입니다.

7

강화 된 트리오, 파이썬 3

Geobits는 우리에게 두 번의 제출 을하기에 충분히 좋았 기 때문에 첫 번째 항목에 대해 바보 같은 것을 제출할 것이라고 생각했습니다. : P

파티는 같은 통계와 이동을 가진 3 개의 Codemon (Metapod1, Metapod2, Metapod3)입니다.

  • 공격 80, 방어 100, 속도 50
  • 펀치, 치유, 방패 강화

모든 보너스 포인트도 방어에 할당됩니다.


from collections import namedtuple
import sys

BattleState = namedtuple("BattleState", ["us", "them"])
TeamState = namedtuple("TeamState", ["name", "active", "members"])
MemberState = namedtuple("MemberState", ["name", "id", "attack", "defense", "speed", "hp",
                                         "typeid", "poisonedturns", "otherstats"])

def parse_battle_state(state):
    return BattleState(*map(parse_team_state, state.split("#")))

def parse_team_state(state):
    na, *members = state.split("|")
    name, active = na.split(":")
    return TeamState(name, int(active), list(map(parse_member_state, members)))

def parse_member_state(state):
    name, id_, attack, defense, speed, hp, typeid, poisonedturns, *rest = state.split(":")
    return MemberState(name, int(id_), float(attack), float(defense), float(speed),
                       float(hp), int(typeid), int(poisonedturns), rest)

command = sys.argv[1].strip()

if command.startswith("T"):
    print("HardenedTrio|Metapod1:0:80:100:50:0:1:11|"
          "Metapod2:0:80:100:50:0:1:11|Metapod3:0:80:100:50:0:1:11")

elif command.startswith("C"):
    battle_state = parse_battle_state(command[2:])

    for i, codemon in enumerate(battle_state.us.members):
        if codemon.hp > 0:
            print(i)
            break

elif command.startswith("A"):
    battle_state = parse_battle_state(command[2:])
    current_codemon = battle_state.us.members[battle_state.us.active]

    if current_codemon.hp < 50 and int(current_codemon.otherstats[1]) > 0:
        print(1) # Heal up if low

    elif int(current_codemon.otherstats[2]) > 0:
        print(2) # Harden!

    else:
        print(0) # Punch!

elif command.startswith("B"):
    print("1:1:1")

로 실행

py -3 <filename>

(또는 설치 에 따라 대신 python/로 )python3py



1
@FryAmTheEggman 메타 포드,하든!
Sp3000

코드를 읽으려고하는데에 혼란스러워했습니다 int(current_codemon.otherstats[1])>0. 그가 상태 효과가 있다면 true를 반환합니까? 그리고 그는 두 가지 상태 효과가있는 경우에만 강화를 사용합니까?
Mooing Duck

@MooingDuck Codemon의 경우 moveCountS보다 먼저 있어 effectid여전히 Harden을 사용할 수 있는지 여부를 확인합니다. 나는 파싱에 게으르다. 그래서 거기에 집중된다.
Sp3000

@ Sp3000 : 아! 권리! 하하하!
Mooing Duck

6

머리 속으로, 루비

  • 브라이언 : 사이 킥, 공격력 : 100, 방어 : 50, 속도 : 80, 고통, 화염 구, 물총
  • Elemon1 : Psychic, 공격력 : 100, 방어력 : 50, 속도 : 80, Fireball, Watergun, Vine
  • Elemon2 : Psychic, 공격력 : 100, 방어력 : 50, 속도 : 80, Fireball, Watergun, Vine
TEAM_SPEC = "InsideYourHead"+
            "|Brian:1:100:50:80:3:6:9"+
            "|Elemon1:1:100:50:80:6:9:12"+
            "|Elemon2:1:100:50:80:6:9:12"

def parse_battle_state request
    request.map do |team_state|
        state = {}
        parts = team_state.split '|'
        state[:active] = parts.shift.split(':')[1].to_i
        state[:monsters] = parts.map do |monster_state|
            monster = {}
            parts = monster_state.split(':')
            monster[:name] = parts[0]
            monster[:hp] = parts[5].to_i
            monster[:type] = parts[6].to_i
            monster
        end
        state
    end
end

request = ARGV[0].split '#'
case request.shift
when 'T'
    puts TEAM_SPEC
when 'C'
    battle_state = parse_battle_state request
    my_state = battle_state[0]
    puts my_state[:monsters].find_index {|monster| monster[:hp] > 0}
when 'A'
    battle_state = parse_battle_state request
    my_state, their_state = *battle_state
    my_monster = my_state[:monsters][my_state[:active]]
    their_monster = their_state[:monsters][their_state[:active]]
    puts [1,0,1,2,0][their_monster[:type]]
when 'B'
    puts '0:0:0'
end

로 실행

ruby InsideYourHead.rb

이것은 Manu의 봇에 대해서는 잘 작동하지 않지만 다른 세 가지를 능가합니다. 팀과 몬스터 이름은 매우 무작위입니다. 더 나은 것을 생각해 내면 이름이 변경 될 수 있습니다.

전략은 매우 간단합니다 : 공격! 세 몬스터는 모두 순수한 공격 동작 만하며 상대 몬스터의 유형에 따라 이동을 선택합니다.

나중에 치료를 던지는 실험을 할 수도 있습니다.


1
그는 더욱 흥미로워진다. 내가 당신을 믿을 수 있다는 것을 알았습니다, Martin :)

6

리틀 키드, 자바

어린 꼬마가 3 개의 동일한 코 데몬을 발견하고 훈련 시켰습니다. 그들은 치료 + 독 공격에 매우 성가신입니다. 독은 모든 유형에 대해 잘 작용하기 때문에 일반 유형의 코 데몬 만 사용하면 특정 적과 짝을 지을 필요가 없습니다.

public class LittleKid {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("Geobits says you can't do this.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "LittleKid";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                out += "|Poisoner:0:80:100:50:0:1:13";
                break;
            case "B":
                out = "1:1:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];
                int pick = 0;

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = String.valueOf(pick);
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int enemyActive = getActive(them);
                if (getField(me, HP, active) < 50 && getField(me, MOVE1, active) != 0) {
                    out = "1";
                } else if (getEffectCount(them, POISON, enemyActive, false) < 1 && getField(me, MOVE2, active) != 0) {
                    out = "2";
                } else {
                    out = "0";
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6;
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10;

    final static int POISON =           1;
}

5
" Geobits는이 작업을 수행 할 수 없다고 말합니다 ": D
Geobits

독 :이 게임에서 실제 A-폭탄 보인다

5

노 데몬-자바 스크립트

지위가 지배적 인 전략 인 것처럼 보이기 때문에이 팀은 먼저 독과 혼동과 같은 상태를 상대방에게 알리는 속도에 중점을 둔 다음 상대가 낭비하는 동안 치유 및 / 또는 수면 상태에 빠집니다.

나는 PHP를 설치하지 않았기 때문에 이것은 Campers에 대해 테스트되지는 않았지만 LittleKid와의 시험에서 좋은 경쟁자 인 것 같습니다 (그리고 Bitter Rivals를 죽입니다).

/*jshint node:true*/
'use strict';

var fs = require('fs');

var dataFile = 'Nodemon/data.json';
function getData(callback) {
  fs.readFile(dataFile, 'utf8', function(err, contents) {
    var data = {round: 0};

    if(!err) {
      data = JSON.parse(contents);
    }

    callback(data);
  });
}

function saveData(data, callback) {
  fs.mkdir('Nodemon', function() {    
    fs.writeFile(dataFile, JSON.stringify(data), callback);
  });
}

var effect = {
  poison: '1',
  confusion: '2',
  burn: '3',
  sleep: '4',
  heal: '5',
  attackUp: '6',
  attackDown: '7',
  defenseUp: '8',
  defenseDown: '9',
  speedDown: '10'
};

function parseMemberCommon(args) {
  return {
    name: args[0],
    id: args[1],
    baseAttack: +args[2],
    baseDefense: +args[3],
    baseSpeed: +args[4],
    hp: +args[5],
    typeId: args[6],
    poisonedTurns: +args[7],
    effects: args.slice(8)
  };
}

function parseOwnMember(arg) {
  var args = arg.split(':');

  var ownArgs = args.splice(8, 6);

  var member = parseMemberCommon(args);

  member.moveCount = [
    +ownArgs[0],
    +ownArgs[1],
    +ownArgs[2]
  ];

  member.bonusAttack = +ownArgs[3];
  member.bonusDefense = +ownArgs[3];
  member.bonusSpeed = +ownArgs[3];

  return member;
}

function parseOpponentMember(arg) {
  return parseMemberCommon(arg.split(':'));
}

function parseTeamStateCommon(arg, memberParse) {
  var args = arg.split(':');
  var state = {
    name: args[0],
    members: []
  };
  args = arg.substring(state.name.length + 1).split('|');
  var activeSlot = args[0];
  for(var index = 1; index < args.length; index++) {
    state.members.push(memberParse(args[index]));
  }
  state.activeMember = state.members[activeSlot];
  return state;
}

function parseOwnState(arg) {
  return parseTeamStateCommon(arg, parseOwnMember);
}

function parseOpponentState(arg) {
  return parseTeamStateCommon(arg, parseOpponentMember);
}

function parseBattleState(arg) {
  var args = arg.split('#');
  return {
    own: parseOwnState(args[0]),
    opponent: parseOpponentState(args[1])
  };
}

function teamData() {

  saveData({round:0}, function() {
    console.log('Nodemon|' + 
      'Charasaur:0:50:80:100:10:13:1|' +
      'Bulbtortle:4:50:80:100:10:13:1|' +
      'Squirtmander:1:50:80:100:10:13:4');
  });
}

function getActiveIndex(battleState) {
  for(var index = 0; index < battleState.own.members.length; index++) {
    var member = battleState.own.members[index];
    if(member.hp > 0) {
      return index;
    }
  }
}

function chooseActive(arg) {
  var battleState = parseBattleState(arg);

  getData(function(data) {
    var allFull = true;
    for(var index = 0; index < battleState.opponent.members.length; index++) {
      var member = battleState.opponent.members[index];
      if(!data.maxSpeed || member.baseSpeed > data.maxSpeed) {
        data.maxSpeed = member.baseSpeed;
      }
      if(member.hp < 100) {
        allFull = false;
      }
    }

    if(allFull) {
      data.round++;
    }

    saveData(data, function() {
      console.log(getActiveIndex(battleState));
    });    
  });
}

function useMove(moves, battleState) {
  var fighter = battleState.own.activeMember;

  for(var moveIndex = 0; moveIndex < moves.length; moveIndex++) {
    var move = moves[moveIndex];
    if(fighter.moveCount[move]) {
      return move;
    }

    for(var memberIndex = 0; memberIndex < battleState.own.members.length; memberIndex++) {
      var member = battleState.own.members[memberIndex];

      if(member.hp > 0 && member.moveCount[move] > 0) {
        return 10 + memberIndex;
      }
    }
  }

  return -1;  //do nothing
}

function battleAction(arg) {
  var battleState = parseBattleState(arg);

  var fighter = battleState.own.activeMember;
  var opponent = battleState.opponent.activeMember;

  var attemptedMoves = [];

  if(opponent.effects.indexOf(effect.poison) === -1) {
    attemptedMoves.push(1);
  }

  if(opponent.effects.indexOf(effect.confusion) === -1) {
    attemptedMoves.push(0);
  }

  if(fighter.name === 'Squirtmander') {
    //sleep
    if(opponent.effects.indexOf(effect.sleep) === -1) {
      attemptedMoves.push(2);
    }
  }
  else {
    //heal
    if(fighter.hp <= 60) {
      attemptedMoves.push(2);
    }
  }

  console.log(useMove(attemptedMoves, battleState));
}

function bonusStats(arg) {
  var teamState = parseOwnState(arg);

  getData(function(data) {
    var result = '1:';

    if(data.round % 4 === 0) {
      result += '1:';
    }
    else {
      result += '2:';
    }
    if(teamState.members[2].baseSpeed + teamState.members[2].bonusSpeed > data.maxSpeed + (data.round / 2)) {
      result += '1';
    }
    else {
      result += '2';
    }
    console.log(result);
  });
}

var actions = {
  'T': teamData,
  'C': chooseActive,
  'A': battleAction,
  'B': bonusStats
};

var arg = process.argv[2];
actions[arg[0]](arg.substring(2));

로 실행

node nodemon

nodemon에 대한 PS 사과 .


이것은 서버 측 스크립트 글로벌 전쟁으로 확대되고 있습니다. : D

4

쓴 라이벌-자바

잔디 / 화재 / 물 팀이 좋아합니다.

그린 사우루스

누구에게나 최소한 중립적 인 범위를 갖습니다. 방어력 부족을 보완하는 고속.

Type: Grass
Attack:   80     Vine
Defense:  50     Punch
Speed:   100     Pain

시리 자드

낮은 공격력으로 적을 사로 잡으려고합니다. 그 후 화상과 불 덩어리.

Type: Fire
Attack:  100     Fireball
Defense:  50     Burn
Speed:    80     Sap

방풍

방패를 사용하여 이미 높은 방어력을 향상시킵니다. 필요할 때 치유합니다.

Type: Water
Attack:   80     Watergun
Defense: 100     Shield
Speed:    50     Heal

암호

이것은 컨트롤러에도 포함되어 있습니다. 이 팀 DummyTeam과 달리 경쟁 팀입니다. 필요한 명령 players.conf은 다음과 같습니다.

java BitterRivals

public class BitterRivals {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You're not doing this right. Read the spec and try again.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String me, them, out = "";
        switch(sections[0]){
            case "T":
                out = "BitterRivals";
                out += "|Greenosaur:4:80:50:100:12:0:3";
                out += "|Searizard:2:100:50:80:6:7:14";
                out += "|Blastshield:3:80:100:50:9:11:1";
                break;
            case "B":
                out = "2:0:1";
                break;
            case "C":
                me = sections[1];
                them = sections[2];

                int pick = 0;
                switch(getField(them, TYPE, getActive(them))){
                    case 0:
                    case 1:
                    case 3:
                        pick = 0;
                        break;
                    case 2:
                        pick = 2;
                        break;
                    case 4:
                        pick = 1;
                        break;
                }

                if(!isAlive(me, pick)){
                    for(int i=0;i<3;i++){
                        if(isAlive(me,i))
                            pick = i;
                    }
                }

                out = pick + "";
                break;
            case "A":
                me = sections[1];
                them = sections[2];
                int active = getActive(me);
                int oType = getField(them, TYPE, getActive(them));
                switch(active){
                    case 0:         // Greenosaur
                        switch(oType){
                            case 0:
                            case 4:
                                out = "1";
                                break;
                            case 1:
                                out = "2";
                                break;
                            case 3:
                                out = "0";
                                break;
                            case 2:
                                if(isAlive(me, 2)){
                                    out = "12";
                                } else if(isAlive(me, 1)){
                                    out = "11";
                                } else {
                                    out = "1";
                                }
                                break;
                        }
                        break;
                    case 1:         // Searizard
                        if(oType == 3){
                            if(isAlive(me, 0)){
                                out = "10";
                                break;
                            } else if(isAlive(me, 2)){
                                out = "12";
                                break;
                            }
                            if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                out = "1";
                            } else if(getField(me, MOVE2, active) > 0){
                                out = "2";
                            } else {
                                out = "3";
                            }                           
                        } else {
                            if(getField(them, ATTACK, getActive(them)) < 80){
                                if(getEffectCount(them, DEFENSE_DOWN, getActive(them), false) < 1 && getField(me, MOVE2, active) > 0){
                                    out = "2";
                                    break;
                                } else if(getEffectCount(them, BURN, getActive(them), false) < 1 && getField(me, MOVE1, active) > 0){
                                    out = "1";
                                    break;
                                }
                            }
                            out = "0";
                        }
                        break;
                    case 2:         // Blastshield
                        if(oType == 4){
                            if(isAlive(me, 1)){
                                out = "11";
                                break;
                            } else if(isAlive(me, 0)){
                                out = "10";
                                break;
                            }
                        }
                        if(getField(me, HP, active) < 50 && getField(me, MOVE2, active) > 0){
                            out = "2";
                        } else if(getEffectCount(me, DEFENSE_UP, active, true) < 3 && getField(me, MOVE1, active) > 0){
                            out = "1";
                        } else {
                            out = "0";
                        }
                        break;
                }
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }

    static boolean isAlive(String teamState, int who){
        return getField(teamState, HP, who) > 0;
    }

    static int getActive(String teamState){
        return Integer.parseInt(teamState.split("\\|")[0].split(":")[1]);
    }

    static int getField(String teamState, int field, int who){
        String[] fields = teamState.split("\\|")[who+1].split(":");
        return Integer.parseInt(fields[field]);
    }

    static int getEffectCount(String teamState, int effect, int who, boolean mine){
            String[] fields = teamState.split("\\|")[who+1].split(":");
            int count = 0;
            for(int i=mine?14:8;i<fields.length;i++){
                if(Integer.parseInt(fields[i]) == effect)
                    count++;
            }
            return count;
    }

    final static int ID =       1; 
    final static int ATTACK =   2; 
    final static int DEFENSE =  3; 
    final static int SPEED =    4; 
    final static int HP =       5; 
    final static int TYPE =     6; 
    final static int PTURNS =   7; 
    final static int MOVE0 =    8; 
    final static int MOVE1 =    9; 
    final static int MOVE2 =    10; 
    final static int HA =       11; 
    final static int HD =       12; 
    final static int HS =       13; 

    final static int POISON =           1;
    final static int CONFUSION =        2;
    final static int BURN =             3;
    final static int SLEEP =            4;
    final static int ATTACK_UP =        6;
    final static int ATTACK_DOWN =      7;
    final static int DEFENSE_UP =       8;
    final static int DEFENSE_DOWN =     9;
    final static int SPEED_DOWN =       10;
}

4

오류 310 : 너무 많은 리디렉션-C ++

독의 황폐화를 막기 위해 고도로 훈련되고 조직 된 팀

3 주 동안 나는 코 데몬을 거의 훈련하지 않았다. 여러 팀을 구성했습니다. 마지막으로이 도전에 맞설 준비가되었습니다. 나는 모든 독살 자에게 답하기 위해 각각 특정한 역할을 가진 매우 다른 코 데몬으로 팀을 구성했습니다.


해독제(영상)

Type : Normal - atk:50 def:100 spd:80 - Poison/Burn/Heal

해독제는 독을 좋아합니다. 독을 공격하기 위해 서두르는 것을 막을 수 없을 정도로.


(영상)

Type : Fire - atk:100 def:80 spd:50 - Poison/Vine/Heal

Zen은 모든 효과를 수용 할 수있는 매우 놀라운 코 데몬입니다. 그는 그의 적들이 그의 침묵에 맞서 싸우고 소진하는 것을 선호합니다.


트라이 포스(영상)

Type : Psychic - atk:88 def:60 spd:82 - Fireball/Watergun/Vine

Triforce는 항상 싸울 준비가 된 고전적인 코 데몬입니다. 이것은 그의 심령을 사용하여 세 가지 요소를 제어하고 가능한 한 많은 피해를 입 힙니다.


여기에서 팀을 다운로드 할 수 있습니다.

리눅스 :

http://dl.free.fr/iHYlmTOQ2

로 시작 ./Error310TMR

윈도우 :

http://dl.free.fr/vCyjtqo2s

로 시작 ./Error310TMR.exe

코드는 완전한 C ++ 프로젝트입니다. 게시 방법을 모르겠습니다.

$ wc -l src/*
    165 src/BruteForce.cpp
     26 src/BruteForce.h
    349 src/Codemon.cpp
     77 src/Codemon.h
     21 src/Logger.cpp
     35 src/Logger.h
    105 src/NoTimeToExplain.cpp
     27 src/NoTimeToExplain.h
    240 src/Recoverator.cpp
     31 src/Recoverator.h
     26 src/StrManip.cpp
     16 src/StrManip.h
    303 src/Team.cpp
     68 src/Team.h
     88 src/TooManyRedirects.cpp
     24 src/TooManyRedirects.h
     87 src/Unrecoverable.cpp
     27 src/Unrecoverable.h
     59 src/enums.cpp
    119 src/enums.h
     68 src/main.cpp
   1961 total

그러나 매우 효과적입니다.

------- Final Results -------

176     Error310TMR
131     H3C
130     LittleKid
121     Nodemon
58      InsideYourHead
47      HardenedTrio
37      BitterRivals

2

동화

상당히 일반적인 중간 팀. 자신의 일을하려고하는 세 가지 원형을 기반으로하고, 전혀 할 수없는 경우 전환합니다.

이 팀은 독이 새로운 메타 인 것처럼 보이기 전에 만들어졌습니다. 처음에 팀을 만든 이후로 팀을 변경하지 않았으며 대부분의 시간은 파싱을 내리는 데 소비되었습니다. 토너먼트를 아직 테스트 할 수 없었지만 꽤 바빴습니다. 이것이 테스트 데이터와 같이 실제로 작동하지 않으면 작업 후에 더 빛을 발할 것입니다.

#!/bin/perl
use 5.20.0;
use strict;

use constant MINE => 0;
use constant THEIRS => 1;

$_ = $ARGV[0];

if(/^T/){
    say 'FairyTale|Fairy:1:89:90:51:3:4:13|Dragon:2:100:50:80:6:1:8|Assassin:0:70:60:100:0:1:10';

} elsif(/^C#(.*)/){
    my $state = readBattleState($1);
    if($state->[MINE]->{$state->[MINE]->{slot}}{hp}){
        say $state->[MINE]->{slot};
    } elsif($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp}){
        say (($state->[MINE]->{slot}+1)%3);
    } else {
        say (($state->[MINE]->{slot}+2)%3);
    }

} elsif(/^A#(.*)/){
    my $state = readBattleState($1);
    my @actives = (
        $state->[MINE]->{$state->[MINE]->{slot}},
        $state->[THEIRS]->{$state->[THEIRS]->{slot}}
    );
    if($state->[MINE]->{slot} == 0){
        if(!exists($actives[THEIRS]{effects}{4}) && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif(!exists($actives[THEIRS]{effects}{1}) && $actives[MINE]{pp}->[2]) {
            say 2;
        } elsif(!$actives[THEIRS]{type}) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 1){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } else {
            say 0;
        }
    } elsif($state->[MINE]->{slot} == 2){
        if(!exists($actives[MINE]{effects}{6}) && $actives[MINE]{pp}->[2]){
            say 2;
        } elsif ($actives[MINE]{hp} > 10 && $actives[MINE]{hp} < 50 && $actives[MINE]{pp}->[1]){
            say 1;
        } elsif($actives[THEIRS]{type} == 1) {
            if($state->[MINE]->{($state->[MINE]->{slot}+1)%3}{hp} > 0){
                say (($state->[MINE]->{slot}+1)%3);
            } elsif($state->[MINE]->{($state->[MINE]->{slot}+2)%3}{hp} > 0) {
                say (($state->[MINE]->{slot}+2)%3);
            } else {
                say 0;
            }
        } else {
            say 0;
        }
    }

} elsif(/^B#(.*)/){
    my $state = readTeam($1, 1);
    say '1:0:2';
}

sub readBattleState {
    local $_ = $_[0];
    if(/^(.*?)#(.*?)$/){
        my @teams;
        $teams[0] = readTeam($1, 1);
        $teams[1] = readTeam($2, 0);
        return \@teams;
    }
}

sub readTeam {
    my $isMine = $_[1];
    local $_ = $_[0];
    if(/.*?:(?<slot>.*?)\|(.*?)\|(.*?)\|(.*?)$/){
        my %team;
        $team{slot} = $1;
        $team{0} = $isMine ? readYourMember($2) : readTheirMember($2);
        $team{1} = $isMine ? readYourMember($3) : readTheirMember($3);
        $team{2} = $isMine ? readYourMember($4) : readTheirMember($4);
        return \%team;
    }
    return 0;
}

sub readYourMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?):(?<move0>.*?):(?<move1>.*?):(?<move2>.*?):(?<batk>.*?):(?<bdef>.*?):(?<bspd>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk}+$+{batk},
            def    => $+{def}+$+{bdef},
            spd    => $+{spd}+$+{bspd},
            type   => $+{type},
            pp     => [$+{move0}, $+{move1}, $+{move2}],
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
}

sub readTheirMember {
    local $_ = $_[0];
    if(/(?<name>.*?):(?<id>.*?):(?<atk>.*?):(?<def>.*?):(?<spd>.*?):(?<hp>.*?):(?<type>.*?):(?<poison>.*?)(?<effects>(?::.*)|$)/){
        my %effects = map { $_ => 1 } readEffects($+{effects});
        my %member = (
            name   => $+{name},
            id     => $+{id},
            hp     => $+{hp},
            atk    => $+{atk},
            def    => $+{def},
            spd    => $+{spd},
            type   => $+{type},
            poistrn=> $+{poison},
            effects=> \%effects
        );
        return \%member;
    }
    return 0;
}

sub readEffects {
    local $_ = $_[0];
    my @retval = /:([^:]*)/g;
    if(!@retval){
        @retval = (0);
    }
    return @retval;
}

로 실행

perl fairytale.pl

이 봇은 첫 번째 사망 후 죽은 회원을 '선택'하려고 시도하여 쫓겨납니다. 내가 볼 수있는 첫 전투는 결코 끝나지 않습니다.
Geobits

정말? 나는 이전에 버그가 해결되었다고 생각했다.
아마도이

codemon이 녹아웃되면 힐 포인트가 0 이하로 감소한다는 것을 잊지 마십시오 . 따라서 if($state->[MINE]->{$state->[MINE]->{slot}}{hp})문이 없으면 문이 제대로 작동하지 않습니다 >0.
GholGoth21

아, 그래요.
mezzoEmrys

0

더미 팀-자바

(경쟁이 아닌 CW)

이것은 연습 할 더미 팀입니다. 그것은 모든 일반 유형이며, 매 턴마다 자신의 움직임 (펀치, 치유, 느리게) 사이에서 무작위로 선택합니다. 그것으로 재미있게 보내십시오.

public class DummyTeam {

    public static void main(String[] args) {
        if(args.length < 1){
            System.out.println("You need to run this from the tournament. Try to keep up.");
            System.exit(0);
        }

        String[] sections = args[0].split("#");
        String out = "";
        switch(sections[0]){
            // team data
            //      sends back all Normal types with minimum stats and Normal moves (randomized name suffixes to distinguish in tests)
            case "T":
                out = "DummyTeam";
                for(int i=0;i<3;i++)
                    out += "|Dummy"+((char)(Math.random()*26)+65) + i + ":0:50:50:50:0:1:2";
                break;
            // bonus points
            //      shoves them all in defense every time
            case "B":
                out = "1:1:1";
                break;
            // choose active
            //      picks last active if alive, otherwise loops to find first living member
            case "C":
                String[] team = sections[1].split("\\|");
                int current = Integer.parseInt(team[0].split(":")[1]);
                if(Integer.parseInt(team[current+1].split(":")[5]) > 0){
                    out = current + "";
                } else {
                    for(int i=1;i<team.length;i++){
                        if(Integer.parseInt(team[i].split(":")[5]) > 0){
                            out = (i - 1) + "";
                        }
                    }
                }               
                break;
            // choose action
            //      chooses a random move. does not check if it ran out of uses, so wastes turns quite often
            case "A":
                out = ((int)(Math.random()*3)) + "";
                break;
            default:
                out = "Invalid query from controller.";             
        }
        System.out.println(out);
    }


}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.