Josephus problem (counting out)

29

3

The challenge

Write a function that takes two positive integers n and k as arguments and returns the number of the last person remaining out of n after counting out each k-th person.

This is a code-golf challenge, so the shortest code wins.

The problem

n people (numbered from 1 to n) are standing in a circle and each k-th is counted out until a single person is remaining (see the corresponding wikipedia article). Determine the number of this last person.

E.g. for k=3 two people will be skipped and the third will be counted out. I.e. for n=7 the numbers will be counted out in the order 3 6 2 7 5 1 (in detail 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4) and thus the answer is 4.

Examples

J(7,1) = 7      // people are counted out in order 1 2 3 4 5 6 [7]
J(7,2) = 7      // people are counted out in order 2 4 6 1 5 3 [7]
J(7,3) = 4      // see above
J(7,11) = 1
J(77,8) = 1
J(123,12) = 21

Howard

Posted 2012-05-20T07:19:19.520

Reputation: 23 109

Answers

5

GolfScript, 17 bytes

{{@+\)%}+\,*)}:f;

Takes n k on the stack, and leaves the result on the stack.

Dissection

This uses the recurrence g(n,k) = (g(n-1,k) + k) % n with g(1, k) = 0 (as described in the Wikipedia article) with the recursion replaced by a fold.

{          # Function declaration
           # Stack: n k
  {        # Stack: g(i-1,k) i-1 k
    @+\)%  # Stack: g(i,k)
  }+       # Add, giving stack: n {k block}
  \,*      # Fold {k block} over [0 1 ... n-1]
  )        # Increment to move from 0-based to 1-based indexing
}:f;

Peter Taylor

Posted 2012-05-20T07:19:19.520

Reputation: 41 901

Can you add an explanation, please? – Sherlock9 – 2015-11-26T18:49:26.667

@Sherlock9, I managed to figure out what I was doing despite almost 3.5 years having passed. Who says that GolfScript is read-only? ;) – Peter Taylor – 2015-11-26T21:45:01.427

Ahem. s/read/write/ – Peter Taylor – 2015-11-26T22:40:22.937

Sorry. I've only started learning Golfscript two or three days ago and I every time I read your code, I kept thinking I'd missed something. ... Ok, I'm still missing something, how does folding {k block} over [0..n-1] get you g(0,k) 0 k to start with? Sorry, if I'm posting these questions in the wrong place. – Sherlock9 – 2015-11-27T05:30:03.713

@Sherlock9, fold works pairwise, so the first thing it does is evaluate 0 1 block. Very conveniently, that happens to be g(1, k) (2-1) block. So it's starting at g(1,k) 1 rather than g(0,k) 0. Then after executing the block, it pushes the next item from the array (2) and executes the block again, etc. – Peter Taylor – 2015-11-27T06:47:21.553

OH! Ok that makes sense. Thanks @Peter Taylor – Sherlock9 – 2015-11-27T07:06:01.417

14

Minsky Register Machine (25 non-halt states)

Not technically a function, but it's in a computing paradigm which doesn't have functions per se...

This is a slight variation on the main test case of my first MRM interpretation challenge: Josephus problem as Minsky register machine

Input in registers n and k; output in register r; it is assumed that r=i=t=0 on entry. The first two halt instructions are error cases.

Peter Taylor

Posted 2012-05-20T07:19:19.520

Reputation: 41 901

I think you have to adjust your machine slightly. If I read it correctly the output is zero-indexed, isn't it? – Howard – 2012-05-21T13:45:45.243

I was thinking the other way: if k=1 then r=0. Hmm, I have to think about this one again... – Howard – 2012-05-21T14:40:37.557

As I read your diagram, i is simply counting from 2 to n while r is the register which accumulates the result. – Howard – 2012-05-21T15:39:56.073

@Howard, I looked up the comments I made when I first wrote this and you're right. Whoops. Now corrected (I believe - will test more thoroughly later). – Peter Taylor – 2012-05-21T16:19:03.320

