To są moje szczęśliwe kości [zamknięte]

10

Zaimplementuj program lub funkcję, która symuluje wspólne kości do gier RPG. Powinien obsługiwać przynajmniej d6 i d20, dwie najczęściej używane kości.

Powinno jednak działać tak, jak oczekują od stereotypowych graczy, a nie jak w prawdziwych kościach.

Żart między graczami polega na tym, że można mieć wyjątkowo szczęśliwą kostkę za bardzo ważny rzut, uprzednio rzucając dużą ilością kości, wybierając te, które dały wynik „1”, a następnie rzucając je ponownie, aż otrzymasz kilka, które rzuciły „1” wiele razy. Następnie ostrożnie je zachowaj, ponieważ rzuciły 1 wielokrotnie w sekwencji, więc prawdopodobieństwo rzutu 1 następnym razem powinno być bardzo niskie.

Oczywiście nie tak działają kości w prawdziwym życiu , ponieważ rzuty są statystycznie niezależne.

Twoje symulowane kości muszą brać pod uwagę wcześniejsze rzuty i działać podobnie do tego, jak hazardzista z błędu gracza oczekuje, że zadziała. Na przykład, jeśli wyrzucono wiele niskich liczb, należy zwiększyć prawdopodobieństwo wyrzucenia większej liczby.

Ponieważ jest to oszustwo, musisz to dobrze ukryć . Oznacza to, że przypadkowe spojrzenie na program nie powinno ujawniać, że oszukiwałeś. Oznacza to, że jawne zapisywanie poprzednich wyników i czytanie ich przy każdym rzucie byłoby zbyt podejrzane. Musisz ukryć tę „właściwość” swoich kości i punkty bonusowe, jeśli sprawisz, że będzie to możliwe, bez wątpienia, i ukryj to jako uczciwy błąd. (na przykład tworzysz własne RNG z „niezamierzoną” wadą)

Głosujący, proszę wziąć pod uwagę, jak dobrze ukryta jest ta „wada”.

Programy powinny być jasne i nie zaciemniać. Zbyt łatwo ukryć zły kod w zaciemnionym programie.

vsz
źródło
3
Jak dobrze rozmawiamy? IMO, cokolwiek poza językowym odpowiednikiem getRandomBetween(1,d)spowodowałoby, że zajrzałbym głębiej.
Geobits
@Geobits: tutaj możesz znaleźć bardzo fajny przykład rozwiązywania podstępnych problemów: codegolf.stackexchange.com/questions/19569/... Mam na myśli, że możesz zrobić wszystko, jeśli uzasadnisz to wystarczająco dobrze, oczywiście uzasadnienie może być wielkie kłamstwo.
vsz
Cholera jasna, java nie ma dość dziwactw do podstępnych rzeczy ...
masterX244
4
Głosuję za zamknięciem tego pytania jako nie na temat, ponieważ podstępne wyzwania są teraz nie na temat, i jakoś to ześlizgnęło się pod radarem.
Mego

Odpowiedzi:

3

Jawa

public class GamerDie {
    private final java.util.Random rnd;
    private final int sides;

    public GamerDie(int sides) {
        this.sides = sides;
        this.rnd = new java.util.Random();
    }

    public int throw() {
        return rnd.nextInt(sides) + 1;
    }
}

Jest tak prosty, że oczywiście niczego nie ukrywa: ale java.util.Randomjest prostym liniowym generatorem kongruencjalnym i wykorzystuje technikę odrzutu, aby zapewnić jednorodność, więc gwarantuje, że w każdej serii największej wielokrotności sizemniejszej niż 2 ^ 48 próbek rozdzieli liczby równomiernie, spełniając wymagania.

Peter Taylor
źródło
Nie mogę się za wyjaśnić, jak działa java.util.random
masterX244
Odrzucanie, które java.util.Randomwykonuje, ma bardzo niewiele wspólnego z zachowaniem tej odpowiedzi. Naprawdę to, na czym polega ta odpowiedź, to fakt, że jak każdy RNG java.util.Randomma kropkę, a jeśli wygenerujesz liczbę liczb w porządku tego okresu, jej właściwości statystyczne się rozpadną. To nie jest bardzo interesujące; to samo stanie się z nawet bezpiecznym kryptograficznie RNG, takim jak Blum Blum Shub, jeśli uruchomisz go wystarczająco długo.
user2357112 obsługuje Monikę
@ user2357112, odrzucenie jest istotne, ponieważ pytanie wymaga jednolitości, a nie niewielkiego uprzedzenia do mniejszych liczb. Moim zdaniem odpowiedź ta uosabia podstępność: celowe użycie standardowej biblioteki w sposób, który na pierwszy rzut oka wydaje się transparentnie poprawny, ale w rzeczywistości wykracza poza jego parametry projektowe.
Peter Taylor
Jednak prawie każdy RNG robi coś odrzucającego. To nic specjalnego. Mógłbyś użyć tej odpowiedzi dosłownie z dowolnym generatorem liczb pseudolosowych, ponieważ jeśli RNG 1) ma kropkę, a 2) może wygenerować więcej niż 1 inną liczbę, to w ramach jednego okresu, tym bardziej liczba się wyświetla w stosunku do innych liczb, tym mniej wyświetli się do następnego okresu za pomocą prostego argumentu liczenia.
user2357112 obsługuje Monikę
Analiza w tej odpowiedzi wymaga rzędu 2 ^ 48 rolek, aby pojawił się efekt. Być może, jeśli zastosowałeś bardziej wyrafinowaną analizę, która pokazuje, że użycie LCG powoduje pojawienie się mierzalnych anomalii statystycznych w obrębie szeregu rzutów, które prawdopodobnie pojawiłyby się w grze stołowej, może to być dobra odpowiedź. Kiedy mówisz o trylionach bułek, nie jest to zbyt mało zrozumiałe.
user2357112 obsługuje Monikę
0

