From d37d2ba60310084f9e4b8d9e85c9ccd3d6f245f1 Mon Sep 17 00:00:00 2001 From: Marc Heiligers Date: Sun, 28 Feb 2021 16:47:50 -0700 Subject: [PATCH 1/4] BasicArrayTwoD, top row drawn, and trying to logic my way through the next row --- 02 Amazing/ruby/amazing.rb | 276 +++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 02 Amazing/ruby/amazing.rb diff --git a/02 Amazing/ruby/amazing.rb b/02 Amazing/ruby/amazing.rb new file mode 100644 index 00000000..7e7db0ce --- /dev/null +++ b/02 Amazing/ruby/amazing.rb @@ -0,0 +1,276 @@ +# frozen_string_literal: true + +# BASIC arrays are 1-based, unlike Ruby 0-based arrays +class BasicArrayTwoD + def initialize(width, height) + @val = Array.new(height) { Array.new(width, 0) } + end + + def [](x, y) + @val[y - 1][x - 1] + end + + def []=(x, y, n) + @val[y - 1][x - 1] = n + end + + def to_s + @val.map { |r| r.join(' ') }.join("\n") + end +end + +# 10 PRINT TAB(28);"AMAZING PROGRAM" +# 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +# 30 PRINT:PRINT:PRINT:PRINT +puts ' ' * 28 + 'AMAZING PROGRAM' +puts ' ' * 15 + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' +puts "\n" * 4 + +# 100 INPUT "WHAT ARE YOUR WIDTH AND LENGTH";H,V +# 102 IF H<>1 AND V<>1 THEN 110 +# 104 PRINT "MEANINGLESS DIMENSIONS. TRY AGAIN.":GOTO 100 +def ask_dimensions + print 'WHAT ARE YOUR WIDTH AND LENGTH? ' + h = gets.to_i + print '?? ' + v = gets.to_i + [h, v] +end + +h, v = ask_dimensions +while h < 1 || v < 1 + puts "MEANINGLESS DIMENSIONS. TRY AGAIN." + h, v = ask_dimensions +end + +# 110 DIM W(H,V),V(H,V) +# BASIC programs can have the same variable names for different types, +# so the v array is not the same as the v int. Here we're using suffixes. +w_arr = BasicArrayTwoD.new(h, v) +v_arr = BasicArrayTwoD.new(h, v) + +# 120 PRINT +# 130 PRINT +# 140 PRINT +# 150 PRINT +puts "\n" * 4 + +# 160 Q=0:Z=0:X=INT(RND(1)*H+1) +q = 0 +z = 0 + +def draw_top(x, h) + # 165 FOR I=1 TO H + # 170 IF I=X THEN 173 + # 171 PRINT ".--";:GOTO 180 + # 173 PRINT ". "; + # 180 NEXT I + (1..h).each do |i| + if i == x + print i == 1 ? '┏ ' : '┳ ' + else + print i == 1 ? '┏━━' : '┳━━' + end + end + + # 190 PRINT "." + puts '┓' + + x # return this because we need it +end + +# x represents the location of the opening +x = (rand * h).round + 1 +draw_top(x, h) + +# 195 C=1:W(X,1)=C:C=C+1 +c = 1 +w_arr[x, 1] = c # This marks the opening in the first row +c += 1 + +puts w_arr + +# 200 R=X:S=1:GOTO 260 +r = x +s = 1 +# 260 IF R-1=0 THEN 530 +if r - 1 == 0 + # 530 IF S-1=0 THEN 670 + if s - 1 == 0 + # 670 IF R=H THEN 740 + if r == h + # 740 IF S<>V THEN 760 + if s != v + # 760 IF W(R,S+1)<>0 THEN 780 + if w_arr[r, s + 1] != 0 + # 780 GOTO 1000 + # Well, we'll just go directly to 1000 + # 1000 GOTO 210 + # Well, now. I just got here, now back to 210 + # 210 IF R<>H THEN 240 + if r != h + # 240 R=R+1 + r += 1 + # 250 IF W(R,S)=0 THEN 210 + if w_arr[r, s] == 0 + # GOTO 210 -- this is a loop + end + # 260 IF R-1=0 THEN 530 + if r - 1 == 0 + # 530 IF S-1=0 THEN 670 + # 540 IF W(R,S-1)<>0 THEN 670 + if s - 1 == 0 || w_arr[r, s - 1] != 0 + # 670 IF R=H THEN 740 + # 680 IF W(R+1,S)<>0 THEN 740 + # 685 IF S<>V THEN 700 + # 690 IF Z=1 THEN 730 + # 695 Q=1:GOTO 710 + end + # 545 IF R=H THEN 610 + # 547 IF W(R+1,S)<>0 THEN 610 + if r == h || w_arr[r + 1, s] != 0 + # 610 IF S<>V THEN 630 + # 620 IF Z=1 THEN 660 + # 625 Q=1:GOTO 640 + end + # 550 IF S<>V THEN 560 + if s != v + # 560 IF W(R,S+1)<>0 THEN 590 + # 570 X=INT(RND(1)*3+1) + # 580 ON X GOTO 820,860,910 + end + # 552 IF Z=1 THEN 590 + if z == 1 + # 590 X=INT(RND(1)*2+1) + # 600 ON X GOTO 820,860 + end + # 554 Q=1:GOTO 570 + q = 1 + # 570 X=INT(RND(1)*3+1) + # 580 ON X GOTO 820,860,910 + end + end + end + end + end + end +end + +# 210 IF R<>H THEN 240 +# 215 IF S<>V THEN 230 +# 220 R=1:S=1:GOTO 250 +# 230 R=1:S=S+1:GOTO 250 +# 240 R=R+1 +# 250 IF W(R,S)=0 THEN 210 +# 260 IF R-1=0 THEN 530 +# 265 IF W(R-1,S)<>0 THEN 530 +# 270 IF S-1=0 THEN 390 +# 280 IF W(R,S-1)<>0 THEN 390 +# 290 IF R=H THEN 330 +# 300 IF W(R+1,S)<>0 THEN 330 +# 310 X=INT(RND(1)*3+1) +# 320 ON X GOTO 790,820,860 +# 330 IF S<>V THEN 340 +# 334 IF Z=1 THEN 370 +# 338 Q=1:GOTO 350 +# 340 IF W(R,S+1)<>0 THEN 370 +# 350 X=INT(RND(1)*3+1) +# 360 ON X GOTO 790,820,910 +# 370 X=INT(RND(1)*2+1) +# 380 ON X GOTO 790,820 +# 390 IF R=H THEN 470 +# 400 IF W(R+1,S)<>0 THEN 470 +# 405 IF S<>V THEN 420 +# 410 IF Z=1 THEN 450 +# 415 Q=1:GOTO 430 +# 420 IF W(R,S+1)<>0 THEN 450 +# 430 X=INT(RND(1)*3+1) +# 440 ON X GOTO 790,860,910 +# 450 X=INT(RND(1)*2+1) +# 460 ON X GOTO 790,860 +# 470 IF S<>V THEN 490 +# 480 IF Z=1 THEN 520 +# 485 Q=1:GOTO 500 +# 490 IF W(R,S+1)<>0 THEN 520 +# 500 X=INT(RND(1)*2+1) +# 510 ON X GOTO 790,910 +# 520 GOTO 790 +# 530 IF S-1=0 THEN 670 +# 540 IF W(R,S-1)<>0 THEN 670 +# 545 IF R=H THEN 610 +# 547 IF W(R+1,S)<>0 THEN 610 +# 550 IF S<>V THEN 560 +# 552 IF Z=1 THEN 590 +# 554 Q=1:GOTO 570 +# 560 IF W(R,S+1)<>0 THEN 590 +# 570 X=INT(RND(1)*3+1) +# 580 ON X GOTO 820,860,910 +# 590 X=INT(RND(1)*2+1) +# 600 ON X GOTO 820,860 +# 610 IF S<>V THEN 630 +# 620 IF Z=1 THEN 660 +# 625 Q=1:GOTO 640 +# 630 IF W(R,S+1)<>0 THEN 660 +# 640 X=INT(RND(1)*2+1) +# 650 ON X GOTO 820,910 +# 660 GOTO 820 +# 670 IF R=H THEN 740 +# 680 IF W(R+1,S)<>0 THEN 740 +# 685 IF S<>V THEN 700 +# 690 IF Z=1 THEN 730 +# 695 Q=1:GOTO 710 +# 700 IF W(R,S+1)<>0 THEN 730 +# 710 X=INT(RND(1)*2+1) +# 720 ON X GOTO 860,910 +# 730 GOTO 860 +# 740 IF S<>V THEN 760 +# 750 IF Z=1 THEN 780 +# 755 Q=1:GOTO 770 +# 760 IF W(R,S+1)<>0 THEN 780 +# 770 GOTO 910 +# 780 GOTO 1000 +# 790 W(R-1,S)=C +# 800 C=C+1:V(R-1,S)=2:R=R-1 +# 810 IF C=H*V+1 THEN 1010 +# 815 Q=0:GOTO 260 +# 820 W(R,S-1)=C +# 830 C=C+1 +# 840 V(R,S-1)=1:S=S-1:IF C=H*V+1 THEN 1010 +# 850 Q=0:GOTO 260 +# 860 W(R+1,S)=C +# 870 C=C+1:IF V(R,S)=0 THEN 880 +# 875 V(R,S)=3:GOTO 890 +# 880 V(R,S)=2 +# 890 R=R+1 +# 900 IF C=H*V+1 THEN 1010 +# 905 GOTO 530 +# 910 IF Q=1 THEN 960 +# 920 W(R,S+1)=C:C=C+1:IF V(R,S)=0 THEN 940 +# 930 V(R,S)=3:GOTO 950 +# 940 V(R,S)=1 +# 950 S=S+1:IF C=H*V+1 THEN 1010 +# 955 GOTO 260 +# 960 Z=1 +# 970 IF V(R,S)=0 THEN 980 +# 975 V(R,S)=3:Q=0:GOTO 1000 +# 980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250 +# 1000 GOTO 210 +# 1010 FOR J=1 TO V +# 1011 PRINT "I"; +# 1012 FOR I=1 TO H +# 1013 IF V(I,J)<2 THEN 1030 +# 1020 PRINT " "; +# 1021 GOTO 1040 +# 1030 PRINT " I"; +# 1040 NEXT I +# 1041 PRINT +# 1043 FOR I=1 TO H +# 1045 IF V(I,J)=0 THEN 1060 +# 1050 IF V(I,J)=2 THEN 1060 +# 1051 PRINT ": "; +# 1052 GOTO 1070 +# 1060 PRINT ":--"; +# 1070 NEXT I +# 1071 PRINT "." +# 1072 NEXT J +# 1073 END From c4b2260ae7c5faa3f20161eb84ade951a5a78b18 Mon Sep 17 00:00:00 2001 From: Marc Heiligers Date: Sat, 6 Mar 2021 11:42:35 -0700 Subject: [PATCH 2/4] Translate Python version for main algorithm --- 02 Amazing/ruby/amazing.rb | 374 +++++++++++++------------------------ 1 file changed, 130 insertions(+), 244 deletions(-) diff --git a/02 Amazing/ruby/amazing.rb b/02 Amazing/ruby/amazing.rb index 7e7db0ce..c14148b1 100644 --- a/02 Amazing/ruby/amazing.rb +++ b/02 Amazing/ruby/amazing.rb @@ -1,276 +1,162 @@ # frozen_string_literal: true -# BASIC arrays are 1-based, unlike Ruby 0-based arrays +# Set up a constant hash for directions +DIRECTIONS = { + left: 0, + up: 1, + right: 2, + down: 3 +}.freeze + +EXIT_DOWN = 1 +EXIT_RIGHT = 2 + +# BASIC arrays are 1-based, unlike Ruby 0-based arrays, +# and this class simulates that. BASIC arrays are also zero-filled, +# which is also done here. class BasicArrayTwoD - def initialize(width, height) - @val = Array.new(height) { Array.new(width, 0) } + def initialize(rows, cols) + @val = Array.new(rows) { Array.new(cols, 0) } end - def [](x, y) - @val[y - 1][x - 1] + def [](row, col = nil) + if col + @val[row - 1][col - 1] + else + @val[row - 1] + end end - def []=(x, y, n) - @val[y - 1][x - 1] = n + def []=(row, col, n) + @val[row - 1][col - 1] = n end def to_s - @val.map { |r| r.join(' ') }.join("\n") + @val.map { |row| row.join(' ') }.join("\n") end end -# 10 PRINT TAB(28);"AMAZING PROGRAM" -# 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -# 30 PRINT:PRINT:PRINT:PRINT -puts ' ' * 28 + 'AMAZING PROGRAM' -puts ' ' * 15 + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' -puts "\n" * 4 - -# 100 INPUT "WHAT ARE YOUR WIDTH AND LENGTH";H,V -# 102 IF H<>1 AND V<>1 THEN 110 -# 104 PRINT "MEANINGLESS DIMENSIONS. TRY AGAIN.":GOTO 100 -def ask_dimensions - print 'WHAT ARE YOUR WIDTH AND LENGTH? ' - h = gets.to_i - print '?? ' - v = gets.to_i - [h, v] -end - -h, v = ask_dimensions -while h < 1 || v < 1 - puts "MEANINGLESS DIMENSIONS. TRY AGAIN." - h, v = ask_dimensions -end - -# 110 DIM W(H,V),V(H,V) -# BASIC programs can have the same variable names for different types, -# so the v array is not the same as the v int. Here we're using suffixes. -w_arr = BasicArrayTwoD.new(h, v) -v_arr = BasicArrayTwoD.new(h, v) - -# 120 PRINT -# 130 PRINT -# 140 PRINT -# 150 PRINT -puts "\n" * 4 - -# 160 Q=0:Z=0:X=INT(RND(1)*H+1) -q = 0 -z = 0 - -def draw_top(x, h) - # 165 FOR I=1 TO H - # 170 IF I=X THEN 173 - # 171 PRINT ".--";:GOTO 180 - # 173 PRINT ". "; - # 180 NEXT I - (1..h).each do |i| - if i == x +def draw_top(entry, width) + (1..width).each do |i| + if i == entry print i == 1 ? '┏ ' : '┳ ' else print i == 1 ? '┏━━' : '┳━━' end end - # 190 PRINT "." puts '┓' - - x # return this because we need it end -# x represents the location of the opening -x = (rand * h).round + 1 -draw_top(x, h) +def draw_row(row) + print '┃' + row.each { |val| print val < 2 ? ' ┃' : ' ' } + puts + row.each { |val| print val == 0 || val == 2 ? '┣━━' : '┃ ' } + puts '┫' +end -# 195 C=1:W(X,1)=C:C=C+1 + +# 10 PRINT TAB(28);"AMAZING PROGRAM" +# 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +# 30 PRINT:PRINT:PRINT:PRINT +puts ' ' * 28 + 'AMAZING PROGRAM' +puts ' ' * 15 + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' +puts "\n" * 3 + +# 100 INPUT "WHAT ARE YOUR WIDTH AND LENGTH";H,V +# 102 IF H<>1 AND V<>1 THEN 110 +# 104 PRINT "MEANINGLESS DIMENSIONS. TRY AGAIN.":GOTO 100 +def ask_dimensions + print 'WHAT ARE YOUR WIDTH AND HEIGHT? ' + width = gets.to_i + print '?? ' + height = gets.to_i + [width, height] +end + +width, height = ask_dimensions +while width <= 1 || height <= 1 + puts "MEANINGLESS DIMENSIONS. TRY AGAIN." + width, height = ask_dimensions +end + +# 110 DIM W(H,V),V(H,V) +# BASIC programs can have the same variable names for different types, +# so the v array is not the same as the v int. Here we're renaming the arrays +# to have more friendly names +used = BasicArrayTwoD.new(height, width) +walls = BasicArrayTwoD.new(height, width) + +puts "\n" * 3 + + +# entry represents the location of the opening +entry = (rand * width).round + 1 + +# Set up our current row and column, starting at the top and the locations of the opening +row = 1 +col = entry c = 1 -w_arr[x, 1] = c # This marks the opening in the first row +used[row, col] = c # This marks the opening in the first row c += 1 -puts w_arr +while c != width * height + 1 do + # remove possible directions that are blocked or + # hit cells that we have already processed + possible_dirs = DIRECTIONS.keys + if col == 0 || used[row, col - 1] != 0 + possible_dirs.delete(:left) + end + if row == 0 || used[row - 1, col] != 0 + possible_dirs.delete(:up) + end + if col == width || used[row, col + 1] != 0 + possible_dirs.delete(:right) + end + if row == height || used[row + 1, col] != 0 + possible_dirs.delete(:down) + end -# 200 R=X:S=1:GOTO 260 -r = x -s = 1 -# 260 IF R-1=0 THEN 530 -if r - 1 == 0 - # 530 IF S-1=0 THEN 670 - if s - 1 == 0 - # 670 IF R=H THEN 740 - if r == h - # 740 IF S<>V THEN 760 - if s != v - # 760 IF W(R,S+1)<>0 THEN 780 - if w_arr[r, s + 1] != 0 - # 780 GOTO 1000 - # Well, we'll just go directly to 1000 - # 1000 GOTO 210 - # Well, now. I just got here, now back to 210 - # 210 IF R<>H THEN 240 - if r != h - # 240 R=R+1 - r += 1 - # 250 IF W(R,S)=0 THEN 210 - if w_arr[r, s] == 0 - # GOTO 210 -- this is a loop - end - # 260 IF R-1=0 THEN 530 - if r - 1 == 0 - # 530 IF S-1=0 THEN 670 - # 540 IF W(R,S-1)<>0 THEN 670 - if s - 1 == 0 || w_arr[r, s - 1] != 0 - # 670 IF R=H THEN 740 - # 680 IF W(R+1,S)<>0 THEN 740 - # 685 IF S<>V THEN 700 - # 690 IF Z=1 THEN 730 - # 695 Q=1:GOTO 710 - end - # 545 IF R=H THEN 610 - # 547 IF W(R+1,S)<>0 THEN 610 - if r == h || w_arr[r + 1, s] != 0 - # 610 IF S<>V THEN 630 - # 620 IF Z=1 THEN 660 - # 625 Q=1:GOTO 640 - end - # 550 IF S<>V THEN 560 - if s != v - # 560 IF W(R,S+1)<>0 THEN 590 - # 570 X=INT(RND(1)*3+1) - # 580 ON X GOTO 820,860,910 - end - # 552 IF Z=1 THEN 590 - if z == 1 - # 590 X=INT(RND(1)*2+1) - # 600 ON X GOTO 820,860 - end - # 554 Q=1:GOTO 570 - q = 1 - # 570 X=INT(RND(1)*3+1) - # 580 ON X GOTO 820,860,910 - end - end - end + # If we can move in a direction, move and make opening + if possible_dirs.size != 0 + direction = possible_dirs.sample # pick a random direction + if direction == :left + col = col - 1 + walls[row, col] = EXIT_RIGHT + elsif direction == :up + row = row - 1 + walls[row, col] = EXIT_DOWN + elsif direction == :right + walls[row, col] += EXIT_RIGHT + col = col + 1 + elsif direction == :down + walls[row, col] += EXIT_DOWN + row = row + 1 + end + used[row, col] = c + c = c + 1 + # otherwise, move to the next used cell, and try again + else + while true do + if col != width + col += 1 + elsif row != height + row += 1 + col = 1 + else + row = col = 1 end + break if used[row, col] != 0 end end end -# 210 IF R<>H THEN 240 -# 215 IF S<>V THEN 230 -# 220 R=1:S=1:GOTO 250 -# 230 R=1:S=S+1:GOTO 250 -# 240 R=R+1 -# 250 IF W(R,S)=0 THEN 210 -# 260 IF R-1=0 THEN 530 -# 265 IF W(R-1,S)<>0 THEN 530 -# 270 IF S-1=0 THEN 390 -# 280 IF W(R,S-1)<>0 THEN 390 -# 290 IF R=H THEN 330 -# 300 IF W(R+1,S)<>0 THEN 330 -# 310 X=INT(RND(1)*3+1) -# 320 ON X GOTO 790,820,860 -# 330 IF S<>V THEN 340 -# 334 IF Z=1 THEN 370 -# 338 Q=1:GOTO 350 -# 340 IF W(R,S+1)<>0 THEN 370 -# 350 X=INT(RND(1)*3+1) -# 360 ON X GOTO 790,820,910 -# 370 X=INT(RND(1)*2+1) -# 380 ON X GOTO 790,820 -# 390 IF R=H THEN 470 -# 400 IF W(R+1,S)<>0 THEN 470 -# 405 IF S<>V THEN 420 -# 410 IF Z=1 THEN 450 -# 415 Q=1:GOTO 430 -# 420 IF W(R,S+1)<>0 THEN 450 -# 430 X=INT(RND(1)*3+1) -# 440 ON X GOTO 790,860,910 -# 450 X=INT(RND(1)*2+1) -# 460 ON X GOTO 790,860 -# 470 IF S<>V THEN 490 -# 480 IF Z=1 THEN 520 -# 485 Q=1:GOTO 500 -# 490 IF W(R,S+1)<>0 THEN 520 -# 500 X=INT(RND(1)*2+1) -# 510 ON X GOTO 790,910 -# 520 GOTO 790 -# 530 IF S-1=0 THEN 670 -# 540 IF W(R,S-1)<>0 THEN 670 -# 545 IF R=H THEN 610 -# 547 IF W(R+1,S)<>0 THEN 610 -# 550 IF S<>V THEN 560 -# 552 IF Z=1 THEN 590 -# 554 Q=1:GOTO 570 -# 560 IF W(R,S+1)<>0 THEN 590 -# 570 X=INT(RND(1)*3+1) -# 580 ON X GOTO 820,860,910 -# 590 X=INT(RND(1)*2+1) -# 600 ON X GOTO 820,860 -# 610 IF S<>V THEN 630 -# 620 IF Z=1 THEN 660 -# 625 Q=1:GOTO 640 -# 630 IF W(R,S+1)<>0 THEN 660 -# 640 X=INT(RND(1)*2+1) -# 650 ON X GOTO 820,910 -# 660 GOTO 820 -# 670 IF R=H THEN 740 -# 680 IF W(R+1,S)<>0 THEN 740 -# 685 IF S<>V THEN 700 -# 690 IF Z=1 THEN 730 -# 695 Q=1:GOTO 710 -# 700 IF W(R,S+1)<>0 THEN 730 -# 710 X=INT(RND(1)*2+1) -# 720 ON X GOTO 860,910 -# 730 GOTO 860 -# 740 IF S<>V THEN 760 -# 750 IF Z=1 THEN 780 -# 755 Q=1:GOTO 770 -# 760 IF W(R,S+1)<>0 THEN 780 -# 770 GOTO 910 -# 780 GOTO 1000 -# 790 W(R-1,S)=C -# 800 C=C+1:V(R-1,S)=2:R=R-1 -# 810 IF C=H*V+1 THEN 1010 -# 815 Q=0:GOTO 260 -# 820 W(R,S-1)=C -# 830 C=C+1 -# 840 V(R,S-1)=1:S=S-1:IF C=H*V+1 THEN 1010 -# 850 Q=0:GOTO 260 -# 860 W(R+1,S)=C -# 870 C=C+1:IF V(R,S)=0 THEN 880 -# 875 V(R,S)=3:GOTO 890 -# 880 V(R,S)=2 -# 890 R=R+1 -# 900 IF C=H*V+1 THEN 1010 -# 905 GOTO 530 -# 910 IF Q=1 THEN 960 -# 920 W(R,S+1)=C:C=C+1:IF V(R,S)=0 THEN 940 -# 930 V(R,S)=3:GOTO 950 -# 940 V(R,S)=1 -# 950 S=S+1:IF C=H*V+1 THEN 1010 -# 955 GOTO 260 -# 960 Z=1 -# 970 IF V(R,S)=0 THEN 980 -# 975 V(R,S)=3:Q=0:GOTO 1000 -# 980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250 -# 1000 GOTO 210 -# 1010 FOR J=1 TO V -# 1011 PRINT "I"; -# 1012 FOR I=1 TO H -# 1013 IF V(I,J)<2 THEN 1030 -# 1020 PRINT " "; -# 1021 GOTO 1040 -# 1030 PRINT " I"; -# 1040 NEXT I -# 1041 PRINT -# 1043 FOR I=1 TO H -# 1045 IF V(I,J)=0 THEN 1060 -# 1050 IF V(I,J)=2 THEN 1060 -# 1051 PRINT ": "; -# 1052 GOTO 1070 -# 1060 PRINT ":--"; -# 1070 NEXT I -# 1071 PRINT "." -# 1072 NEXT J -# 1073 END +# Add a random exit +walls[height, (rand * width).round + 1] += 1 + +# Print the maze +draw_top(entry, width) +(1..height).each do |row| + draw_row(walls[row]) +end From e6f7975a6de13c4f68d68b5921cdb0f7190c9cd6 Mon Sep 17 00:00:00 2001 From: Marc Heiligers Date: Sat, 6 Mar 2021 15:40:56 -0700 Subject: [PATCH 3/4] Refactor --- 02 Amazing/ruby/amazing.rb | 298 ++++++++++++++++++++++--------------- 1 file changed, 176 insertions(+), 122 deletions(-) diff --git a/02 Amazing/ruby/amazing.rb b/02 Amazing/ruby/amazing.rb index c14148b1..d9a4f9d0 100644 --- a/02 Amazing/ruby/amazing.rb +++ b/02 Amazing/ruby/amazing.rb @@ -1,19 +1,15 @@ # frozen_string_literal: true -# Set up a constant hash for directions -DIRECTIONS = { - left: 0, - up: 1, - right: 2, - down: 3 -}.freeze +DEBUG = !ENV['DEBUG'].nil? -EXIT_DOWN = 1 -EXIT_RIGHT = 2 +require 'io/console' if DEBUG # BASIC arrays are 1-based, unlike Ruby 0-based arrays, -# and this class simulates that. BASIC arrays are also zero-filled, -# which is also done here. +# and this class simulates that. BASIC arrays are zero-filled, +# which is also done here. While we could easily update the +# algorithm to work with zero-based arrays, this class makes +# the problem easier to reason about, row or col 1 are the +# first row or column. class BasicArrayTwoD def initialize(rows, cols) @val = Array.new(rows) { Array.new(cols, 0) } @@ -31,132 +27,190 @@ class BasicArrayTwoD @val[row - 1][col - 1] = n end - def to_s - @val.map { |row| row.join(' ') }.join("\n") + def to_s(width: max_width, row_hilite: nil, col_hilite: nil) + @val.map.with_index do |row, row_index| + row.map.with_index do |val, col_index| + if row_hilite == row_index + 1 && col_hilite == col_index + 1 + "[#{val.to_s.center(width)}]" + else + val.to_s.center(width + 2) + end + end.join + end.join("\n") + end + + def max_width + @val.flat_map { |row| row.map { |val| val.to_s.length } }.sort.last end end -def draw_top(entry, width) - (1..width).each do |i| - if i == entry - print i == 1 ? '┏ ' : '┳ ' - else - print i == 1 ? '┏━━' : '┳━━' +class Maze + EXIT_DOWN = 1 + EXIT_RIGHT = 2 + + # Set up a constant hash for directions + # The values represent the direction of the move as changes to row, col + # and the type of exit when moving in that direction + DIRECTIONS = { + left: { row: 0, col: -1, exit: EXIT_RIGHT }, + up: { row: -1, col: 0, exit: EXIT_DOWN }, + right: { row: 0, col: 1, exit: EXIT_RIGHT }, + down: { row: 1, col: 0, exit: EXIT_DOWN } + }.freeze + + attr_reader :width, :height, :used, :walls, :entry + + def initialize(width, height) + @width = width + @height = height + + @used = BasicArrayTwoD.new(height, width) + @walls = BasicArrayTwoD.new(height, width) + + create + end + + def draw + # Print the maze + draw_top(entry, width) + (1..height - 1).each do |row| + draw_row(walls[row]) end + draw_bottom(walls[height]) end - puts '┓' -end + private -def draw_row(row) - print '┃' - row.each { |val| print val < 2 ? ' ┃' : ' ' } - puts - row.each { |val| print val == 0 || val == 2 ? '┣━━' : '┃ ' } - puts '┫' -end + def create + # entry represents the location of the opening + @entry = (rand * width).round + 1 + # Set up our current row and column, starting at the top and the locations of the opening + row = 1 + col = entry + c = 1 + used[row, col] = c # This marks the opening in the first row + c += 1 -# 10 PRINT TAB(28);"AMAZING PROGRAM" -# 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -# 30 PRINT:PRINT:PRINT:PRINT -puts ' ' * 28 + 'AMAZING PROGRAM' -puts ' ' * 15 + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' -puts "\n" * 3 + while c != width * height + 1 do + debug walls, row, col + # remove possible directions that are blocked or + # hit cells that we have already processed + possible_dirs = DIRECTIONS.reject do |dir, change| + nrow = row + change[:row] + ncol = col + change[:col] + nrow < 1 || nrow > height || ncol < 1 || ncol > width || used[nrow, ncol] != 0 + end.keys -# 100 INPUT "WHAT ARE YOUR WIDTH AND LENGTH";H,V -# 102 IF H<>1 AND V<>1 THEN 110 -# 104 PRINT "MEANINGLESS DIMENSIONS. TRY AGAIN.":GOTO 100 -def ask_dimensions - print 'WHAT ARE YOUR WIDTH AND HEIGHT? ' - width = gets.to_i - print '?? ' - height = gets.to_i - [width, height] -end - -width, height = ask_dimensions -while width <= 1 || height <= 1 - puts "MEANINGLESS DIMENSIONS. TRY AGAIN." - width, height = ask_dimensions -end - -# 110 DIM W(H,V),V(H,V) -# BASIC programs can have the same variable names for different types, -# so the v array is not the same as the v int. Here we're renaming the arrays -# to have more friendly names -used = BasicArrayTwoD.new(height, width) -walls = BasicArrayTwoD.new(height, width) - -puts "\n" * 3 - - -# entry represents the location of the opening -entry = (rand * width).round + 1 - -# Set up our current row and column, starting at the top and the locations of the opening -row = 1 -col = entry -c = 1 -used[row, col] = c # This marks the opening in the first row -c += 1 - -while c != width * height + 1 do - # remove possible directions that are blocked or - # hit cells that we have already processed - possible_dirs = DIRECTIONS.keys - if col == 0 || used[row, col - 1] != 0 - possible_dirs.delete(:left) - end - if row == 0 || used[row - 1, col] != 0 - possible_dirs.delete(:up) - end - if col == width || used[row, col + 1] != 0 - possible_dirs.delete(:right) - end - if row == height || used[row + 1, col] != 0 - possible_dirs.delete(:down) - end - - # If we can move in a direction, move and make opening - if possible_dirs.size != 0 - direction = possible_dirs.sample # pick a random direction - if direction == :left - col = col - 1 - walls[row, col] = EXIT_RIGHT - elsif direction == :up - row = row - 1 - walls[row, col] = EXIT_DOWN - elsif direction == :right - walls[row, col] += EXIT_RIGHT - col = col + 1 - elsif direction == :down - walls[row, col] += EXIT_DOWN - row = row + 1 - end - used[row, col] = c - c = c + 1 - # otherwise, move to the next used cell, and try again - else - while true do - if col != width - col += 1 - elsif row != height - row += 1 - col = 1 + # If we can move in a direction, move and make opening + if possible_dirs.size != 0 + direction = possible_dirs.sample + change = DIRECTIONS[direction] # pick a random direction + if %i[left up].include?(direction) + row += change[:row] + col += change[:col] + walls[row, col] = change[:exit] + else + walls[row, col] += change[:exit] + row += change[:row] + col += change[:col] + end + used[row, col] = c + c = c + 1 + # otherwise, move to the next used cell, and try again else - row = col = 1 + loop do + if col != width + col += 1 + elsif row != height + row += 1 + col = 1 + else + row = col = 1 + end + break if used[row, col] != 0 + debug walls, row, col + end end - break if used[row, col] != 0 end + + # Add a random exit + walls[height, (rand * width).round] += 1 + end + + def draw_top(entry, width) + (1..width).each do |i| + if i == entry + print i == 1 ? '┏ ' : '┳ ' + else + print i == 1 ? '┏━━' : '┳━━' + end + end + + puts '┓' + end + + def draw_row(row) + print '┃' + row.each.with_index do |val, col| + print val < 2 ? ' ┃' : ' ' + end + puts + row.each.with_index do |val, col| + print val == 0 || val == 2 ? (col == 0 ? '┣━━' : '╋━━') : (col == 0 ? '┃ ' : '┫ ') + end + puts '┫' + end + + def draw_bottom(row) + print '┃' + row.each.with_index do |val, col| + print val < 2 ? ' ┃' : ' ' + end + puts + row.each.with_index do |val, col| + print val == 0 || val == 2 ? (col == 0 ? '┗━━' : '┻━━') : (col == 0 ? '┗ ' : '┻ ') + end + puts '┛' + end + + def debug(walls, row, col) + return unless DEBUG + + STDOUT.clear_screen + puts walls.to_s(row_hilite: row, col_hilite: col) + sleep 0.1 end end -# Add a random exit -walls[height, (rand * width).round + 1] += 1 +class Amazing + def run + draw_header -# Print the maze -draw_top(entry, width) -(1..height).each do |row| - draw_row(walls[row]) + width, height = ask_dimensions + while width <= 1 || height <= 1 + puts "MEANINGLESS DIMENSIONS. TRY AGAIN." + width, height = ask_dimensions + end + + maze = Maze.new(width, height) + puts "\n" * 3 + maze.draw + end + + def draw_header + puts ' ' * 28 + 'AMAZING PROGRAM' + puts ' ' * 15 + 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' + puts "\n" * 3 + end + + def ask_dimensions + print 'WHAT ARE YOUR WIDTH AND HEIGHT? ' + width = gets.to_i + print '?? ' + height = gets.to_i + [width, height] + end end + +Amazing.new.run \ No newline at end of file From 1e56217a86131bdb03e28a29a577f370653b4d9a Mon Sep 17 00:00:00 2001 From: Marc Heiligers Date: Sat, 6 Mar 2021 15:46:40 -0700 Subject: [PATCH 4/4] Add some notes to README --- 02 Amazing/ruby/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/02 Amazing/ruby/README.md b/02 Amazing/ruby/README.md index fb32811e..8bf7896b 100644 --- a/02 Amazing/ruby/README.md +++ b/02 Amazing/ruby/README.md @@ -1,3 +1,9 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Ruby](https://www.ruby-lang.org/en/) + +Converted to Ruby (with tons of inspiration from the Python version) by @marcheiligers + +Run `ruby amazing.rb`. + +Run `DEBUG=1 ruby amazing.ruby` to see how it works (requires at least Ruby 2.7).