Bash does not have 2-D arrays. The best you can do is emulate them with associative arrays.
Add the following line to the beginning of your script:
declare -A x
This makes x into an associative array. When that is done, the script produces the output that you expect:
$ bash script
x[1,1]=0
x[2,1]=1
loop1 x[1,1]=1
loop2 x[2,1]=2
x[1,1]=1
x[2,1]=2
Bash indexed arrays
Unless declare -A is used, a bash array is just an indexed array. Let's define y as an indexed array:
$ y=()
Now, let's assign two values:
$ y[2,3]=1
$ y[22,3]=2
Now, let's use declare -p to find out what the contents of the array really are:
$ declare -p y
declare -a y='([3]="2")'
As you can see, there is only y[3]. The reason is that the index in an indexed array is subject to arithmetic expansion and, when given a list of comma-separated values, arithmetic expansion returns just the last one.
In other words, as far as bash is concerned, assignments to y[2,3] and y[22,3] are both just assignments to y[3]. The second assignment overwrites the first.
We can see this directly if we echo the results of arithmetic expansion:
$ echo $((3))
3
$ echo $((2,3))
3
$ echo $((22,3))
3
When given a list of comma-separated values, arithmetic expansion returns the last one. This is true even if the comma-separated list is a long one:
$ echo $((1+2,3*4,5,6,7,8))
8
It is always the last value which is returned.
Bash associative arrays
Let's examine what happens with associative arrays. Let's define z as an associative array and assign some values to it:
$ declare -A z
$ z[1,2]=1
$ z[3,4]=2
$ z["Jim Bob"]=3
Now, let's see what was stored in z:
$ declare -p z
declare -A z='([3,4]="2" ["Jim Bob"]="3" [1,2]="1" )'
This seems to be what you need.