7

Python, 36

I also used the formula from wikipedia:

J=lambda n,k:n<2or(J(n-1,k)+k-1)%n+1

Examples:

>>> J(7,3)
4
>>> J(77,8)
1
>>> J(123,12)
21

grc

Posted 2012-05-20T07:19:19.520

Reputation: 18 565

6

Mathematica, 38 36 bytes

Same Wikipedia formula:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]

Mr.Wizard

Posted 2012-05-20T07:19:19.520

Reputation: 2 481

1If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]& – alephalpha – 2015-05-07T05:27:54.713

5

C, 40 chars

This is pretty much just the formula that the above-linked wikipedia article gives:

j(n,k){return n>1?(j(n-1,k)+k-1)%n+1:1;}

For variety, here's an implementation that actually runs the simulation (99 chars):

j(n,k,c,i,r){char o[999];memset(o,1,n);for(c=k,i=0;r;++i)(c-=o[i%=n])||(o[i]=!r--,c=k);
return i;}

breadbox

Posted 2012-05-20T07:19:19.520

Reputation: 6 893

4Save a character: j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}. – ugoren – 2012-05-20T10:06:20.987

5

dc, 27 bytes

[d1-d1<glk+r%1+]dsg?1-skrxp

Uses the recurrence from the Wikipedia article. Explanation:

# comment shows what is on the stack and any other effect the instructions have
[   # n
d   # n, n
1-  # n-1, n
d   # n-1, n-1, n
1<g # g(n-1), n ; g is executed only if n > 1, conveniently g(1) = 1
lk+ # g(n-1)+(k-1), n; remember, k register holds k-1
r%  # g(n-1)+(k-1) mod n
1+  # (g(n-1)+(k-1) mod n)+1
]
dsg # code for g; code also stored in g
?   # read user input => k, n, code for g
1-  # k-1, n, code for g
sk  # n, code for g; k-1 stored in register k
r   # code for g, n
x   # g(n)
p   # prints g(n)

Geoff Reedy

Posted 2012-05-20T07:19:19.520

Reputation: 2 828

4

J, 45 characters

