From c7d58f3e2af41f6656d8de16768f7340ab148783 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 27 Mar 2014 10:51:56 +0100 Subject: [PATCH 1/2] google maps enabled monsters --- bashman.sh | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/bashman.sh b/bashman.sh index cb89162..ac4ff33 100755 --- a/bashman.sh +++ b/bashman.sh @@ -18,6 +18,120 @@ dxm=-1 dym=0 } +function noschersvoisins () { + local -i x="$1" + local -i y="$2" + + voisins=() + + # à gauche + if (( x > 0 )); then + voisins[${#voisins}]=$((y*width+(x-1))) + fi + # à droite + if (( x < width )); then + voisins[${#voisins}]=$((y*width+(x+1))) + fi + # en haut + if (( y > 0 )); then + voisins[${#voisins}]=$(((y-1)*width+x)) + fi + # en bas + if (( y < height )); then + voisins[${#voisins}]=$(((y+1)*width+x)) + fi + # ces soirées là ... ♫ ♪ ♬ +} + +function googlemaps () { # calcul le chemin le plus court du monstre + # vers le perso + # (note: l'auteur est devenu aveugle en relisant son code) + local x="$1" + local y="$2" + local -i src=$((y*width+x)) + local -a q=() + local -a Q=() + local -i q_offset=0 + local -a visited=() + local -a dist=() + local -i maxdist=65535 + + previous=() + + for (( vertex=0; vertex < width*height; vertex++ )); do + if [[ ${maping:$vertex:1} -eq 1 ]]; then + continue + fi + dist[$vertex]=$maxdist + if (( vertex == src )); then + (( q[${#q[@]}] = q[0] )) + (( q[0]= src )) + else + (( q[${#q[@]}] = vertex )) + fi + done + + dist[$src]=0 + + while true; do + + ((u=q[q_offset++])) + visited[$u]=$((q_offset-1)) + + if [[ -z "$u" ]] || (( dist[u] == maxdist )); then + throw "Le perso n'est pas reachable" + fi + + # echo "best dist is $u $((u % width))x$((u / width)): ${dist[u]}" + if (( u == (ym*width+xm) )); then + break + fi + + # mise à jour de la liste des voisins + noschersvoisins $((u % width)) $((u / width)) + # echo "$u: ${voisins[@]}" + + for v in "${voisins[@]}"; do + if [[ ${maping:$v:1} -eq 1 ]] || ! [[ -z "${visited[$v]}" ]]; then + continue + fi + if (((dist[u] + 1) < dist[v])); then + ((dist[v] = dist[u] + 1)) + previous[v]=$u + # on remet $v au début de la queue, et on swap les éléments + # pour placer $v à la bonne position + d=dist[v] + (( q[--q_offset]=v )) + q_len=${#q[@]} + if false; then + for (( o = q_offset+1; o < q_len; ++o )); do + if (( dist[q[o]] < d )); then + (( q[o-1] = q[o] )) + (( q[o] = v )) + else + break + fi + done + fi + unset visited[$v] + echo "============" + for (( o = q_offset; o < q_len; ++o )); do + printf "%s: %s\n" $((q[o])) $((dist[q[o]])) + done + exit + fi + done + done + + echo ${previous[$((ym*width+xm))]} +} + +function throw () { + # throw table + echo "$1 (╯°□°)╯︵ ┻━┻ " + exit 1 +} + function affichemap () { tmp=`cat map` @@ -253,6 +367,8 @@ function highscore () { #Cette fonction permet d'enregister le score que l'on } function monstre () { #cette fonction gere les deplacement "intelligents" du monstre + + googlemaps $x $y if [ $x -gt $xm ] ; then #si la position sur l'axe Ox du perso est plus grande que celle du monstre dxm=1 #alors le monstre tend a se deplacer vers la gauche From c8c14134b94da8a3b84beee48eecc6df35e9f4f7 Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 1 Apr 2014 12:36:28 +0200 Subject: [PATCH 2/2] improved speed --- bashman.sh | 106 ++++++++++++++--------------------------------------- heap.sh | 82 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 78 deletions(-) create mode 100644 heap.sh diff --git a/bashman.sh b/bashman.sh index ac4ff33..ad61ccc 100755 --- a/bashman.sh +++ b/bashman.sh @@ -1,5 +1,7 @@ #! /bin/bash +. ./heap.sh + function initialisation(){ #initialisation du terminal save = stty -g #sauvegarde de l'etat initial du terminal tput clear #effacement du terminal @@ -26,19 +28,19 @@ function noschersvoisins () { # à gauche if (( x > 0 )); then - voisins[${#voisins}]=$((y*width+(x-1))) + voisins[${#voisins[@]}]=$((y*width+(x-1))) fi # à droite if (( x < width )); then - voisins[${#voisins}]=$((y*width+(x+1))) + voisins[${#voisins[@]}]=$((y*width+(x+1))) fi # en haut if (( y > 0 )); then - voisins[${#voisins}]=$(((y-1)*width+x)) + voisins[${#voisins[@]}]=$(((y-1)*width+x)) fi # en bas if (( y < height )); then - voisins[${#voisins}]=$(((y+1)*width+x)) + voisins[${#voisins[@]}]=$(((y+1)*width+x)) fi # ces soirées là ... ♫ ♪ ♬ } @@ -49,47 +51,48 @@ function googlemaps () { # calcul le chemin le plus court du monstre local x="$1" local y="$2" local -i src=$((y*width+x)) - local -a q=() - local -a Q=() - local -i q_offset=0 local -a visited=() local -a dist=() local -i maxdist=65535 + heap_init + previous=() for (( vertex=0; vertex < width*height; vertex++ )); do if [[ ${maping:$vertex:1} -eq 1 ]]; then continue fi - dist[$vertex]=$maxdist if (( vertex == src )); then - (( q[${#q[@]}] = q[0] )) - (( q[0]= src )) + (( d = 0 )) else - (( q[${#q[@]}] = vertex )) + (( d = $maxdist )) fi + dist[$vertex]=$d + heap_add $vertex $d done - dist[$src]=0 - while true; do - ((u=q[q_offset++])) - visited[$u]=$((q_offset-1)) + u=${heap_values[1]} + + if [[ -z "$u" ]]; then + break + fi - if [[ -z "$u" ]] || (( dist[u] == maxdist )); then + heap_remove + visited[$u]=1 + + if (( dist[u] == maxdist )); then throw "Le perso n'est pas reachable" fi - # echo "best dist is $u $((u % width))x$((u / width)): ${dist[u]}" if (( u == (ym*width+xm) )); then break fi # mise à jour de la liste des voisins noschersvoisins $((u % width)) $((u / width)) - # echo "$u: ${voisins[@]}" for v in "${voisins[@]}"; do if [[ ${maping:$v:1} -eq 1 ]] || ! [[ -z "${visited[$v]}" ]]; then @@ -98,27 +101,8 @@ function googlemaps () { # calcul le chemin le plus court du monstre if (((dist[u] + 1) < dist[v])); then ((dist[v] = dist[u] + 1)) previous[v]=$u - # on remet $v au début de la queue, et on swap les éléments - # pour placer $v à la bonne position - d=dist[v] - (( q[--q_offset]=v )) - q_len=${#q[@]} - if false; then - for (( o = q_offset+1; o < q_len; ++o )); do - if (( dist[q[o]] < d )); then - (( q[o-1] = q[o] )) - (( q[o] = v )) - else - break - fi - done - fi - unset visited[$v] - echo "============" - for (( o = q_offset; o < q_len; ++o )); do - printf "%s: %s\n" $((q[o])) $((dist[q[o]])) - done - exit + ((d=dist[v])) + heap_add $v $d fi done done @@ -368,43 +352,6 @@ function highscore () { #Cette fonction permet d'enregister le score que l'on function monstre () { #cette fonction gere les deplacement "intelligents" du monstre - googlemaps $x $y - -if [ $x -gt $xm ] ; then #si la position sur l'axe Ox du perso est plus grande que celle du monstre - dxm=1 #alors le monstre tend a se deplacer vers la gauche - dym=0 - if [ ${maping:$(((($ym+$dym)*$width)+($xm+$dxm))):1} -eq 1 ] ; then #mais si la prochaine position est un mur - dxm=0 - dym=1 #alors le perso tend a se deplacer vers le bas - fi - -elif [ $x -lt $xm ] ; then #si la position sur l'axe Ox du perso est plus petite que celle du monstre - dxm=-1 #alors le monstre tend a se deplacer vers la droite - dym=0 - if [ ${maping:$(((($ym+$dym)*$width)+($xm+$dxm))):1} -eq 1 ] ; then #mais si la prochaine position est un mur - dxm=0 - dym=-1 #alors le perso tend a se deplacer vers le haut - fi - - -elif [ $y -lt $ym ] ; then #si la position sur l'axe Oy du perso est plus petite que celle du monstre - dym=-1 #alors le monstre tend a se deplacer vers le haut - dxm=0 - if [ ${maping:$(((($ym+$dym)*$width)+($xm+$dxm))):1} -eq 1 ] ; then #mais si la prochaine position est un mur - dxm=-1 #alors le monstre tend a se deplacer vers la gauche - dym=0 - fi - - -elif [ $y -gt $ym ] ; then #si la position sur l'axe Oy du perso est plus grande que celle du monstre - dym=1 #alors le monstre tend a se deplacer vers le bas - dxm=0 - if [ ${maping:$(((($ym+$dym)*$width)+($xm+$dxm))):1} -eq 1 ] ; then #mais si la prochaine position est un mur - dxm=1 #alors le monstre tend a se deplacer vers la droite - dym=0 - fi -fi - if [ $y -eq $ym ] ; then #si la position du perso est egale a la position du monstre if [ $x -eq $xm ] ; then clear #effacement de la carte @@ -416,6 +363,8 @@ fi #deplacement du monstre + vm=$(googlemaps $x $y) + tput cup $ym $xm tput setaf 3 if [ ${maping:$(((($ym)*$width)+($xm))):1} -eq 0 ] ; then #si le caractere sous le monstre est un points @@ -424,8 +373,9 @@ fi if [ ${maping:$(((($ym)*$width)+($xm))):1} -eq 3 ] ; then #sinon echo -n " " #on laisse l'espace fi - xm=$((($xm+$dxm))) #deplacement du monstre sur Ox - ym=$((($ym+$dym))) #deplacement du monstre sur Oy + + ((xm = vm % width)) + ((ym = vm / width)) tput cup $ym $xm tput setaf 5 diff --git a/heap.sh b/heap.sh new file mode 100644 index 0000000..1f9ce49 --- /dev/null +++ b/heap.sh @@ -0,0 +1,82 @@ + +declare -a heap_values +declare -a heap_prios + +function heap_init() { + heap_values=(0) + heap_prios=(0) +} + +function heap_add() { + local v=$1 + local p=$2 + local len=${#heap_values[@]} + + heap_values[$len]="$v" + heap_prios[$len]="$p" + + heap_bubbleup +} + +function heap_remove() { + local i=$((${#heap_values[@]}-1)) + local result=${heap_values[1]} + + if (( i == 0 )); then + return + fi + + heap_values[1]=${heap_values[$i]} + heap_prios[1]=${heap_prios[$i]} + + unset heap_values[$i] + unset heap_prios[$i] + + heap_bubbledown +} + +function heap_bubbledown() { + + local i=1 + local len=${#heap_values[@]} + + while (( i*2 < len )); do + local smaller=$((i*2)) + if (( i*2+1 < len )) && (( heap_prios[i*2] > heap_prios[i*2+1] )); then + ((smaller=i*2+1)) + fi + if (( heap_prios[i] > heap_prios[smaller] )); then + heap_swap $i $smaller + else + break + fi + i=$smaller + done +} + +function heap_bubbleup() { + local i=$((${#heap_values[@]}-1)) + local prio + + (( prio = heap_prios[i] )) + + while (( i > 1 )) && (( heap_prios[i/2] > prio )); do + heap_swap $i $((i/2)) + (( i = i/2 )) + done +} + +function heap_swap() { + local a="$1" + local b="$2" + local tmp + + tmp="${heap_values[$a]}" + heap_values[$a]="${heap_values[$b]}" + heap_values[$b]="$tmp" + + tmp="${heap_prios[$a]}" + heap_prios[$a]="${heap_prios[$b]}" + heap_prios[$b]="$tmp" +} +