바위, 종이, 가위, 도마뱀, Spock 토너먼트


13

5 월 4 일 이후에 스타 트렉 참조와 관련된 도전을하는 것은 눈살을 찌푸리게 할 수 있습니다.

귀하, Luke, Anakin, Palpatine, Yoda 및 Han Solo는 Rock, Paper, Scissor, Lizard, Spock의 미친 토너먼트에 참여합니다.

여기서 중요한 것은 고정 된 이동 순서 만 사용할 수 있다는 것입니다. 주문이 "R"이면 모든 사람을 잃거나 이길 때까지 Rock을 사용해야합니다. 주문이 RRV 인 경우 2 개의 Rocks와 Spock을 사용해야하며,이기거나 잃을 때까지 계속 반복해야합니다.

Luke, Anakin, Palpatine, Yoda 및 Han Solo는 각각의 주문을 제출했으며 전문가 해커는 각 주문에 대해 손을 잡았습니다!

이 지식을 바탕으로 토너먼트 주문을 설계해야합니다. 모두가 이기고 싶어하기 때문에 모든 사람을 때리고 토너먼트에서이기도록 순서를 정하고 싶습니다. 그러나 모든 상황에서 가능한 것은 아닙니다.

당첨 주문이있을 경우이를 인쇄하십시오. 당신이 이길 수있는 방법이 없다면 -1 (또는 0 또는 False 또는 "불가능")을 인쇄하십시오

입력 : 5 개 주문 목록

출력 : 단일 주문 또는 -1

샘플 입력 1

R
P
S
L
V

샘플 출력 1

-1

설명 1

당신이 첫 번째 움직임에서 무엇을 하든지, 적어도 당신을 때리는 사람이있을 것이므로, 당신은 이길 수 없습니다.

샘플 입력 2

RPS
RPP
R
SRR
L

샘플 출력 2

RPSP

설명 2

첫 번째 움직임에서 Rock을 플레이하면 "L"과 "SRR"을 꺾고 나머지를 묶습니다. 도마뱀과 가위가 락을 잃기 때문입니다. 다음에 Paper를 플레이하면 "R"을 이기고 나머지 2와 묶습니다. 이것은 Rock이 Paper를 잃기 때문입니다. 다음에 가위를 사용하면 가위가 종이를 이길 때 "RPP"에 맞서 승리합니다.

마지막으로, 종이가 바위를 이길 때 종이로 "RPS"를 이길 것입니다.

다음은 표기법 목록입니다 (5 개의 리터럴을 사용할 수 있지만 답변에 명시하십시오).

R : Rock
P : Paper
S : Scissor
L : Lizard
V : Spock

가능한 모든 결과 목록은 다음과 같습니다.

winner('S', 'P') -> 'S'
winner('S', 'R') -> 'R'
winner('S', 'V') -> 'V'
winner('S', 'L') -> 'S'
winner('S', 'S') -> Tie
winner('P', 'R') -> 'P'
winner('P', 'V') -> 'P'
winner('P', 'L') -> 'L'
winner('P', 'S') -> 'S'
winner('P', 'P') -> Tie
winner('R', 'V') -> 'V'
winner('R', 'L') -> 'R'
winner('R', 'S') -> 'R'
winner('R', 'P') -> 'P'
winner('R', 'R') -> Tie
winner('L', 'R') -> 'R'
winner('L', 'V') -> 'L'
winner('L', 'S') -> 'S'
winner('L', 'P') -> 'L'
winner('L', 'L') -> Tie
winner('V', 'R') -> 'V'
winner('V', 'L') -> 'L'
winner('V', 'S') -> 'V'
winner('V', 'P') -> 'P'
winner('V', 'V') -> Tie

이것은 이므로 가장 적은 바이트가 이깁니다.

추신 : 더 많은 테스트 사례가 필요하면 알려주십시오.


4
"스타 변경해주십시오 트렉 '스타에" 전쟁 당신의 소개에 ";)
movatica

1
이것은 매우 어려운 문제입니다. 글쎄, 또는 나는 이런 종류의 프로그래밍에 나쁘다.
CrabMan

@CrabMan 이것은 골프에 약간 어려운 문제입니다. 특히 실용적인 언어로.
Koishore Roy

1
몇 가지 작품이 있지만 이론적으로는 무한한 승리 전략이 있으므로 명심하십시오
Koishore Roy

1
관련 , 그리고 KOTH (cc : @Arnauld)
DLosc

답변:


2

젤리 , 29 바이트

