#naive - literal approach to the problem via a form of simulation (as attempted in https://www.youtube.com/watch?v=7fylNa2wZaU) #the proper solution is of course just a little bit of maths - but the list-manipulation is an interesting exercise. proc collapse lst { #puts stdout "lst:'$lst' len:[llength $lst]" foreach i $lst { #puts stderr "'$i len:[llength $i] len-el0:[llength [lindex $i 0]]'" if {[llength $i] == 2 && [llength [lindex $i 0]] ==2} { lappend out [list [list [lindex $i 0 0] [expr {[lindex $i 0 1] + [lindex $i 1 1]}] ] ] } else { lappend out $i } } return $out } #.=* list |h/0,t/tail> .=t>1*,h>end,h>end list |> punk::group_list_by {[lindex $item 0]} |> inspect |> .= collapse } .=t>1*,h>end,h>end list {| data2, nplus@end/1 >} {expr {$nsofar + $nplus}} {| nsofar >} {set data2} {| >} punk::group_list_by {[lindex $item 0]} {| >} .= collapse {| >} .=>2 lmap v {lindex $v 0} {| >} .=nsofar>1,n>2,data>end* list } .=>. {set in $data; while {$i < $n } { #puts stdout "$i < $n" #puts stdout "drinkx $in" set in [drinkx {*}$in] lassign $in i n }; set in} {| >} inspect -channel null {| result/end >} {set result} peopleInLine) { r -= peopleInLine; copiesOfEachPerson *= 2; peopleInLine *= 2; } return names[Math.floor((r - 1) / copiesOfEachPerson) % peopleInLine]; } } proc who_is_next {names n} { set peopleInLine [llength $names] set copiesOfEachPerson 1 while {$n > $peopleInLine} { set n [expr {$n - $peopleInLine}] set copiesOfEachPerson [expr {$copiesOfEachPerson * 2}] set peopleInLine [expr {$peopleInLine * 2}] } set idx [expr {int(floor(($n -1)/$copiesOfEachPerson)) % $peopleInLine}] #puts "idx:$idx names: $names" set result [lindex $names $idx] }