j=.[:{.@{:]([:}.]|.~<:@[|~#@])^:(<:@#)>:@i.@[

Runs the simulation.

Alternatively, using the formula (31 characters):

j=.1:`(1+[|1-~]+<:@[$:])@.(1<[)

I hope Howard doesn't mind that I've adjusted the input format slightly to suit a dyadic verb in J.

Usage:

   7 j 3
4
   123 j 12
21

Gareth

Posted 2012-05-20T07:19:19.520

Reputation: 11 678

4

GolfScript, 32 24 bytes

:k;0:^;(,{))^k+\%:^;}/^)

Usage: Expects the two parameters n and k to be in the stack and leaves the output value.

(thanks to Peter Taylor for suggesting an iterative approach and many other tips)

The old (recursive) approach of 32 chars:

{1$1>{1$(1$^1$(+2$%)}1if@@;;}:^;

This is my first GolfScript, so please let me know your criticisms.

Cristian Lupascu

Posted 2012-05-20T07:19:19.520

Reputation: 8 369

11- has special opcode (. Similarly 1+ is ). You don't have to use alphabetic characters for storage, so you could use e.g. ^ instead of J and not need a space after it. You have far more $s than are usual in a well-golfed program: consider whether you can reduce them using some combination of \@.. – Peter Taylor – 2012-05-21T07:27:18.240

@PeterTaylor Thanks a lot for these great tips! It's pretty hard to grasp all the Golfscript operators and I overlooked these two very straightforward one. Only by applying the first two suggestions I manage to shorten the code by 5 chars. I'll also try to remove the $ references. – Cristian Lupascu – 2012-05-21T08:23:06.680

1Also, recursion isn't really GolfScript's thing. Try flipping it round and doing a loop. I can get it down to 19 chars (albeit untested code) that way. Hint: unroll the function g from the Wikipedia article, and use , and /. – Peter Taylor – 2012-05-21T09:21:21.470

Actually, make that 21. I forgot to pop k at the end. – Peter Taylor – 2012-05-21T09:29:28.650

@Peter Taylor: Actually, you can build a 19 chars solution (not using each but fold). – Howard – 2012-05-21T13:25:18.920

@Howard, cunning. Nice one. – Peter Taylor – 2012-05-21T14:07:57.820

@PeterTaylor Thanks, the iterative solution is much better than the recursive one in GS. I'm still thinking of ways to get this shorter. – Cristian Lupascu – 2012-05-21T16:55:05.510

1{,{\2$+\)%}*)\;}:f; Make sure you understand why it works ;) – Peter Taylor – 2012-05-21T17:12:05.457

1One final trick: rather than using 2 characters to access k inside the loop and then 2 more to discard it at the end, we can pull it inside using + to get down to 17 characters: {{@+\)%}+\,*)}:f; I doubt that can be improved. – Peter Taylor – 2012-05-21T18:13:41.620

@PeterTaylor These things are a work of art. I really liked the second example that adds the 3 and the code block together to make a code block that uses the 3. – Cristian Lupascu – 2012-05-21T20:11:21.520

In the 19 chars I think there should be a \\ at the beginning (it seems to expect the parameters in the opposite order). – Cristian Lupascu – 2012-05-21T20:12:10.287

One more thing: isn't is OK for the purpose of this site to leave out the function wrapper? For example, I think {@+\)%}+\,*) might be acceptable (the usage being that it expects two params in the stack and leaves the result at the end) – Cristian Lupascu – 2012-05-21T20:14:21.190

Yes. As I said: untested code. I've tested the 17-char one, though, because I thought it up on the way home from work. In general, when the question asks for a function, give a function; when it asks for a program, give a program; and when it doesn't specify, pick whatever's in your favour but state what you picked. – Peter Taylor – 2012-05-21T21:21:49.390

@PeterTaylor If you want to post your solution as answer I'd accept it as the currently shortest one. – Howard – 2012-05-31T19:11:27.863

3

Groovy, 36 bytes

def j(n,k){n>1?(j(n-1,k)+k-1)%n+1:1}

Prince John Wesley

Posted 2012-05-20T07:19:19.520

Reputation: 669

3

R, 48

J=function(n,k)ifelse(n<2,1,(J(n-1,k)+k-1)%%n+1)

Running Version with examples: http://ideone.com/i7wae

Paolo

Posted 2012-05-20T07:19:19.520

Reputation: 696

2

Scala, 53 bytes

def?(n:Int,k:Int):Int=if(n<2)1 else(?(n-1,k)+k-1)%n+1

Prince John Wesley

Posted 2012-05-20T07:19:19.520

Reputation: 669

2

Haskell, 68

j n=q$cycle[0..n]
q l@(i:h:_)k|h/=i=q(drop(k-1)$filter(/=i)l)k|1>0=i

Does the actual simulation. Demonstration:

GHCi> j 7 1
7
GHCi> j 7 2
7
GHCi> j 7 3
4
GHCi> j 7 11
1
GHCi> j 77 8
1
GHCi> j 123 12
21

ceased to turn counterclockwis

Posted 2012-05-20T07:19:19.520

Reputation: 5 200

1

J, 8 bytes

1&|.&.#:

       1&|.&.#: 10
    5

       1&|.&.#: 69
    11

        1&|.&.#: 123456
    115841

        1&|.&.#: 123245678901234567890x NB. x keeps input integral
    98917405212792722853

All credit to Roger Hui, co-inventor of J and all-round uber-genius
www.jsoftware.com for free j software across many platforms

Explanation
    (J works right-to-left)
     #:       convert input to binary
     &.       a&.b <=> perform b, perform a, perform reverse of b
     1&|.     rotate bitwise one bit left

So
    1&|.&.#: 10

    a. #:            convert input (10) TO binary -> 1 0 1 0
    b. 1&|.          rotate result 1 bit left -> 0 1 0 1
    c. due to the &. perform convert FROM binary -> 5 (answer)

Richard Donovan

Posted 2012-05-20T07:19:19.520

Reputation: 87

1Isn't it supposed to take two inputs? – Erik the Outgolfer – 2017-09-28T16:45:04.133

1

Ruby, 39 bytes

def J(n,k)
n<2?1:(J(n-1,k)+k-1)%n+1
end

Running version with test cases: http://ideone.com/pXOUc

Cristian Lupascu

Posted 2012-05-20T07:19:19.520

Reputation: 8 369

1

C, 88 chars

Does the simulation, doesn't calculate the formula.
Much longer than the formula, but shorter than the other C simulation.

j(n,k){
    int i=0,c=k,r=n,*p=calloc(n,8);
    for(;p[i=i%n+1]||--c?1:--r?p[i]=c=k:0;);
    return i;
}

Notes:
1. Allocates memory and never releases.
2. Allocates n*8 instead of n*4, because I use p[n]. Could allocate (n+1)*4, but it's more characters.

ugoren

Posted 2012-05-20T07:19:19.520

Reputation: 16 527

1

Q, 34 bytes

f:{$[x=1;1;1+mod[;x]f[x-1;y]+y-1]}

Usage:

q)f .'(7 1;7 2;7 3;7 11;77 8;123 12)
7 7 4 1 1 21

tmartin

Posted 2012-05-20T07:19:19.520

Reputation: 3 917

1

Ruby, 34 bytes

J=->n,k{n<2?1:(J(n-1,k)+k-1)%n+1}

Hauleth

Posted 2012-05-20T07:19:19.520

Reputation: 1 472

1

C++, 166 bytes

Golfed:

#include<iostream>
#include <list>
int j(int n,int k){if(n>1){return(j(n-1,k)+k-1)%n+1;}else{return 1;}}
int main(){intn,k;std::cin>>n>>k;std::cout<<j(n,k);return 0;}

Ungolfed:

#include<iostream>
#include <list>
int j(int n,int k){
    if (n > 1){
        return (j(n-1,k)+k-1)%n+1;
    } else {
        return 1;
    }
}
int main()
{
    int n, k;
    std::cin>>n>>k;
    std::cout<<j(n,k);
    return 0;
}

Michelfrancis Bustillos

Posted 2012-05-20T07:19:19.520

Reputation: 695

2You could save bytes on the J function, by using the ternary operator. – Yytsi – 2016-06-26T09:52:19.570

intn in your golfed version won't compile – Felipe Nardi Batista – 2017-10-24T10:56:16.293

you can remove space in #include <list> – Felipe Nardi Batista – 2017-10-24T10:56:46.417

0

JavaScript (ECMAScript 5), 48 bytes

Using ECMAScript 5 since that was the latest version of JavaScript at the time this question was asked.

function f(a,b){return a<2?1:(f(a-1,b)+b-1)%a+1}

ES6 version (non-competing), 33 bytes

f=(a,b)=>a<2?1:(f(a-1,b)+b-1)%a+1

Explanation

Not much to say here. I'm just implementing the function the Wikipedia article gives me.

Luke

Posted 2012-05-20T07:19:19.520

Reputation: 4 675

0

05AB1E, 11 bytes

L[Dg#²<FÀ}¦

Try it online!

L           # Range 1 .. n
 [Dg#       # Until the array has a length of 1:
     ²<F }  #   k - 1 times do:
        À   #     Rotate the array
          ¦ #   remove the first element

Riley

Posted 2012-05-20T07:19:19.520

Reputation: 11 345

0

8th, 82 bytes

Code

: j >r >r a:new ( a:push ) 1 r> loop ( r@ n:+ swap n:mod ) 0 a:reduce n:1+ rdrop ;

SED (Stack Effect Diagram) is: n k -- m

Usage and explanation

The algorithm uses an array of integers like this: if people value is 5 then the array will be [1,2,3,4,5]

: j \ n k -- m
    >r                               \ save k
    >r a:new ( a:push ) 1 r> loop    \ make array[1:n]
    ( r@ n:+ swap n:mod ) 0 a:reduce \ translation of recursive formula with folding using an array with values ranging from 1 to n
    n:1+                             \ increment to move from 0-based to 1-based indexing
    rdrop                            \ clean r-stack
;

ok> 7 1 j . cr
7
ok> 7 2 j . cr
7
ok> 7 3 j . cr
4
ok> 7 11 j . cr
1
ok> 77 8 j . cr
1
ok> 123 12 j . cr
21

Chaos Manor

Posted 2012-05-20T07:19:19.520

Reputation: 521

0

J, 24 bytes

1+1{1([:|/\+)/@,.1|.!.0#

Try it online!

An iterative approach based on the dynamic programming solution.

Explanation

1+1{1([:|/\+)/@,.1|.!.0#  Input: n (LHS), k (RHS)
                       #  Make n copies of k
                 1|.!.0   Shift left by 1 and fill with zero
    1          ,.         Interleave with 1
             /@           Reduce using
           +                Addition
        |/\                 Cumulative reduce using modulo
  1{                      Select value at index 1
1+                        Add 1

miles

Posted 2012-05-20T07:19:19.520

Reputation: 15 654

0

J, 19 bytes

1+(}:@|.^:({:@])i.)

Try it online!

How it works

1+(}:@|.^:({:@])i.)   Left: k, Right: n
                i.    Generate [0..n-1]
        ^:            Repeat:
   }:@|.                Rotate left k items, and remove the last item
          ({:@])        n-1 (tail of [0..n-1]) times
1+                    Add one to make the result one-based

Bubbler

Posted 2012-05-20T07:19:19.520

Reputation: 16 616

0

Dart, 33 bytes

f(n,k)=>n<2?1:(f(n-1,k)+k-1)%n+1;

Try it online!

Elcan

Posted 2012-05-20T07:19:19.520

Reputation: 913

0

Japt, 15 bytes

_é1-V Å}h[Uõ] Ì

Try it online!

A byte could be saved by 0-indexing k, but it isn't actually an index so I decided against that.

Explanation:

         [Uõ]      :Starting with the array [1...n]
_      }h          :Repeat n-1 times:
 é1-V              : Rotate the array right 1-k times (i.e. rotate left k-1 times)
      Å            : Remove the new first element
              Ì    :Get the last value remaining

Kamil Drakari

Posted 2012-05-20T07:19:19.520

Reputation: 3 461

0

Powershell, 56 bytes

param($n,$k)if($n-lt2){1}else{((.\f($n-1)$k)+$k-1)%$n+1}

Important! The script calls itself recursively. So save the script as f.ps1 file in the current directory. Also you can call a script block variable instead script file (see the test script below). That calls has same length.

Test script:

$f = {

param($n,$k)if($n-lt2){1}else{((&$f($n-1)$k)+$k-1)%$n+1}

}

@(
    ,(7, 1, 7)
    ,(7, 2, 7)
    ,(7, 3, 4)
    ,(7, 11, 1)
    ,(77, 8, 1)
    ,(123,12, 21)
) | % {
    $n,$k,$expected = $_
    $result = &$f $n $k
    "$($result-eq$expected): $result"
}

Output:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21

mazzy

Posted 2012-05-20T07:19:19.520

Reputation: 4 832

0

Japt -h, 10 bytes

õ
£=éVn1¹v

Try it

Shaggy

Posted 2012-05-20T07:19:19.520

Reputation: 24 623

0

Haskell, 29

Using the formula from wikipedia.

1#_=1
n#k=mod((n-1)#k+k-1)n+1

alephalpha

Posted 2012-05-20T07:19:19.520

Reputation: 23 988