BATCH - RPS - Rock, Paper, Scissors - Keep failing after a few rounds - if-statement

I have been trying to make a rock, paper, scissors game in batch. So far, the script runs and I can make it play against itself or to play against me (I need to change the B var from /A and random number to /P and have user input).
The thing is that after a few (different amount every time) rounds, the script crash and I do not have time to read the last line of text (which would help me find the error). I have tried with ECHO ON and OFF, I also tried to run 'RPS.bat >> log.txt' from a different DOS window (with the right directory chosen). That did log everything until it crashed, and did not get the last line either.
I have been looking through it several times, but I cant find the error... :(
I made the same game in PHP with currently no errors... (it is a totally different language, I know)
So here is my script:
#ECHO OFF
:TOP
SET /A AWON=0
SET /A BWON=0
SET /A NWON=0
:GAME
SET /A A=%RANDOM% %% 3 + 1
SET /P B=Number from 1 to 3
IF %A% EQU 1 (
GOTO A1
) ELSE IF %A% EQU 2 (
GOTO A2
) ELSE IF %A% EQU 3 (
GOTO A3
) ELSE (
GOTO GAME
)
:A1
IF %B% EQU 1 (
GOTO DRAW
) ELSE IF %B% EQU 2 (
GOTO BWIN
) ELSE IF %B% EQU 3 (
GOTO AWIN
) ELSE (
GOTO GAME
)
:A2
IF %B% EQU 1 (
GOTO ARAW
) ELSE IF %B% EQU 2 (
GOTO DRAW
) ELSE IF %B% EQU 3 (
GOTO BWIN
) ELSE (
GOTO GAME
)
:A3
IF %B% EQU 1 (
GOTO BWIN
) ELSE IF %B% EQU 2 (
GOTO AWIN
) ELSE IF %B% EQU 3 (
GOTO DRAW
) ELSE (
GOTO GAME
)
:AWIN
SET /A AWON=%AWON% + 1
ECHO -------------------------------------------------------------------------------
ECHO A won this round!
ECHO ---
ECHO A won: %AWON%
ECHO B won: %BWON%
ECHO Draw: %NWON%
PAUSE
GOTO GAME
:BWIN
SET /A BWON=%BWON% + 1
ECHO -------------------------------------------------------------------------------
ECHO B won this round!
ECHO ---
ECHO A won: %AWON%
ECHO B won: %BWON%
ECHO Draw: %NWON%
PAUSE
GOTO GAME
:DRAW
SET /A NWON=%NWON% + 1
ECHO -------------------------------------------------------------------------------
ECHO This round was a draw!
ECHO ---
ECHO A won: %AWON%
ECHO B won: %BWON%
ECHO Draw: %NWON%
PAUSE
GOTO GAME
Thanks to Gray for helping me out with my stupid mistake ^^
Also thanks for the script, but if I am not missing something here, it is not quite correct.
#ECHO OFF
:GAME
SET /P A=A:
SET /P B=B:
SET /A WINNER=(%A%-%B%) %% 3
ECHO %A% - %B% = %WINNER%
IF %WINNER% EQU 1 (
echo A WON!
) ELSE (
IF %WINNER% EQU 0 (
echo DRAW!
) ELSE (
echo B WON!
))
PAUSE
GOTO GAME
Run that script (a 'shortened' version of Gray's script). Use the variables like as in my 'table', you can see that by choosing 1 (rock), A is not able to win (A=1 vs B=3 should be: A WON). Do you have any idea on how to fix this? I guess a 'hard-coded?' solution when A=1 and B=3 would be best? (I mean that when those are the values, the 'normal' script does not apply, but a special code gives the result instead).
In my table, if the last sign is '+', then the script gives the correct answer, if the last sign is a '-', then the script gives an incorrect answer.
ITEM VALUE
ROCK 1
PAPER 2
SCISSORS 3
A - B = WINNER
1 - 1 = 0 DRAW +
1 - 2 = -1 B WON +
1 - 3 = -2 A WON -
2 - 1 = 1 A WON +
2 - 2 = 0 DRAW +
2 - 3 = -1 B WON +
3 - 1 = 2 B WON +
3 - 2 = 1 A WON +
3 - 3 = 0 DRAW +
Also, if you have any tips on how to keep the script more tidy and use less lines code to do the same job, I would gladly listen!
Thanks in advance! - Espen

Your error likely says:
The system cannot find the batch label specified - ARAW
This is because you have GOTO ARAW in your A2 label, when it looks like you meant to do GOTO AWIN
Bonus: as a more "clever" way of determining the winner (can surely be improved more)
#echo off
rem rock:1; paper:2; scissors:3
:GAME
SET /A CPU=%RANDOM% %% 3 + 1
SET /P PLAYER=Number from 1 to 3
cls
echo %CPU% vs %PLAYER%
rem set /A WINNER=(%CPU%-%PLAYER%) %% 3 //this does not work with batch - my mistake
SET /A WINNER=(%CPU% - %PLAYER% + 3) %% 3
IF %WINNER% EQU 1 (
echo CPU WON!
) ELSE (
IF %WINNER% EQU 0 (
echo DRAW!
) ELSE (
echo YOU WON!
))
GOTO GAME
And finally, here is one that prints "rock", "paper", and "scissors" to make it a little more... fun
#echo off
rem rock:1; paper:2; scissors:3
:GAME
SET /A CPU=%RANDOM% %% 3 + 1
SET /P PLAYER=Number from 1 to 3
goto CPUTYPE
:TYPE1
goto PLAYERTYPE
:TYPE2
cls
echo CPU:%CPUT% vs YOU:%PLAYERT%
rem set /A WINNER=(%CPU%-%PLAYER%) %% 3 //this does not work with batch - my mistake
SET /A WINNER=(%CPU% - %PLAYER% + 3) %% 3
IF %WINNER% EQU 1 (
echo CPU WON!
) ELSE (
IF %WINNER% EQU 0 (
echo DRAW!
) ELSE (
echo YOU WON!
))
GOTO GAME
:CPUTYPE
IF %CPU% EQU 1 (
SET CPUT="ROCK"
) ELSE (
IF %CPU% EQU 2 (
SET CPUT="PAPER"
) ELSE (
SET CPUT="SCISSORS"
))
GOTO TYPE1
:PLAYERTYPE
IF %PLAYER% EQU 1 (
SET PLAYERT="ROCK"
) ELSE (
IF %PLAYER% EQU 2 (
SET PLAYERT="PAPER"
) ELSE (
SET PLAYERT="SCISSORS"
))
GOTO TYPE2
Updated version based on asker's PvP version (fixed modul
#ECHO OFF
:GAME
SET /P A=A:
SET /P B=B:
SET /A WINNER=(%A% - %B% + 3) %% 3
ECHO W= %WINNER%
IF %WINNER% EQU 1 (
echo A WON!
) ELSE (
IF %WINNER% EQU 0 (
echo DRAW!
) ELSE (
echo B WON!
))
PAUSE
GOTO GAME
Explanation of SET /A WINNER=(%CPU% - %PLAYER% + 3) %% 3:
2 beats 1, 3 beats 2, and 1 beats 3. If you draw it out, it is kind of circular. We use the % or modulus operator to do that. The modulus operator basically gives you the remainder if you had divided by that number using integer division.
Here are 1 through 6 mod 3, with the answer in bold.
1 / 3 = 0 rem 1
2 / 3 = 0 rem 2
3 / 3 = 1 rem 0
4 / 3 = 1 rem 1
5 / 3 = 1 rem 2
6 / 3 = 2 rem 0
Notice how the result is always < 3 and > 0? We exploit this mechanic to mimic the circular behavior of rock paper scissors. You also may have noticed I didn't do the +3 in those examples. The +3 was added because the way Microsoft chose to implement modulus, it does weird things when you have a negative number (that was how we fixed the bug you caught). I had assumed it used a modulus like I was used to where the sign didn't change the outcome. Basically, it just shifts the operation up 3 so that it is never negative. You can read more about this kind of thing here: circular buffer. I like examples, so here is something that may help.
Ties:
1v1 -> (1 - 1 + 3) % 3 -> 3 % 3 -> 1 rem 0
2v2 -> (2 - 2 + 3) % 3 -> 3 % 3 -> 1 rem 0
3v3 -> (3 - 3 + 3) % 3 -> 3 % 3 -> 1 rem 0
player 1 win
1v3 -> (1 - 3 + 3) % 3 -> 1 % 3 -> 0 rem 1
2v1 -> (2 - 1 + 3) % 3 -> 4 % 3 -> 1 rem 1
3v2 -> (3 - 2 + 3) % 3 -> 4 % 3 -> 1 rem 1
player 2 win
1v2 -> (1 - 2 + 3) % 3 -> 2 % 3 -> 0 rem 2
2v3 -> (2 - 3 + 3) % 3 -> 2 % 3 -> 0 rem 2
3v1 -> (3 - 1 + 3) % 3 -> 5 % 3 -> 1 rem 2
The pattern here is that all of the remainders (results of the modulus operator) all match up. How convenient! Now we can just match that case to an if-statement, and we know who won every game.

Related

If Statement logic is not correct

I have this if statement and it is not working:
if (pEntry->GetStudentMaterialStudyPoint(StudentAssign::kBibleReading) == 1 &&
(pEntry->GetStudentMaterialStudyPoint(StudentAssign::kItem1) == 1 && LOBYTE(LOWORD(pEntry->GetStudentAssignFlags()))) &&
(pEntry->GetStudentMaterialStudyPoint(StudentAssign::kItem2) == 1 && HIBYTE(LOWORD(pEntry->GetStudentAssignFlags()))) &&
(pEntry->GetStudentMaterialStudyPoint(StudentAssign::kItem3) == 1 && LOBYTE(HIWORD(pEntry->GetStudentAssignFlags()))) &&
(pEntry->GetStudentMaterialStudyPoint(StudentAssign::kItem4) == 1 && HIBYTE(HIWORD(pEntry->GetStudentAssignFlags()))))
{
MWBValidationErrorStruct errorMWBValidation;
errorMWBValidation.iDateIndex = iDateIndex;
errorMWBValidation.datMeeting = pEntry->GetMeetingDate();
errorMWBValidation.eValidationErrorType = CChristianLifeMinistryDefines::MWBValidationErrorType::MaterialStudyPoints;
m_listValidationErrors.push_back(errorMWBValidation);
}
}
I am trying to find out if all of the items have a value of 1. The first item (bible reading) will always be checked. But the items 1 to 4 only need to be checked if they are "included". That is what the LOBYTE(LOWORD(pEntry->GetStudentAssignFlags())) is for.
So,
Bible Reading - 1
Item 1 - 1
Item 2 - 1 - Not included
Item 3 - 1 - Not included
Item 4 - 1 - Not included
In the above scenario the if should be true because both BR and Item 1 are set to 1. We ignore the other 3 items.
Bible Reading - 1
Item 1 - 2
Item 2 - 3
Item 3 - 1 - Not included
Item 4 - 1 - Not included
In the above scenario the if should return false because all the values are not 1 and we are ignoring the last two items.
What is wrong with my if logic?
You should use (!included || x == 1) to ignore checking an item if it's not included. Because of short circuiting, if included is false, you won't even check the other side of the OR, which is exactly what you want.
Your if could look like:
if (pEntry->GetStudentMaterialStudyPoint(StudentAssign::kBibleReading) == 1 &&
(!LOBYTE(LOWORD(pEntry->GetStudentAssignFlags())) || pEntry->GetStudentMaterialStudyPoint(StudentAssign::kItem1) == 1) &&
...
This may be a little confusing, so let's make a truth table...
included | x | !included | x == 1 | (!included || x == 1)
------------------------------------------------------
false | 3 | true | false | true
true | 3 | false | false | false
true | 1 | false | true | true
If included = false, then !included will be true, so (!included || x == 1) will always be true. This is what we want--if we're not included, just evaluate to true without even checking x == 1.
If included = true, then !included is false, so the value of (!included || x == 1) will be whatever x == 1 is. Which is again what we want. If we're included, then depend on x == 1.

mutliline regex concatenation

I have a tough one here which I am struggling with. It involves a case of multiline search-replace and/or concatenation situation.
Here is my input text:
//
import tset flash_read, flash_writ;
vector ( $tset , (XMOSI, XMISO, XSCLK, XSTRMSTRT, XSTRMSCLK, XSTRMCKEN, XXTALIN, XXTALCPUEN, XHVREGON, XFDRESET, XGLDATA5, XGLDATA4, XGLDATA3, XGLDATA2, XGLDATA1, XGLDATA0):H, (XSTRMD3, XSTRMD2, XSTRMD1, XSTRMD0, XNSS3, XNSS2, XNSS1, XNSS0):H, XTECLOCK, XRXDATA, XRXENABLE, XTXDATA, XTXENABLE, XNRESET, XTCK, XTMS, XTDI, XTDO, XNTRST)
{
repeat 2
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 0; // XNTRST
repeat 9
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Test Logic Reset
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 1; // Run Test Idle
repeat 2
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Select IR
My desired output format is this:
//
import tset flash_read, flash_writ;
vector ( $tset , (XMOSI, XMISO, XSCLK, XSTRMSTRT, XSTRMSCLK, XSTRMCKEN, XXTALIN, XXTALCPUEN, XHVREGON, XFDRESET, XGLDATA5, XGLDATA4, XGLDATA3, XGLDATA2, XGLDATA1, XGLDATA0):H, (XSTRMD3, XSTRMD2, XSTRMD1, XSTRMD0, XNSS3, XNSS2, XNSS1, XNSS0):H, XTECLOCK, XRXDATA, XRXENABLE, XTXDATA, XTXENABLE, XNRESET, XTCK, XTMS, XTDI, XTDO, XNTRST)
{
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 0; // XNTRST
repeat 9 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Test Logic Reset
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 1; // Run Test Idle
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Select IR
I am looking for a unix one liner that would search for lines that contain repeat in the input text and replace the new line character at the end of repeat count with a space such that the end outcome looks like the repeat line being concatenated with its next line as illustrated in the output text with the indicated number of white spaces.
For lines that do not contain a repeat count, it is just a matter of pushing the commencement of the line to as many spaces as illustrated in the output text.
Some of the areas where I have explored to accomplish this but with futile finishes are
(1) Sed with usage of branch labels, N, pattern space
(2) AWK with changing the RS
(3) Perl with s/// and multiline flag turned on
Granted that this could be done with nested regex if conditions in a full-fledged perl or python script but I am looking for a more elegant solution.
In perl:
perl -0777 -lne 's/^(repeat[ ]+\d+)\s+/\1\t/mg; s/^[ ]*>/\t\t>/mg; print' file
//
import tset flash_read, flash_writ;
vector ( , (XMOSI, XMISO, XSCLK, XSTRMSTRT, XSTRMSCLK, XSTRMCKEN, XXTALIN, XXTALCPUEN, XHVREGON, XFDRESET, XGLDATA5, XGLDATA4, XGLDATA3, XGLDATA2, XGLDATA1, XGLDATA0):H, (XSTRMD3, XSTRMD2, XSTRMD1, XSTRMD0, XNSS3, XNSS2, XNSS1, XNSS0):H, XTECLOCK, XRXDATA, XRXENABLE, XTXDATA, XTXENABLE, XNRESET, XTCK, XTMS, XTDI, XTDO, XNTRST)
{
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 0; // XNTRST
repeat 9 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Test Logic Reset
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 1; // Run Test Idle
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Select IR
Or, you can also do:
perl -0777 -lpe 's/^(repeat[ ]+\d+)\s+/\1\t/mg; s/^[ ]*>/\t\t>/mg;' file
You may need to play with how many \t in the second substitution, but you get the idea.
Ed's awk is brilliant. You can also do something like that in perl:
perl -lne ' if (/^repeat[\h]+\d+/) {$ll=$_; next}
if (/^\h+>/) {$_=sprintf("%-21s%s",$ll,$_);$ll="";}
print' file
$ awk '
/^repeat/ { pfx = $0; next }
/^ >/ { $0 = sprintf("%-21s%s", pfx, $0); pfx="" }
{ print }
' file
//
import tset flash_read, flash_writ;
vector ( $tset , (XMOSI, XMISO, XSCLK, XSTRMSTRT, XSTRMSCLK, XSTRMCKEN, XXTALIN, XXTALCPUEN, XHVREGON, XFDRESET, XGLDATA5, XGLDATA4, XGLDATA3, XGLDATA2, XGLDATA1, XGLDATA0):H, (XSTRMD3, XSTRMD2, XSTRMD1, XSTRMD0, XNSS3, XNSS2, XNSS1, XNSS0):H, XTECLOCK, XRXDATA, XRXENABLE, XTXDATA, XTXENABLE, XNRESET, XTCK, XTMS, XTDI, XTDO, XNTRST)
{
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 0; // XNTRST
repeat 9 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Test Logic Reset
> flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 0 0 X 1; // Run Test Idle
repeat 2 > flash_writ X0X00X0XXXXXXXXX 0000XXXX X 0 L X X 0 1 1 0 X 1; // Select IR
or if you prefer brevity over clarity:
awk '/^repeat/{p=$0;next} /^ >/{$0=sprintf("%-21s",p)$0;p=""} 1' file
and if you want "in place" editing then use GNU awk:
awk -i inplace '/^repeat/{p=$0;next} /^ >/{$0=sprintf("%-21s",p)$0;p=""} 1' file

Find position of first non-zero decimal

Suppose I have the following local macro:
loc a = 12.000923
I would like to get the decimal position of the first non-zero decimal (4 in this example).
There are many ways to achieve this. One is to treat a as a string and to find the position of .:
loc a = 12.000923
loc b = strpos(string(`a'), ".")
di "`b'"
From here one could further loop through the decimals and count since I get the first non-zero element. Of course this doesn't seem to be a very elegant approach.
Can you suggest a better way to deal with this? Regular expressions perhaps?
Well, I don't know Stata, but according to the documentation, \.(0+)? is suported and it shouldn't be hard to convert this 2 lines JavaScript function in Stata.
It returns the position of the first nonzero decimal or -1 if there is no decimal.
function getNonZeroDecimalPosition(v) {
var v2 = v.replace(/\.(0+)?/, "")
return v2.length !== v.length ? v.length - v2.length : -1
}
Explanation
We remove from input string a dot followed by optional consecutive zeros.
The difference between the lengths of original input string and this new string gives the position of the first nonzero decimal
Demo
Sample Snippet
function getNonZeroDecimalPosition(v) {
var v2 = v.replace(/\.(0+)?/, "")
return v2.length !== v.length ? v.length - v2.length : -1
}
var samples = [
"loc a = 12.00012",
"loc b = 12",
"loc c = 12.012",
"loc d = 1.000012",
"loc e = -10.00012",
"loc f = -10.05012",
"loc g = 0.0012"
]
samples.forEach(function(sample) {
console.log(getNonZeroDecimalPosition(sample))
})
You can do this in mata in one line and without using regular expressions:
foreach x in 124.000923 65.020923 1.000022030 0.0090843 .00000425 {
mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
}
4
2
5
3
6
Below, you can see the steps in detail:
. local x = 124.000823
. mata:
: /* Step 1: break Stata's local macro x in tokens using . as a parsing char */
: a = tokens(st_local("x"), ".")
: a
1 2 3
+----------------------------+
1 | 124 . 000823 |
+----------------------------+
: /* Step 2: tokenize the string in a[1,3] using 0 as a parsing char */
: b = tokens(a[3], "0")
: b
1 2 3 4
+-------------------------+
1 | 0 0 0 823 |
+-------------------------+
: /* Step 3: find which values are different from zero */
: c = b :!= "0"
: c
1 2 3 4
+-----------------+
1 | 0 0 0 1 |
+-----------------+
: /* Step 4: find the first index position where this is true */
: d = selectindex(c :!= 0)[1]
: d
4
: end
You can also find the position of the string of interest in Step 2 using the
same logic.
This is the index value after the one for .:
. mata:
: k = selectindex(a :== ".") + 1
: k
3
: end
In which case, Step 2 becomes:
. mata:
:
: b = tokens(a[k], "0")
: b
1 2 3 4
+-------------------------+
1 | 0 0 0 823 |
+-------------------------+
: end
For unexpected cases without decimal:
foreach x in 124.000923 65.020923 1.000022030 12 0.0090843 .00000425 {
if strmatch("`x'", "*.*") mata: selectindex(tokens(tokens(st_local("x"), ".")[selectindex(tokens(st_local("x"), ".") :== ".") + 1], "0") :!= "0")[1]
else display " 0"
}
4
2
5
0
3
6
A straighforward answer uses regular expressions and commands to work with strings.
One can select all decimals, find the first non 0 decimal, and finally find its position:
loc v = "123.000923"
loc v2 = regexr("`v'", "^[0-9]*[/.]", "") // 000923
loc v3 = regexr("`v'", "^[0-9]*[/.][0]*", "") // 923
loc first = substr("`v3'", 1, 1) // 9
loc first_pos = strpos("`v2'", "`first'") // 4: position of 9 in 000923
di "`v2'"
di "`v3'"
di "`first'"
di "`first_pos'"
Which in one step is equivalent to:
loc first_pos2 = strpos(regexr("`v'", "^[0-9]*[/.]", ""), substr(regexr("`v'", "^[0-9]*[/.][0]*", ""), 1, 1))
di "`first_pos2'"
An alternative suggested in another answer is to compare the lenght of the decimals block cleaned from the 0s with that not cleaned.
In one step this is:
loc first_pos3 = strlen(regexr("`v'", "^[0-9]*[/.]", "")) - strlen(regexr("`v'", "^[0-9]*[/.][0]*", "")) + 1
di "`first_pos3'"
Not using regex but log10 instead (which treats a number like a number), this function will:
For numbers >= 1 or numbers <= -1, return with a positive number the number of digits to the left of the decimal.
Or (and more specifically to what you were asking), for numbers between 1 and -1, return with a negative number the number of digits to the right of the decimal where the first non-zero number occurs.
digitsFromDecimal = (n) => {
dFD = Math.log10(Math.abs(n)) | 0;
if (n >= 1 || n <= -1) { dFD++; }
return dFD;
}
var x = [118.8161330, 11.10501660, 9.254180571, -1.245501523, 1, 0, 0.864931613, 0.097007836, -0.010880074, 0.009066729];
x.forEach(element => {
console.log(`${element}, Digits from Decimal: ${digitsFromDecimal(element)}`);
});
// Output
// 118.816133, Digits from Decimal: 3
// 11.1050166, Digits from Decimal: 2
// 9.254180571, Digits from Decimal: 1
// -1.245501523, Digits from Decimal: 1
// 1, Digits from Decimal: 1
// 0, Digits from Decimal: 0
// 0.864931613, Digits from Decimal: 0
// 0.097007836, Digits from Decimal: -1
// -0.010880074, Digits from Decimal: -1
// 0.009066729, Digits from Decimal: -2
Mata solution of Pearly is very likable, but notice should be paid for "unexpected" cases of "no decimal at all".
Besides, the regular expression is not a too bad choice when it could be made in a memorable 1-line.
loc v = "123.000923"
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
Below code tests with more values of v.
foreach v in 124.000923 605.20923 1.10022030 0.0090843 .00000425 12 .000125 {
capture local x = regexm("`v'","(\.0*)")*length(regexs(0))
di "`v': The wanted number = `x'"
}

Printing element of List in a different way

I need to print a List of Lists using Scala and the function toString, where every occurrence of 0 needs to be replaced by an '_'. This is my attempt so far. The commented code represents my different attempts.
override def toString() = {
// grid.map(i => if(i == 0) '_' else i)
// grid map{case 0 => '_' case a => a}
// grid.updated(0, "_")
//grid.map{ case 0 => "_"; case x => x}
grid.map(_.mkString(" ")).mkString("\n")
}
My output should look something like this, but an underscore instead of the zeros
0 0 5 0 0 6 3 0 0
0 0 0 0 0 0 4 0 0
9 8 0 7 4 0 0 0 5
1 0 0 0 7 0 9 0 0
0 0 9 5 0 1 6 0 0
0 0 8 0 2 0 0 0 7
6 0 0 0 1 8 0 9 3
0 0 1 0 0 0 0 0 0
Thanks in advance.
Just put an extra map in there to change 0 to _
grid.map(_.map(_ match {case 0 => "_"; case x => x}).mkString(" ")).mkString("\n")
Nothing special:
def toString(xs: List[List[Int]]) = xs.map { ys =>
ys.map {
case 0 => "_"
case x => String.valueOf(x)
}.mkString(" ")
}.mkString("\n")
Although the other solutions are functionally correct, I believe this shows more explicitly what happens and as such is better suited for a beginner:
def gridToString(grid: List[List[Int]]): String = {
def replaceZero(i: Int): Char =
if (i == 0) '_'
else i.toString charAt 0
val lines = grid map { line =>
line map replaceZero mkString " "
}
lines mkString "\n"
}
First we define a method for converting the digit into a character, replacing zeroes with underscores. (It is assumed from your example that all the Int elements are < 10.)
The we take each line of the grid, run each of the digits in that line through our conversion method and assemble the resulting chars into a string.
Than we take we take the resulting line-strings and turn them into the final string.
The whole thing could be written shorter, but it wouldn't necessarily be more readable.
It is also good Scala style to use small inner methods like replaceZero in this example instead of writing all code inline, as the naming of a method helps indicating what it is does, and as such enhances readability.
There's always room for another solution. ;-)
A grid:
type Grid[T] = List[List[T]]
Print a grid:
def print[T](grid: Grid[T]) = grid map(_ mkString " ") mkString "\n"
Replace all zeroes:
for (row <- grid) yield row.collect {
case 0 => "_"
case anything => anything
}

Regex Negations in Vim

Question:
How do I convert var x+=1+2+3+(5+6+7) to var x += 1 + 2 + 3 + ( 5 + 6 + 7 )
Details:
Using regular expressions, something like :%s/+/\ x\ /g won't work because it will convert += to + = (amongst other problems). So instead one would use negations (negatives, nots, whatever they're called) like so :%s/\s\#!+/\ +/g, which is about as complicated a way as one can say "plus sign without an empty space before it". But now this converts something like x++ into x + +. What I need is something more complex. I need more than one constraint in the negation, and an additional constraint afterwards. Something like so, but this doesn't work :%s/[\s+]\#!+\x\#!/\ +/g
Could someone please provide the one, or possibly two regex statements which will pad out an example operator, such that I can model the rest of my rules on it/them.
Motivation:
I find beautifiers for languages like javascript or PHP don't give me full control (see here). Therefore, I am attempting to use regex to carry out the following conversions:
foo(1,2,3,4) → foo( 1, 2, 3, 4 )
var x=1*2*3 → var x = 1 * 2 * 3
var x=1%2%3 → var x = 1 % 2 % 3
var x=a&&b&&c → var x = a && b && c
var x=a&b&c → var x = a & b & c
Any feedback would also be appreciated
Thanks to the great feedback, I now have a regular expression like so to work from. I am running these two regular expressions:
:%s/\(\w\)\([+\-*\/%|&~)=]\)/\1\ \2/g
:%s/\([+\-*\/%|&~,(=]\)\(\w\)/\1\ \2/g
And it is working fairly well. Here are some results.
(1+2+3+4,1+2+3+4,1+2+3+4) --> ( 1 + 2 + 3 + 4, 1 + 2 + 3 + 4, 1 + 2 + 3 + 4 )
(1-2-3-4,1-2-3-4,1-2-3-4) --> ( 1 - 2 - 3 - 4, 1 - 2 - 3 - 4, 1 - 2 - 3 - 4 )
(1*2*3*4,1*2*3*4,1*2*3*4) --> ( 1 * 2 * 3 * 4, 1 * 2 * 3 * 4, 1 * 2 * 3 * 4 )
(1/2/3/4,1/2/3/4,1/2/3/4) --> ( 1 / 2 / 3 / 4, 1 / 2 / 3 / 4, 1 / 2 / 3 / 4 )
(1%2%3%4,1%2%3%4,1%2%3%4) --> ( 1 % 2 % 3 % 4, 1 % 2 % 3 % 4, 1 % 2 % 3 % 4 )
(1|2|3|4,1|2|3|4,1|2|3|4) --> ( 1 | 2 | 3 | 4, 1 | 2 | 3 | 4, 1 | 2 | 3 | 4 )
(1&2&3&4,1&2&3&4,1&2&3&4) --> ( 1 & 2 & 3 & 4, 1 & 2 & 3 & 4, 1 & 2 & 3 & 4 )
(1~2~3~4,1~2~3~4,1~2~3~4) --> ( 1 ~ 2 ~ 3 ~ 4, 1 ~ 2 ~ 3 ~ 4, 1 ~ 2 ~ 3 ~ 4 )
(1&&2&&3&&4,1&&2&&3&&4,1&&2&&3&&4) --> ( 1 && 2 && 3 && 4, 1 && 2 && 3 && 4, 1 && 2 && 3 && 4 )
(1||2||3||4,1||2||3||4,1||2||3||4) --> ( 1 || 2 || 3 || 4, 1 || 2 || 3 || 4, 1 || 2 || 3 || 4 )
var x=1+(2+(3+4*(965%(123/(456-789))))); --> var x = 1 +( 2 +( 3 + 4 *( 965 %( 123 /( 456 - 789 )))));
It seems to work fine for everything except nested brackets. If I fix the nested brackets problem, I will update it here.