Rubin

Obecnie obsługuje tylko d6, doda obsługę d20 później ...

I oto - te kości są paskudne!

# first idea was to create 6 super cool dices just by copy&paste
# -> each dice holds its number at the beginning of the array
# -> we don't need all of them now, so we comment them out
dice0 = %w[[[[[[[[[ 0 . : :. :: ::. ::: ]]]]]]]]
#dice1 = %w[[[[[[[ 1 : . :. ::. :: ::: ]]]]]]]
#dice2 = %w[[[[[[ 2 . : :. :: ::. ::: ]]]]]]
#dice3 = %w[[[[[[ 3 : . :. ::. :: ::: ]]]]]]]
#dice4 = %w[[[[[[[ 4 . : :. :: ::: ::. ]]]]]]]
#dice5 = %w[[[[[[[[ 5 . : :. :: ::. ::: ]]]]]]]]]

# and hey, those dices are almost ascii art ;)

# well, let's just create a standard dice
# -> get rid of the number at the beginning
# -> then sort (maybe we need that later due to the
#    currently unused dices being unsorted)
dice = dice0.select!{|e| /[:.]+/ === e}.sort

def roll(d)
  # rolling is easy
  # -> use size instead of hardcoded number,
  #   maybe we'll have other dices later
  d.slice!(rand(d.size - 1))
end

# and here you have 8 very underhanded dices!
dices = [dice]*8

# roll like a champion
roll(dices[0])
...
David Herrmann
źródło
Dodałbym „przerwanie” wymaga ruby ​​2 ”, jeśli gdzieś tam RUBY_VERSION <„ 2 ”, tak jakbyś uruchomił go na wcześniejszych wersjach, psuje to sztuczkę
bazzargh
0

Haskell

Użyj jednej losowej rzeczy, aby zrobić inną losową rzecz: w tym przypadku potasuj karty, aby wygenerować rzuty kostkami.

import System.Environment
import System.Random
import Data.Array.IO
import Control.Monad
-- make random dice from random cards
suit c=map (\(a,b)->[a,b])$zip "A23456789TJQK" (repeat c)
deck=concatMap(\s->suit s) "♠♥♦♣"
-- just like casinos, use more decks for extra randomness
decks=concat$take 8$repeat deck
-- shuffle the cards
shuffle :: [a] -> IO [a]
shuffle xs = do
        ar <- newArray n xs
        forM [1..n] $ \i -> do
            j <- randomRIO (i,n)
            vi <- readArray ar i
            vj <- readArray ar j
            writeArray ar j vi
            return vj
  where
    n = length xs
    newArray :: Int -> [a] -> IO (IOArray Int a)
    newArray n xs =  newListArray (1,n) xs
-- convert a card to a die, by counting along the original deck
-- then taking mod (faces). If we don't have enough cards to make
-- a full set of faces, assign the 'extra' cards a value of 0
card2die faces card=
  let index=(head[i|(i,c)<-zip[0..]deck,c==card]) in
  if (index > (length deck-(length deck`mod`faces)))
  then 0
  else (index`mod`faces)+1
main=
  do
    args <- getArgs
    let faces = read (args!!0)
    -- throw away cards we can't map to die faces
    cards<-shuffle$filter (\card->card2die faces card/=0) decks
    mapM_ (\card->putStrLn (card++" -> "++(show (card2die faces card)))) cards

Przyjmuje jeden argument, liczbę twarzy na kości. Dane wyjściowe są takie:

./cards 20|head
2♦ -> 8
7♥ -> 20
J♦ -> 17
6♥ -> 19
9♥ -> 2
8♥ -> 1
5♥ -> 18
4♠ -> 4
Q♥ -> 5
2♣ -> 1

... i tak dalej dla wszystkich kart (odrzuty nie są drukowane). Zbyt oczywisty?

bazzargh
źródło