📜 ⬆️ ⬇️

Jianshitsi and tcl

There is such a rare little known programming language tcl. In Wikipedia, it is painted well, but when writing a program, there will be questions.
Jianshitszy is such a Chinese (as the name suggests) game, translated as “choosing stones”, interesting by itself: there are two piles of stones with any number of stones, two are playing. Each player can take any number of stones from any pile, as well as an equal number of both at once. The winner is the one who takes the last stone. More detailed description here . The game of maintaining balance: on the one hand, it is necessary that the numbers in the heaps differ, on the other, so that the difference is not too large. To begin with, the game has a winning strategy, the origin of which we will not consider. Take only a brief description. There are combinations of heap sizes in which the player who will make the next move loses.




Square brackets denote taking the whole part. No, the first formula is not Fibonacci numbers, although the coefficient is the same, but here is an arithmetic progression, not a geometric one. Immediately, we note that the difference between the numbers of the pair is n.
')
Earlier on Habré were Reversi on TCL in 64 lines and Fifteen on TCL in 10 lines , in which there was a compact and beautiful code, you will not see this here. He is also perhaps far from the rules of good form. In general, if something seems to you to govnokodom, most likely the way it is. On the other hand, it is even good, because it will be something to improve in the future. Partly due to the fact that the language for me is new, partly to make it easier to make explanations. There are also no optional checks.
Next will go the pieces of the program. It is far from optimal, but shows the features of the language and works.

The beginning of the program is:
#!/usr/bin/tclsh #---  (+ ab)    #---  ,   , (a + b)     namespace path {::tcl::mathop ::tcl::mathfunc} #---   proc lsum L {expr [join $L +]+0} proc random range {expr int(rand()*$range)} 


The code for losing pairs:
 set n_max 20 ;#  for {set i 1} {[<= $i $n_max]} {incr i} { set q [/ [+ [sqrt 5] 1 ] 2] ;# " " set a [int [* $q $i]] ;#i-  a set b [+ $a $i] ;#ie  b lappend lPair1 "$a $b" ;#   lPair1  a  b } 

You can view the list like this:
  puts lPair1; #    ;  ,  ,       

Here is what we get at the output:
{0 0} {1 2} {3 5} {4 7} {6 10} {8 13} {9 15} {11 18} {12 20} {14 23} {16 26} {17 28} {19 31} {21 34} {22 36} {24 39} {25 41} {27 44} {29 47} {30 49} {32 52}

So, we have a list of pairs with which to respond to the course of a person, it is necessary to learn how to choose a particular pair. There are 3 options for moving to a new state:

Since we only have to take the stones, the amount of stones decreases with each turn.
Let us proceed to the consideration of the computer running command:

 #--- : #----st -  , #----lAns -             #----lPair -      , #--------------         proc turn {st lAns lPair} { set st_cur_sum [lsum $st] ;#   #---   ,    0    0, #---  ,      if {[== 0 $st_cur_sum]} {return {you win}} set a [lindex $st 0] ;#      set b [lindex $st 1] ;#      #---lindex -       , #---           set c [abs [- $a $b]] #--- ,     #---    ,     set a1 [min $a [lindex $lAns $b]] set b1 [min $b [lindex $lAns $a]] set cPair1 [lindex $lPair $c] #---      set a2 [random $a] set b2 [random $b] set c2 [random [+ 1 [min $a $b]]] set cPair2 [list [- $a $c2] [- $b $c2]] set st_next1 [list "$a $b1" [+ $a $b1]] set st_next2 [list "$a1 $b" [+ $a1 $b]] set st_next3 [list "$cPair1" [lsum $cPair1]] #---    set lst_next [list $st_next1 $st_next2 $st_next3] #---     set st_next [lindex [lsort -integer -index 1 $lst_next] 0] set st_next_sum [lindex $st_next 1] if {[== 0 $st_next_sum]} {return {i won}} ;#   -  ,   #--- ,     #---  ,    - , #--- :   ,      ,   #---   ,     if {[> $st_cur_sum $st_next_sum]} { return [lindex $st_next 0] } else { #---     -    switch [random 3] { 0 {return "$a $b2"} 1 {return "$a2 $b"} 2 {return "$cPair2"} } } } 

A little explanation about what lAns and lPair are. The winning response must match one of the three options above. And the first two differ only in what heap to take. Consider the first option, take from the first pile, which means that the second pile does not change, and by the number of stones in it you can determine the desired size of the first, i.e. not how much we take, but how many we will leave. The content of lAns is:
0 2 1 5 7 3 10 4 13 15 6 18 20 8 23 9 26 28 11 31 12 34 36 14 39 41…
The index in the list is the number of stones in the heap, which does not change, the value for this index is the new number of stones in the heap from which we will take the stones.
The content of lPair does not differ from the content of lPair1, above. The value of the index is in this case a new pair of quantities of stones with a difference equal to the index.
Here is how we organize the dialogue with the user:
 puts {Enter heap sizes:} #--- ,     if {[< 0 [gets stdin state]]} { #---    set n_max [lindex [lsort -integer $state] end] #---    genAnsList $n_max lPair lAns #---   set state [turn $state $lAns $lPair] #   puts $state #---      while {[< 0 [gets stdin state]]} { set state [turn $state $lAns $lPair] puts $state } } 


The entire code can be seen on pastebin .
The syntax of the language is on the link .
Working with lists is important, the corresponding commands are in the documentation .
PS In the next part, if it is, constructive comments will be taken into account in the comments.

Source: https://habr.com/ru/post/141029/


All Articles