#!/bin/zsh SAVEFILE=~/.local/share/1248.save #PAUSE_COMBINE=0.1 PAUSE_POPULATE=0.1 #DRAW_CLEAR=1 function draw { [ "$DRAW_CLEAR" ] && clear || tput cup 0 0 index=1 for y in {0..3}; do for x in {0..3}; do this=${grid[$index]} if [ "$this" ]; then printf "%2d " ${grid[$index]} else printf " ยท " fi index=$(( $index + 1 )) done echo done } function populate { # Go through each board position randomly echo {1..16} | sed 's/ /\n/g' | sort -R | while read index; do this=${grid[$index]} if [ -z "$this" ]; then # 2/3 chance for 0, 1/3 chance for 1 grid[$index]=$(( ($RANDOM % 3) / 2 )) return fi done } function move { # $1: Direction (vim style) case $1 in 0) start=1 startstep=4 step=1 ;; 1) start=13 startstep=1 step=-4 ;; 2) start=1 startstep=1 step=4 ;; 3) start=4 startstep=4 step=-1 ;; esac # Entire game logic # For each row/column, iterate through in reverse order and keep track of the # last filled tile and first free tile moved=1 for s in {0..3}; do pos=$start firstfree= lastfill= for p in {0..3}; do this=${grid[$pos]} if [ "$this" ]; then # If not first tile in row/column if [ "$lastfill" ]; then last=${grid[$lastfill]} # If tiles match, combine them if [ "$this" = "$last" ]; then moved=0 # Remove tile and "double" the last one grid[$pos]= grid[$lastfill]=$(( $last + 1 )) firstfree=$(( $lastfill + $step )) # Don't want to count the combined tile to combine further this turn lastfill= [ $PAUSE_COMBINE ] && draw && sleep $PAUSE_COMBINE else # If tiles don't match, but there is space to move the tile if [ "$firstfree" ]; then moved=0 # Move tile back grid[$pos]= grid[$firstfree]=$this lastfill=$firstfree firstfree=$(( $firstfree + $step )) else lastfill=$pos fi fi # If first tile in row/column, but there is space to move the tile elif [ "$firstfree" ]; then moved=0 # Move tile back grid[$pos]= grid[$firstfree]=$this lastfill=$firstfree firstfree=$(( $firstfree + $step )) else lastfill=$pos fi elif [ -z "$firstfree" ]; then firstfree=$pos fi pos=$(( $pos + $step )) done start=$(( $start + $startstep )) done return moved } function save { echo -n "( " > $SAVEFILE for i in {1..16}; do echo -n "\"${grid[$i]}\" " >> $SAVEFILE done echo -n ")" >> $SAVEFILE } function load { if [ -f "$SAVEFILE" ]; then eval grid=$( cat "$SAVEFILE" ) return 0 fi return 1 } clear if ! load; then grid=() populate fi while true; do draw dir= case $( read -ke ) in h) dir=0 ;; j) dir=1 ;; k) dir=2 ;; l) dir=3 ;; o) load continue ;; w) save continue ;; n) grid=() populate continue ;; q) save exit ;; *) continue ;; esac if move $dir; then if [ "$PAUSE_POPULATE" ]; then draw sleep $PAUSE_POPULATE fi populate fi done