_%5ḟ0ḢḂ¬
ṁ€ZLḤƊçþ`Ạ€Tị;‘%5Ɗ$€

정수 목록을 허용하는 모나드 링크 (각각 상대방의 전략 임)는 정수 목록을 생성합니다. 각 목록은 승리 전략입니다 (가능한 경우 비어있는 목록).
(단 하나의 전략 목록 만 생성하거나 0불가능한 경우 추가하십시오 .)

온라인으로 사용해보십시오! (항상 목록을 표시하는 바닥 글 형식)

Rock  Paper  Scissors  Spock  Lizard
0     1      2         3      4

또는 문자 매핑 버전을 사용해보십시오 (전략은 RPSVL표기법을 사용하여 자체 행에 표시됨).

어떻게?

숫자는 다른 모듈로 5 승보다 큰 홀수 인 임의의 숫자가 선택됩니다 (즉, 그들은 던져진 오각형의 가장자리를 따라 번호가 매겨집니다).

이 코드는 패배하지 않은 패자를 유지하는 패자를 찾기 위해 가장 긴 전략의 두 배에 이르는 모든 전략 (자체 포함)에 대해 각 전략을 실행합니다. 결과적인 전략 목록에는 당첨자가있는 경우 단일 전략이 포함됩니다. 승자가 없으면 전략이 없습니다. 또는 드로잉 플레이어가있는 경우 여러 전략. 이 후,이 전략들 각각에 승리의 움직임이 추가됩니다.

_%5ḟ0ḢḂ¬ - Link 1, does B survive?: list A, list B (A & B of equal lengths)
                              e.g. RPSR vs RPVL ->  [0,1,2,0], [0,1,3,4]
_        - subtract (vectorises)                    [0,0,-1,-4]
 %5      - modulo five (vectorises)                 [0,0,4,1]   ...if all zeros:
   ḟ0    - filter discard zeros (ties)              [4,1]                       []
     Ḣ   - head (zero if an empty list)             4                           0
      Ḃ  - modulo two                               0                           0
       ¬ - logical NOT                              1                           1

ṁ€ZLḤƊçþ`Ạ€Tị;‘%5Ɗ$€ - Main Link: list of lists of integers
ṁ€                   - mould each list like:
     Ɗ               -   last three links as a monad
  Z                  -     transpose
   L                 -     length
    Ḥ                -     double  (i.e. 2 * throws in longest strategy)
        `            - use left as both arguments of:
       þ             -   table using:
      ç              -     last Link (1) as a dyad
         Ạ€          - all for each (1 if survives against all others, else 0)
           T         - truthy indices
            ị        - index into the input strategies
                  $€ - last two links as a monad for each:
             ;       -   concatenate with:
                 Ɗ   -     last three links as a monad:
              ‘      -       increment (vectorises)
               %5    -       modulo five (vectorises)

나는 젤리에 완전히 새로운,하지만 것 같습니다 당신은 대체하여 바이트를 얻을 수 ZLḤ에 의해 .
로빈 라이더

@RobinRyder 작동하지 않습니다. 상대가 많고 던지기가 적기 때문에 예제 데이터로만 작동합니다. 이것은 작동하지 않는 예제입니다 . 우리는 가장 긴 상대 전략보다 두 배의 던지기를 분석해야합니다. (당신의 코드는 실제로 이것과 같습니다 )
Jonathan Allan

... 실제로 Ɗ코드에서 작업으로 인해 생각조차하지 못합니다. 각각 자체 길이로 성형 한 다음 그 결과의 누적 합계를 얻으므로 잘못된 값도 비교합니다. 이것을 시도 예 -이 걸린 [[1,2,3,4,5],[6,7],[8]]전체리스트 (3)의 길이에 의해 금형 각각 얻을 [[1,2,3],[6,7,6],[8,8,8]]얻기 위해 다음을 수행 축적 [[1,1+2,1+2+3],[6,6+7,6+7+8],[8,8+8,8+8+8]]= [[1,3,6],[6,13,19],[8,16,24]].
Jonathan Allan

아 그래, 내가 뭔가를 오해하고 있다는 것을 알았다!
Robin Ryder

7

자바 스크립트 (ES6)  122 115  112 바이트

다음을 사용하여 입력을 문자열의 배열로 가져옵니다.

  • 0
  • 1
  • 2
  • 3
  • 4

false

f=(a,m='',x=0,o,b=a.filter(a=>(y=a[m.length%a.length])-x?o|=y-x&1^x<y:1))=>b+b?x<4&&f(a,m,x+1)||!o&&f(b,m+x):m+x

온라인으로 사용해보십시오!

어떻게?

이것은 광범위한 검색입니다. 먼저 주어진 단계에서 모든 움직임을 시도하여 게임에서 이길 수 있는지 확인합니다. 당장 이길 수 없다면, 각각의 비 손실 이동에 다른 이동을 추가하려고합니다.

AB(BA)mod5

AB

(S)(P)(R)(L)(V)01234(S) 01234(P) 14123(R) 23412(L) 32341(V) 41234

A

((A - B) and 1) xor (B < A)

위치 andxor비트 연산자입니다.

댓글

f = (                        // f is a recursive function taking:
  a,                         //   a[] = input
  m = '',                    //   m   = string representing the list of moves
  x = 0,                     //   x   = next move to try (0 to 4)
  o,                         //   o   = flag set if we lose, initially undefined
  b =                        //   b[] = array of remaining opponents after the move x
    a.filter(s =>            //     for each entry s in a[]:
    ( y =                    //       define y as ...
      s[m.length % s.length] //         ... the next move of the current opponent
    ) - x                    //       subtract x from y
    ?                        //       if the difference is not equal to 0:
      o |=                   //         update o using the formula described above:
        y - x & 1 ^ x < y    //           set it to 1 if we lose; opponents are removed
                             //           while o = 0, and kept as soon as o = 1
    :                        //       else (this is a draw):
      1                      //         keep this opponent, but leave o unchanged
  )                          //     end of filter()
) =>                         //
  b + b ?                    // if b[] is not empty:
    x < 4 &&                 //   if x is less than 4:
      f(a, m, x + 1)         //     do a recursive call with x + 1 (going breadth-first)
    ||                       //   if this fails:
      !o &&                  //     if o is not set:
        f(b, m + x)          //       keep this move and do a recursive call with b[]
  :                          // else (success):
    m + x                    //   return m + x

테스트 사례에 대한 코드 실패 : test(['P','P','S','P','P']) "SR"또는 "SV"여야합니다.
Koishore Roy

@KoishoreRoy 이제 수정되었습니다.
Arnauld

1
이것은 실제로 훌륭한 접근법입니다. 나는 그것을 그래프로 생각조차하지 않았습니다. 나는 (스팍 또는 도마뱀 즉없이) 내 ungolfed 원래의 접근 방식에서 사전 및 역 룩업을 사용하고 있었다
Koishore 로이

3

R , 213190 바이트

주세페 덕분에 -23 바이트

function(L){m=matrix(rep(0:2,1:3),5,5)
m[1,4]=m[2,5]=1
v=combn(rep(1:5,n),n<-sum(lengths(L)))
v[,which(apply(v,2,function(z)all(sapply(L,function(x,y,r=m[cbind(x,y)])r[r>0][1]<2,z)))>0)[1]]}

온라인으로 사용해보십시오!

솔루션이 존재하면 솔루션을 출력합니다. 솔루션이 없으면의 행을 출력합니다 NA. 이 출력 형식이 허용되지 않으면 몇 바이트의 비용으로 변경할 수 있습니다.

이동은 1 = R, 2 = S, 3 = P, 4 = L, 5 = V로 코딩되므로 결과 행렬은 다음과 같습니다.

     [,1] [,2] [,3] [,4] [,5]
[1,]    0    2    2    1    1
[2,]    1    0    2    2    1
[3,]    1    1    0    2    2
[4,]    2    1    1    0    2
[5,]    2    2    1    1    0

(0 = 승자 없음; 1 = 플레이어 1 승리; 2 = 플레이어 2 승리)

어퍼 그것이 존재하는 경우, 용액의 길이에 대한 결합 n=sum(lengths(L))위치를 L상대편의 동작의리스트이다. 이 코드는 가능한 모든 길이의 전략 n(matrix에 저장 됨 v)을 작성하고 모든 전략을 시도하며 모든 승리 전략을 표시합니다.

이 값은 nTIO에서 코드를 매우 느리게 만들므로 n=4테스트 사례에 충분한 TIO로 하드 코딩했습니다 .

첫 번째 테스트 사례의 경우 출력은

     1 4 2 4

솔루션 RLSL에 해당합니다.

두 번째 테스트 사례의 경우 출력은

 NA NA NA NA

해결책이 없다는 것을 의미합니다.

이전 버전에 대한 설명 (가능한 경우 업데이트) :

function(L){
  m = matrix(rep(0:2,1:3),5,5);
  m[1,4]=m[2,5]=1                      # create matrix of outcomes
  v=as.matrix(expand.grid(replicate(   # all possible strategies of length n
    n<-sum(lengths(L))                 # where n is the upper bound on solution length
    ,1:5,F)))             
  v[which(    
    apply(v,1,                         # for each strategy
          function(z)                  # check whether it wins
            all(                       # against all opponents
              sapply(L,function(x,y){  # function to simulate one game
                r=m[cbind(x,y)];       # vector of pair-wise outcomes
                r[r>0][1]<2            # keep the first non-draw outcome, and verify that it is a win
              }
              ,z)))
    >0),]                              # keep only winning strategies
}

which두 선수가 영원히 그릴 때 발생할 수 NAs을 제거하는 것이 필요하다.

이것이 가장 효율적인 전략이라고 확신하지 않습니다. 그것이더라도, 나는 코드가 m꽤 골프 를 칠 수 있다고 확신합니다 .


lengths()별칭이 항상 반환되는 이유는 4무엇입니까?
주세페

1
어쨌든, 나는 당신의 응답을 기다리는 동안, 나는 주로 다음에 중점을 두어 197 까지 골프를 쳤습니다 v.
Giuseppe

lengthsn=45=11

아, 말이되어야합니다. 187 바이트
주세페

@Giuseppe 감사합니다, 인상적인 골프! 출력을 더 읽기 쉽도록 3 바이트를 추가했습니다 (그렇지 않으면 여러 번 동일한 솔루션으로 인쇄됩니다).
Robin Ryder

0

이맥스 리스프, 730 바이트

(require 'cl-extra)
(require 'seq)
(defun N (g) (length (nth 1 g)))
(defun M (g) (mapcar (lambda (o) (nth (% (N g) (length o)) o)) (car g)))
(defun B (x y) (or (eq (% (1+ x) 5) y) (eq (% (+ y 2) 5) x)))
(defun S (g) (seq-filter (lambda (m) (not (seq-some (lambda (v) (B v m)) (M g)))) '(0 1 2 3 4)))
(defun F (g) (cond ((null (car g)) (reverse (nth 1 g))) ((null (S g)) nil) ((>= (nth 3 g) (seq-reduce (lambda (x y) (calc-eval "lcm($,$$)" 'raw x y)) (mapcar 'length (car g)) 1)) nil) (t (cl-some (lambda (m) (F   (let ((r (seq-filter 'identity (mapcar* (lambda (v o) (and (not (B m v)) o)) (M g) (car g))))) (list r (cons m (nth 1 g)) (1+ (N g)) (if (eq (car g) r) (1+ (nth 3 g)) 0))))) (S g)))))
(defun Z (s) (F (list s () 0 0)))

Emacs Lisp의 온라인 인터프리터를 찾지 못했습니다 : (Emacs가 설치되어 있으면 코드를 .el파일로 복사하고 아래의 테스트 줄을 복사 할 수 있습니다

;; 0 = rock, 1 = lizard; 2 = spock;
;; 3 = scissors; 4 = paper
(print (Z '((0) (1) (2) (3) (4))))
; output: nil
(print (Z '((0) (4) (3) (1))))
; output: nil
(print (Z '((0 4 3) (0 4 4) (0) (3 0 0) (1))))
; output: (0 4 3 0 1)
(print (Z '((4) (4) (3) (4) (4))))
; output: (3 0)
(print (Z '((4 3 2 1 0) (2 1 0 4 3))))
; output: (1)
(print (Z '((2) (2) (3) (0) (2) (3) (0) (0))))
; output: (2 1)
(print (Z '((2) (2 0) (3) (0) (2 1) (3) (0) (0))))
; output: nil

그리고 그것을 실행하십시오 $ emacs --script filename.el.

작동 원리

내 프로그램은 깊이있는 첫 번째 검색을 수행하여 때로는 지점에서 이기고 종료하는 것이 불가능하다는 것을 알아냅니다.

단축 버전의 코드에서 전체 설명을 볼 수 있습니다.

(require 'seq)
(require 'cl-extra)

;; This program does depth first search with sometimes figuring out
;; that it's impossible to win and terminating the branch it's on.
;;

;; A move is a number from 0 to 4. 
;; https://d3qdvvkm3r2z1i.cloudfront.net/media/catalog/product/cache/1/image/1800x/6b9ffbf72458f4fd2d3cb995d92e8889/r/o/rockpaperscissorslizardspock_newthumb.png
;; this is a nice visualization of what beats what.
;; Rock = 0, lizard = 1, spock = 2, scissors = 3, paper = 4.

(defun beats (x y) "Calculates whether move x beats move y"
  (or (eq (% (1+ x) 5) y)
      (eq (% (+ y 2) 5) x)))

;; A gamestate is a list with the following elements:
(defun get-orders (gamestate)
  "A list of orders of players who haven't lost yet. Each order is a list of moves.
For example, ((2) (2 0) (3) (0) (2 1) (3) (0) (0)) is a valid orders list.
This function gets orders from the gamestate."
  (car gamestate))

;; At index 1 of the gamestate lies a list of all moves we have made so far in reverse order
;; (because lists are singly linked, we can't push back quickly)
(defun get-num-moves-done (gamestate)
  "Returns the number of moves the player has done so far"
  (length (nth 1 gamestate)))

(defun get-rounds-since-last-elim (gamestate)
  "The last element of a gamestate is the number of rounds passed since an opponent
was eliminated. We use this to determine if it's possible to win from current
gamestate (more about it later)."
  (nth 2 gamestate))

;; next go some utility functions
;; you can skip their descriptions, they are not very interesting
;; I suggest you skip until the next ;; comment

(defun get-next-move (order num-rounds-done)
  "Arguments: an order (e.g. (1 0 1)); how many rounds have passed total.
Returns the move this opponent will make next"
  (nth (% num-rounds-done (length order)) order))

(defun moves-of-opponents-this-round (gamestate)
  "Returns a list of moves the opponents will make next"
  (mapcar (lambda (order) (get-next-move order (get-num-moves-done gamestate)))
          (get-orders gamestate)))

(defun is-non-losing (move opponents-moves)
  "Calculates if we lose right away by playing move against opponents-moves"
  (not (seq-some (lambda (opponent-move) (beats opponent-move move))
                 opponents-moves)))

(defun non-losing-moves (gamestate)
  "Returns a list of moves which we can play without losing right away."
  (seq-filter
   (lambda (move) (is-non-losing move (moves-of-opponents-this-round gamestate)))
   '(0 1 2 3 4)))

(defun advance-gamestate (gamestate move)
  "If this move in this gamestate is non-losing, returns the next game state"
  (let ((new-orders (seq-filter
                    'identity (mapcar* (lambda (opp-move order)
                                         (and (not (beats move opp-move)) order))
                                       (moves-of-opponents-this-round gamestate)
                                       (get-orders gamestate)))))
  (list new-orders
        (cons move (nth 1 gamestate))
        (if (eq (get-orders gamestate) new-orders) (1+ (get-rounds-since-last-elim gamestate)) 0))))

;; How do we prevent our depth first search from continuing without halting?
;; Suppose 3 players (except us) are still in the game and they have orders of lengths a, b, c
;; In this situation, if least_common_multiple(a, b, c) rounds pass without an elimination
;; we will be in the same situation (because they will be playing the same moves they played
;; lcm(a, b, c) rounds ago)
;; Therefore, if it's possible to win from this gamestate,
;; then it's possible to win from that earlier game state,
;; hence we can stop exploring this branch

(defun get-cycle-len (gamestate)
  "Returns a number of rounds which is enough for the situation to become the same
if the game goes this long without an elimination."
  (seq-reduce (lambda (x y) (calc-eval "lcm($,$$)" 'raw x y))
              (mapcar 'length (get-orders gamestate)) 1))

(defun unwinnable-cycle (gamestate)
  "Using the aforementioned information, returns t if we are in such a
suboptimal course of play."
  (>= (get-rounds-since-last-elim gamestate) (get-cycle-len gamestate)))

(defun find-good-moves (gamestate)
  "Given gamestate, if it's possible to win
returns a list of moves, containing all moves already done + additional moves which lead to win.
Otherwise returns nil"
  (cond ((null (get-orders gamestate)) ; if no opponents left, we won, return the list of moves
         (reverse (nth 1 gamestate)))
        ((null (non-losing-moves gamestate)) ; if no non-losing moves available, this gamestate
         nil) ; doesn't lead to a win, return nil
        ((unwinnable-cycle gamestate) ; either it's impossible to win, or
         nil) ; it's possible to win from an earlier position, return nil
        (t (cl-some (lambda (move) ; otherwise return the first non-losing move which leads
                      (find-good-moves (advance-gamestate gamestate move))) ; to a non-nil result
                    (non-losing-moves gamestate)))))

(defun make-initial-gamestate (orders)
  "Given an orders list, create initial gamestate"
  (list orders () 0))

1
tio.run/##S81NTC7WzcksLvgPBAA 여기에 코드를 삽입하고 실행할 수 있습니까?
Koishore Roy

@ KoishoreRoy tio.run을 시도했지만 왜 실행되지 않는지 알 수 없었습니다. "표현 후 쓰레기 추적"이라고 말하고 그 내용이 무엇인지 알지 못하며 5 분 인터넷 검색으로 문제를 해결하는 데 도움이되지 않았습니다.
CrabMan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.