diff --git a/doudizhu/.gitignore b/doudizhu/.gitignore new file mode 100644 index 000000000..f68d10996 --- /dev/null +++ b/doudizhu/.gitignore @@ -0,0 +1,29 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/doudizhu/src/Main.java b/doudizhu/src/Main.java new file mode 100644 index 000000000..4b1cfeefc --- /dev/null +++ b/doudizhu/src/Main.java @@ -0,0 +1,286 @@ + +import java.awt.Color; +import java.awt.Container; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class Main extends JFrame implements ActionListener,Runnable{ + + public Container container = null;// 定义容器 + JMenuItem start, exit, about;// 定义菜单按钮 + JButton landlord[]=new JButton[2];//抢地主按钮 + JButton publishCard[]=new JButton[2];//出牌按钮 + int dizhuFlag;//地主标志 + int turn; + JLabel dizhu; //地主图标 + List currentList[] =new ArrayList[3]; // 当前的出牌 + List playerList[] = new ArrayList[3]; // 定义3个玩家表 + List lordList;//地主牌 + Card card[] = new Card[56]; // 定义54张牌 + JTextField time[]=new JTextField[3]; //计时器 + Time t; //定时器(线程) + boolean nextPlayer=false; //转换角色 + public Main(){ + + Init();// 初始化 + SetMenu();// 创建菜单 按钮(抢地主,发牌,计时器) + this.setVisible(true); + CardInit();//发牌 + getLord(); //发完牌开始抢地主 + time[1].setVisible(true); + //线程安全性,把非主线程的UI控制放到里面 + t=new Time(this,10);//从10开始倒计时 + t.start(); + + } + // 抢地主 + public void getLord(){ + //System.out.println(CardType.c0.toString()); + for(int i=0;i<2;i++) + landlord[i].setVisible(true); + } + //初始化牌 + // 发牌洗牌 + public void CardInit() { + + int count = 1; + //初始化牌 + for (int i = 1; i <= 5; i++) { + for (int j = 1; j <= 13; j++) { + if ((i == 5) && (j > 2)) + break; + else { + card[count] = new Card(this, i + "-" + j, false); + card[count].setLocation(350, 50); + container.add(card[count]); + count++; + } + } + } + //打乱顺序 + for(int i=0;i<100;i++){ + Random random=new Random(); + int a=random.nextInt(54)+1; + int b=random.nextInt(54)+1; + Card k=card[a]; + card[a]=card[b]; + card[b]=k; + } + //开始发牌 + for(int i=0;i<3;i++) + playerList[i]=new ArrayList(); //玩家牌 + lordList=new ArrayList();//地主牌三张 + int t=0; + for(int i=1;i<=54;i++) + { + if(i>=52)//地主牌 + { + Common.move(card[i], card[i].getLocation(),new Point(300+(i-52)*80,10)); + lordList.add(card[i]); + continue; + } + switch ((t++)%3) { + case 0: + //左边玩家 + Common.move(card[i], card[i].getLocation(),new Point(50,60+i*5)); + playerList[0].add(card[i]); + break; + case 1: + //我 + Common.move(card[i], card[i].getLocation(),new Point(180+i*7,450)); + playerList[1].add(card[i]); + card[i].turnFront(); //显示正面 + break; + case 2: + //右边玩家 + Common.move(card[i], card[i].getLocation(),new Point(700,60+i*5)); + playerList[2].add(card[i]); + break; + } + //card[i].turnFront(); //显示正面 + container.setComponentZOrder(card[i], 0); + } + //发完牌排序,从大到小 + for(int i=0;i<3;i++) + { + Common.order(playerList[i]); + Common.rePosition(this,playerList[i],i);//重新定位 + } + dizhu=new JLabel(new ImageIcon("images/dizhu.gif")); + dizhu.setVisible(false); + dizhu.setSize(40, 40); + container.add(dizhu); + } + + // 初始化窗体 + public void Init() { + + this.setTitle("斗地主游戏---帮写代码网"); + this.setSize(830, 620); + setResizable(false); + setLocationRelativeTo(getOwner()); // 屏幕居中 + container = this.getContentPane(); + container.setLayout(null); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + container.setBackground(new Color(0, 112, 26)); // 背景为绿色 + + } + + // 创建菜单 功能按钮 + public void SetMenu() { + JMenuBar jMenuBar = new JMenuBar(); + JMenu game = new JMenu("游戏"); + JMenu help = new JMenu("帮助"); + + start = new JMenuItem("新游戏"); + exit = new JMenuItem("退出"); + about = new JMenuItem("关于"); + + start.addActionListener(this); + exit.addActionListener(this); + about.addActionListener(this); + + game.add(start); + game.add(exit); + help.add(about); + + jMenuBar.add(game); + jMenuBar.add(help); + this.setJMenuBar(jMenuBar); + + landlord[0]=new JButton("抢地主"); + landlord[1]=new JButton("不 抢"); + publishCard[0]= new JButton("出牌"); + publishCard[1]= new JButton("不要"); + for(int i=0;i<2;i++) + { + publishCard[i].setBounds(320+i*100, 400, 60, 20); + landlord[i].setBounds(320+i*100, 400,75,20); + container.add(landlord[i]); + landlord[i].addActionListener(this); + landlord[i].setVisible(false); + container.add(publishCard[i]); + publishCard[i].setVisible(false); + publishCard[i].addActionListener(this); + } + for(int i=0;i<3;i++){ + time[i]=new JTextField("倒计时:"); + time[i].setVisible(false); + container.add(time[i]); + } + time[0].setBounds(140, 230, 60, 20); + time[1].setBounds(374, 360, 60, 20); + time[2].setBounds(620, 230, 60, 20); + + for(int i=0;i<3;i++) + { + currentList[i]=new ArrayList(); + } + + } + + @Override + public void actionPerformed(ActionEvent e) { + // TODO Auto-generated method stub + if (e.getSource() == exit) { + this.dispose(); + } + if (e.getSource() == about) { + JOptionPane.showMessageDialog(this, "帮写代码网!!"); + } + if (e.getSource() == start) { + // this.restart(); + } + if(e.getSource()==landlord[0]) + { + time[1].setText("抢地主"); + t.isRun=false; //时钟终结 + } + if(e.getSource()==landlord[1]) + { + time[1].setText("不抢"); + t.isRun=false; //时钟终结 + } + //如果是不要 + if(e.getSource()==publishCard[1]) + { + this.nextPlayer=true; + currentList[1].clear(); + time[1].setText("不要") ; + } + //如果是出牌按钮 + if(e.getSource()==publishCard[0]) + { + List c=new ArrayList(); + //点选出牌 + for(int i=0;i pokerList = new ArrayList<>(); + static{ + String [] color = {"♠","♥","♣","♦" }; + String [] number = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; + ArrayList pokerList = new ArrayList<>(); + for (String c : color) { + for (String n : number) { + pokerList.add(c+n); + } + } + pokerList.add("大王"); + pokerList.add("小王"); + } + public paper(){ + System.out.println("新牌已经发好了"); + Collections.shuffle(pokerList) ; + ArrayList lord = new ArrayList<>(); + ArrayList player1 = new ArrayList<>(); + ArrayList player2 = new ArrayList<>(); + ArrayList player3= new ArrayList<>(); + for (int i = 0; i < pokerList.size(); i++) { + String p = pokerList.get(i); + if (i>=51){ + lord.add(p); + } + else if (i%3==0){ + player1.add(p); + } + else if (i%3==1){ + player2.add(p); + } + else if (i%3==2){ + player3.add(p); + } + } + + } + public void lookPaper(String name , ArrayList player){ + System.out.print(name + "的牌是:"); + for (String p : player) { + System.out.print(p + " "); + } + System.out.println(); + } + public static void sortPaper(ArrayList player){ + + } +} diff --git a/lab2/Arithmetic/Arithmetic.java b/lab2/Arithmetic/Arithmetic.java index 5edc3bb8b..7c779eb99 100644 --- a/lab2/Arithmetic/Arithmetic.java +++ b/lab2/Arithmetic/Arithmetic.java @@ -20,6 +20,6 @@ public static int product(int a, int b) { * @return Sum of a and b * */ public static int sum(int a, int b) { - return a * b; + return a + b; } } diff --git a/lab2/IntList/IntList.java b/lab2/IntList/IntList.java index 65949a325..02292a161 100644 --- a/lab2/IntList/IntList.java +++ b/lab2/IntList/IntList.java @@ -60,8 +60,8 @@ public String toString() { public static IntList of(int ...argList) { if (argList.length == 0) return null; - int[] restList = new int[argList.length - 1]; - System.arraycopy(argList, 1, restList, 0, argList.length - 1); + int[] restList = new int[argList.length - 1 ]; + System.arraycopy(argList, 1, restList, 0, argList.length - 1 ); return new IntList(argList[0], IntList.of(restList)); } } diff --git a/lab2/IntList/IntListExercises.java b/lab2/IntList/IntListExercises.java index f7f995e6a..a57bdc5fb 100644 --- a/lab2/IntList/IntListExercises.java +++ b/lab2/IntList/IntListExercises.java @@ -10,10 +10,10 @@ public class IntListExercises { */ public static void addConstant(IntList lst, int c) { IntList head = lst; - while (head.rest != null) { + do { head.first += c; head = head.rest; - } + } while (head != null); } /** @@ -51,7 +51,7 @@ public static int max(IntList L) { */ public static boolean firstDigitEqualsLastDigit(int x) { int lastDigit = x % 10; - while (x > 10) { + while (x >= 10) { x = x / 10; } int firstDigit = x % 10; @@ -75,8 +75,12 @@ public static boolean squarePrimes(IntList lst) { if (currElemIsPrime) { lst.first *= lst.first; + return currElemIsPrime || squarePrimes(lst.rest); + } + else{ + return squarePrimes(lst.rest); } - return currElemIsPrime || squarePrimes(lst.rest); + } } diff --git a/lab2/IntList/Primes.java b/lab2/IntList/Primes.java index 7e54ce48d..cd8cb5da3 100644 --- a/lab2/IntList/Primes.java +++ b/lab2/IntList/Primes.java @@ -73,7 +73,7 @@ public static void main(String[] args) { int primeCount = 0; int x = 2; - while (primeCount < 20) { + while (primeCount < 30) { if (isPrime(x)) { System.out.println(x); primeCount++; diff --git a/lab2/IntList/SquarePrimesTest.java b/lab2/IntList/SquarePrimesTest.java index 9182a29f7..bc0fa9365 100644 --- a/lab2/IntList/SquarePrimesTest.java +++ b/lab2/IntList/SquarePrimesTest.java @@ -17,4 +17,5 @@ public void testSquarePrimesSimple() { assertEquals("14 -> 15 -> 16 -> 289 -> 18", lst.toString()); assertTrue(changed); } + } diff --git a/lab2/pom.xml b/lab2/pom.xml index 840c5a509..fcfd3b54a 100644 --- a/lab2/pom.xml +++ b/lab2/pom.xml @@ -14,6 +14,14 @@ CS61B lab2 1.0-SNAPSHOT + + + junit + junit + RELEASE + compile + + ${project.basedir} diff --git a/lab2setup/pom.xml b/lab2setup/pom.xml index 658ca0072..d66735e53 100644 --- a/lab2setup/pom.xml +++ b/lab2setup/pom.xml @@ -14,6 +14,14 @@ CS61B lab2setup 1.0-SNAPSHOT + + + junit + junit + 4.13.2 + compile + + ${project.basedir} diff --git a/lab3/randomizedtest/BuggyAList.java b/lab3/randomizedtest/BuggyAList.java index b2b70c2b8..4acd92ec9 100644 --- a/lab3/randomizedtest/BuggyAList.java +++ b/lab3/randomizedtest/BuggyAList.java @@ -1,30 +1,30 @@ package randomizedtest; -/** Array based list. - * @author Josh Hug +/** 基于数组的列表类。 + * 作者:Josh Hug */ // 0 1 2 3 4 5 6 7 // items: [6 9 -1 2 0 0 0 0 ...] // size: 5 -/* Invariants: - addLast: The next item we want to add, will go into position size - getLast: The item we want to return is in position size - 1 - size: The number of items in the list should be size. +/* 不变量: + addLast: 我们想要添加的下一个项目将进入位置 size + getLast: 我们想要返回的项目在位置 size - 1 + size: 列表中的项目数量应该是 size。 */ public class BuggyAList { private Item[] items; private int size; - /** Creates an empty list. */ + /** 创建一个空列表。 */ public BuggyAList() { - items = (Item[]) new Object[1]; + items = (Item[]) new Object[8]; // 初始容量为 8 size = 0; } - /** Resizes the underlying array to the target capacity. */ + /** 将底层数组的大小调整为目标容量。 */ private void resize(int capacity) { Item[] a = (Item[]) new Object[capacity]; for (int i = 0; i < size; i += 1) { @@ -33,38 +33,38 @@ private void resize(int capacity) { items = a; } - /** Inserts X into the back of the list. */ + /** 将 X 插入到列表的末尾。 */ public void addLast(Item x) { if (size == items.length) { - resize(size * 2); + resize(size * 2); // 如果数组已满,则将其大小加倍 } items[size] = x; size = size + 1; } - /** Returns the item from the back of the list. */ + /** 返回列表末尾的项目。 */ public Item getLast() { return items[size - 1]; } - /** Gets the ith item in the list (0 is the front). */ + + /** 获取列表中的第 i 个项目(0 是前面)。 */ public Item get(int i) { return items[i]; } - /** Returns the number of items in the list. */ + /** 返回列表中的项目数量。 */ public int size() { return size; } - /** Deletes item from back of the list and - * returns deleted item. */ + /** 删除列表末尾的项目并返回删除的项目。 */ public Item removeLast() { - if ((size < items.length / 4) && (size > 4)) { - resize(size / 4); - } Item x = getLast(); items[size - 1] = null; size = size - 1; + if ((size > 0) && (size == items.length / 4)) { + resize(items.length / 2); // 如果大小是数组长度的四分之一,则将其大小减半 + } return x; } -} +} \ No newline at end of file diff --git a/lab3/randomizedtest/RandomizedTest.java b/lab3/randomizedtest/RandomizedTest.java new file mode 100644 index 000000000..37938843b --- /dev/null +++ b/lab3/randomizedtest/RandomizedTest.java @@ -0,0 +1,41 @@ +package randomizedtest; + +import org.junit.Test; +import static org.junit.Assert.*; +import edu.princeton.cs.algs4.StdRandom; + +public class RandomizedTest { + + @Test + public void randomizedTest() { + AListNoResizing L = new AListNoResizing<>(); + + int N = 500; + for (int i = 0; i < N; i += 1) { + int operationNumber = StdRandom.uniform(0, 4); + if (operationNumber == 0) { + // addLast + int randVal = StdRandom.uniform(0, 100); + L.addLast(randVal); + System.out.println("addLast(" + randVal + ")"); + } else if (operationNumber == 1) { + // size + int size = L.size(); + System.out.println("size: " + size); + }else if (operationNumber == 2) { + // getLast + if (L.size() == 0) { + System.out.println("List is empty"); + } else { + int last = L.getLast(); + System.out.println("getLast: " + last); + } + } else if(operationNumber == 3) { + // removeLast + if (L.size() == 0) { + System.out.println("List is empty"); + } + } + } + } +} \ No newline at end of file diff --git a/lab3/randomizedtest/TestBuggyAList.java b/lab3/randomizedtest/TestBuggyAList.java index 8afd045db..c56e58945 100644 --- a/lab3/randomizedtest/TestBuggyAList.java +++ b/lab3/randomizedtest/TestBuggyAList.java @@ -9,4 +9,5 @@ */ public class TestBuggyAList { // YOUR TESTS HERE + } diff --git a/lab3/randomizedtest/testThreeAddThereRemove.java b/lab3/randomizedtest/testThreeAddThereRemove.java new file mode 100644 index 000000000..56c565f26 --- /dev/null +++ b/lab3/randomizedtest/testThreeAddThereRemove.java @@ -0,0 +1,22 @@ +package randomizedtest; + +import timingtest.SLList; + +public class testThreeAddThereRemove { + public static void main(String[] args) { + BuggyAList b = new BuggyAList<>(); + AListNoResizing a = new AListNoResizing<>(); + SLList s = new SLList<>(); + for (int i = 0; i < 1000; i += 1) { + a.addLast(i); + s.addLast(i); + b.addLast(i); + } + for (int i = 1; i < 1000; i *= 2) { + System.out.println(a.get(i)); + System.out.println(b.get(i)); + System.out.println(s.get(i)); + } + } + +} diff --git a/lab3/timingtest/AList.java b/lab3/timingtest/AList.java index 866478d9f..b7f82c3cd 100644 --- a/lab3/timingtest/AList.java +++ b/lab3/timingtest/AList.java @@ -34,7 +34,7 @@ private void resize(int capacity) { /** Inserts X into the back of the list. */ public void addLast(Item x) { if (size == items.length) { - resize(size + 1); + resize(size * 2); } items[size] = x; diff --git a/lab3/timingtest/SLList.java b/lab3/timingtest/SLList.java index b79188678..3e9357320 100644 --- a/lab3/timingtest/SLList.java +++ b/lab3/timingtest/SLList.java @@ -12,7 +12,16 @@ public IntNode(Item i, IntNode n) { next = n; } } - + public int get(Item x){ + IntNode p = sentinel; + while(p.next != null){ + if(p.item == x){ + return (int) p.item; + } + p = p.next; + } + return 0; + } /* The first item (if it exists) is at sentinel.next. */ private IntNode sentinel; private int size; diff --git a/lab3/timingtest/TimeAList.java b/lab3/timingtest/TimeAList.java index 907028317..cdcd2bb5a 100644 --- a/lab3/timingtest/TimeAList.java +++ b/lab3/timingtest/TimeAList.java @@ -23,5 +23,24 @@ public static void main(String[] args) { public static void timeAListConstruction() { // TODO: YOUR CODE HERE + AList Ns = new AList<>(); + AList times = new AList<>(); + AList opCounts = new AList<>(); + int [] testSizes = new int[]{100000, 200000, 400000, 800000, 1600000, 3200000, 6400000, 12800000}; + for (int N : testSizes){ + AList testList = new AList<>(); + Stopwatch sw = new Stopwatch(); + for (int i = 0; i < N; i++){ + testList.addLast(1); + } + double timeInSeconds = sw.elapsedTime(); + Ns.addLast(N); + times.addLast(timeInSeconds); + opCounts.addLast(N); + } + printTimingTable(Ns, times, opCounts); + + + } } diff --git a/lab3/timingtest/TimeSLList.java b/lab3/timingtest/TimeSLList.java index 025e0fcd7..34ec85886 100644 --- a/lab3/timingtest/TimeSLList.java +++ b/lab3/timingtest/TimeSLList.java @@ -22,7 +22,28 @@ public static void main(String[] args) { } public static void timeGetLast() { - // TODO: YOUR CODE HERE + AList Ns = new AList<>(); + AList times = new AList<>(); + AList opCounts = new AList<>(); + int [] testSizes = new int[]{1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000}; + int m = 10000; + for (int N : testSizes){ + SLList testList = new SLList<>();; + for (int i = 0; i < N; i++){ + testList.addLast(1); + } + Stopwatch sw = new Stopwatch(); + for (int i = 0; i < m; i++){ + testList.getLast(); + } + double timeInSeconds = sw.elapsedTime(); + Ns.addLast(N); + times.addLast(timeInSeconds); + opCounts.addLast(m); + } + printTimingTable(Ns, times, opCounts); + + } } diff --git a/lab6/capers/CapersRepository.java b/lab6/capers/CapersRepository.java index ff29ba3e1..70115e272 100644 --- a/lab6/capers/CapersRepository.java +++ b/lab6/capers/CapersRepository.java @@ -3,62 +3,79 @@ import java.io.File; import static capers.Utils.*; -/** A repository for Capers - * @author TODO - * The structure of a Capers Repository is as follows: +/** Capers 仓库类 + * 该类用于管理 Capers 仓库的持久化数据。 + * 仓库的结构如下: * - * .capers/ -- top level folder for all persistent data in your lab12 folder - * - dogs/ -- folder containing all of the persistent data for dogs - * - story -- file containing the current story + * .capers/ -- 顶级文件夹,包含所有持久化数据 + * - dogs/ -- 包含所有狗的持久化数据的文件夹 + * - story -- 包含当前故事的文件 * - * TODO: change the above structure if you do something different. + * TODO: 如果你做了不同的事情,请更改上述结构。 */ public class CapersRepository { - /** Current Working Directory. */ + /** 当前工作目录。 */ static final File CWD = new File(System.getProperty("user.dir")); - - /** Main metadata folder. */ - static final File CAPERS_FOLDER = null; // TODO Hint: look at the `join` - // function in Utils + /** 主元数据文件夹。 */ + static final File CAPERS_FOLDER = join(CWD, "capers"); // TODO 提示:查看 Utils 中的 `join` 函数 /** - * Does required filesystem operations to allow for persistence. - * (creates any necessary folders or files) - * Remember: recommended structure (you do not have to follow): + * 执行所需的文件系统操作以允许持久化。 + * (创建任何必要的文件夹或文件) + * 记住:推荐的结构(你不必遵循): * - * .capers/ -- top level folder for all persistent data in your lab12 folder - * - dogs/ -- folder containing all of the persistent data for dogs - * - story -- file containing the current story + * .capers/ -- 顶级文件夹,包含所有持久化数据 + * - dogs/ -- 包含所有狗的持久化数据的文件夹 + * - story -- 包含当前故事的文件 */ public static void setupPersistence() { // TODO + CAPERS_FOLDER.mkdir(); // 创建 .capers 文件夹 + File dogsFolder = Utils.join(CAPERS_FOLDER, "dogs"); // 创建 dogs 文件夹 + dogsFolder.mkdir(); + File storyFile = join(CAPERS_FOLDER, "story"); // 创建 story 文件 + if (!storyFile.exists()) { + writeContents(storyFile, ""); // 如果 story 文件不存在,则创建一个空文件 + } } /** - * Appends the first non-command argument in args - * to a file called `story` in the .capers directory. - * @param text String of the text to be appended to the story + * 将第一个非命令参数追加到 .capers 目录中的 `story` 文件中。 + * @param text 要追加到故事中的文本字符串 */ public static void writeStory(String text) { // TODO + File storyFile = join(CAPERS_FOLDER, "story"); // 获取 story 文件的路径 + String currentStory = readContentsAsString(storyFile); // 读取当前故事内容 + currentStory += text + "\n"; // 将新文本追加到当前故事内容中 + writeContents(storyFile, currentStory); // 将更新后的故事内容写回文件 + System.out.println(currentStory); // 打印当前故事内容 } /** - * Creates and persistently saves a dog using the first - * three non-command arguments of args (name, breed, age). - * Also prints out the dog's information using toString(). + * 使用第一个三个非命令参数(名字、种、年龄)创建并持久化保存一只狗。 + * 还使用 toString() 打印狗的信。 + * @param name 狗的名字 + * @param breed 狗的品种 + * @param age 狗的年龄 */ public static void makeDog(String name, String breed, int age) { // TODO + Dog newDog = new Dog(name, breed, age); // 创建新的狗对象 + newDog.saveDog(); // 持久化保存狗对象 + System.out.println(newDog.toString()); // 打印狗的信息 } /** - * Advances a dog's age persistently and prints out a celebratory message. - * Also prints out the dog's information using toString(). - * Chooses dog to advance based on the first non-command argument of args. - * @param name String name of the Dog whose birthday we're celebrating. + * 持久化地增加狗的年龄并打印庆祝信息。 + * 还使用 toString() 打印狗的信息。 + * 根据第一个非命令参数选择要庆祝生日的狗。 + * @param name 我们要庆祝生日的狗的名字 */ public static void celebrateBirthday(String name) { // TODO + Dog dog = Dog.fromFile(name); // 从文件中读取狗对象 + dog.haveBirthday(); // 增加狗的年龄并打印庆祝信息 + dog.saveDog(); // 持久化保存更新后的狗对象 } -} +} \ No newline at end of file diff --git a/lab6/capers/Dog.java b/lab6/capers/Dog.java index e9ef3b315..3330a9530 100644 --- a/lab6/capers/Dog.java +++ b/lab6/capers/Dog.java @@ -5,20 +5,18 @@ import static capers.Utils.*; /** Represents a dog that can be serialized. - * @author TODO -*/ -public class Dog { // TODO + */ +public class Dog implements Serializable { // 实现 Serializable 接口以便对象可以被序列化 /** Folder that dogs live in. */ - static final File DOG_FOLDER = null; // TODO (hint: look at the `join` - // function in Utils) + static final File DOG_FOLDER = join(".capers", "dogs"); // 定义狗文件夹路径 /** Age of dog. */ - private int age; + private int age; // 狗的年龄 /** Breed of dog. */ - private String breed; + private String breed; // 狗的品种 /** Name of dog. */ - private String name; + private String name; // 狗的名字 /** * Creates a dog object with the specified parameters. @@ -39,31 +37,31 @@ public Dog(String name, String breed, int age) { * @return Dog read from file */ public static Dog fromFile(String name) { - // TODO (hint: look at the Utils file) - return null; + File dogFile = join(DOG_FOLDER, name); // 创建指向狗文件的路径 + return readObject(dogFile, Dog.class); // 从文件中读取并反序列化狗对象 } /** * Increases a dog's age and celebrates! */ public void haveBirthday() { - age += 1; - System.out.println(toString()); - System.out.println("Happy birthday! Woof! Woof!"); + age += 1; // 增加狗的年龄 + System.out.println(toString()); // 打印狗的详细信息 + System.out.println("Happy birthday! Woof! Woof!"); // 打印生日庆祝信息 } /** * Saves a dog to a file for future use. */ public void saveDog() { - // TODO (hint: don't forget dog names are unique) + File dogFile = join(DOG_FOLDER, name); // 创建指向狗文件的路径 + writeObject(dogFile, this); // 将狗对象序列化并写入文件 } @Override public String toString() { return String.format( - "Woof! My name is %s and I am a %s! I am %d years old! Woof!", - name, breed, age); + "Woof! My name is %s and I am a %s! I am %d years old! Woof!", + name, breed, age); // 返回狗的详细信息字符串 } - -} +} \ No newline at end of file diff --git a/lab6/capers/Main.java b/lab6/capers/Main.java index 6d013bd18..7b5927256 100644 --- a/lab6/capers/Main.java +++ b/lab6/capers/Main.java @@ -53,10 +53,16 @@ public static void main(String[] args) { case "dog": validateNumArgs("dog", args, 4); // TODO: make a dog + String name = args[1]; + String breed = args[2]; + int age = Integer.parseInt(args[3]); + CapersRepository.makeDog(name , breed,age) ; break; case "birthday": validateNumArgs("birthday", args, 2); // TODO: celebrate this dog's birthday + String dogName = args[1]; + CapersRepository.celebrateBirthday(dogName); break; default: exitWithError(String.format("Unknown command: %s", args[0])); diff --git a/lab6/capers/Utils.java b/lab6/capers/Utils.java index d931e3edb..90c849eb9 100644 --- a/lab6/capers/Utils.java +++ b/lab6/capers/Utils.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FilenameFilter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -12,12 +11,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.Formatter; -import java.util.List; - /** Assorted utilities. * @author P. N. Hilfinger @@ -54,11 +47,9 @@ static String readContentsAsString(File file) { static void writeContents(File file, Object... contents) { try { if (file.isDirectory()) { - throw - new IllegalArgumentException("cannot overwrite directory"); + throw new IllegalArgumentException("cannot overwrite directory"); } - BufferedOutputStream str = - new BufferedOutputStream(Files.newOutputStream(file.toPath())); + BufferedOutputStream str = new BufferedOutputStream(Files.newOutputStream(file.toPath())); for (Object obj : contents) { if (obj instanceof byte[]) { str.write((byte[]) obj); @@ -74,16 +65,13 @@ static void writeContents(File file, Object... contents) { /** Return an object of type T read from FILE, casting it to EXPECTEDCLASS. * Throws IllegalArgumentException in case of problems. */ - static T readObject(File file, - Class expectedClass) { + static T readObject(File file, Class expectedClass) { try { - ObjectInputStream in = - new ObjectInputStream(new FileInputStream(file)); + ObjectInputStream in = new ObjectInputStream(new FileInputStream(file)); T result = expectedClass.cast(in.readObject()); in.close(); return result; - } catch (IOException | ClassCastException - | ClassNotFoundException excp) { + } catch (IOException | ClassCastException | ClassNotFoundException excp) { throw new IllegalArgumentException(excp.getMessage()); } } @@ -93,24 +81,22 @@ static void writeObject(File file, Serializable obj) { writeContents(file, serialize(obj)); } - /* OTHER FILE UTILITIES */ /** Return the concatentation of FIRST and OTHERS into a File designator, - * analogous to the {@link java.nio.file.Paths.#get(String, String[])} + * analogous to the {@link java.nio.file.Paths#get(String, String...)} * method. */ static File join(String first, String... others) { return Paths.get(first, others).toFile(); } /** Return the concatentation of FIRST and OTHERS into a File designator, - * analogous to the {@link java.nio.file.Paths.#get(String, String[])} + * analogous to the {@link java.nio.file.Paths#get(String, String...)} * method. */ static File join(File first, String... others) { return Paths.get(first.getPath(), others).toFile(); } - /* SERIALIZATION UTILITIES */ /** Returns a byte array containing the serialized contents of OBJ. */ @@ -122,12 +108,10 @@ static byte[] serialize(Serializable obj) { objectStream.close(); return stream.toByteArray(); } catch (IOException excp) { - throw error("Internal error serializing commit."); + throw new RuntimeException("Internal error serializing commit."); } } - - /* MESSAGES AND ERROR REPORTING */ /** @@ -150,5 +134,4 @@ public static void exitWithError(String message) { static RuntimeException error(String msg, Object... args) { return new RuntimeException(String.format(msg, args)); } - -} +} \ No newline at end of file diff --git a/lab7/bstmap/BSTMap.java b/lab7/bstmap/BSTMap.java new file mode 100644 index 000000000..8b2ba6f6a --- /dev/null +++ b/lab7/bstmap/BSTMap.java @@ -0,0 +1,116 @@ +package bstmap; + +import java.util.Set; +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class BSTMap ,V> implements Map61B{ + private Node root; + private int size; + + private class Node { + private K key; + private V value; + private Node left , right; + + public Node (K key , V value){ + this.key = key; + this.value = value; + } + } + public BSTMap(){ + root = null; + size = 0; + } + + + @Override + public void clear() { + root = null; + size = 0; + } + + @Override + public boolean containsKey(K key) { + return get(key) != null; + } + + @Override + public V get(K key) { + return get(root, key); + } + + private V get(Node node , K key){ + if (node == null){ + return null; + } + int compara = key.compareTo(node.key); + if (compara == 0){ + return node.value; + } + if (compara < 0){ + return get(node.left , key); + }else { + return get(node.right , key); + } + } + + @Override + public int size() { + return size; + } + + @Override + public void put(K key, V value) { + root = put(root , key , value); + } + + private Node put(Node node , K key , V value){ + if (node == null){ + size++; + return new Node (key,value); + } + int cmpara = key.compareTo(node.key); + if (cmpara == 0){ + node.value = value; + }else if (cmpara > 0){ + node.right = put (node.right , key , value); + }else{ + node.left = put (node.left , key , value); + } + return node; + } + + + @Override + public Set keySet() { + Set keys = new HashSet<>(); + keySet(root, keys); + return keys; + } + + private void keySet(Node node, Set keys) { + if (node != null) { + keys.add(node.key); + keySet(node.left, keys); + keySet(node.right, keys); + } + } + + @Override + public V remove(K key) { + return null; + } + + + @Override + public V remove(K key, V value) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + throw new UnsupportedOperationException(); + } +} diff --git a/lab7/bstmap/Main.java b/lab7/bstmap/Main.java new file mode 100644 index 000000000..9d4600f24 --- /dev/null +++ b/lab7/bstmap/Main.java @@ -0,0 +1,5 @@ +package bstmap; + +public class Main { + +} diff --git a/lab7/pom.xml b/lab7/pom.xml index ecf488380..9f54a55db 100644 --- a/lab7/pom.xml +++ b/lab7/pom.xml @@ -14,6 +14,14 @@ CS61B lab7 1.0-SNAPSHOT + + + junit + junit + RELEASE + compile + + ${project.basedir} diff --git a/lab8/hashmap/MyHashMap.java b/lab8/hashmap/MyHashMap.java index 6598f03fe..c6f3305b2 100755 --- a/lab8/hashmap/MyHashMap.java +++ b/lab8/hashmap/MyHashMap.java @@ -1,6 +1,6 @@ package hashmap; -import java.util.Collection; +import java.util.*; /** * A hash table-backed Map implementation. Provides amortized constant time @@ -10,6 +10,12 @@ * @author YOUR NAME HERE */ public class MyHashMap implements Map61B { + private Collection[] buckets; + private int size; + + public MyHashMap() { + buckets = createTable(16); // 初始化buckets数组,大小为16 + } /** * Protected helper class to store key/value pairs @@ -25,14 +31,17 @@ protected class Node { } } + + public MyHashMap(int initialSize) { + buckets = createTable(initialSize); + } + + /* Instance Variables */ - private Collection[] buckets; // You should probably define some more! /** Constructors */ - public MyHashMap() { } - public MyHashMap(int initialSize) { } /** * MyHashMap constructor that creates a backing array of initialSize. @@ -41,15 +50,18 @@ public MyHashMap(int initialSize) { } * @param initialSize initial size of backing array * @param maxLoad maximum load factor */ - public MyHashMap(int initialSize, double maxLoad) { } + public MyHashMap(int initialSize, double maxLoad) { + buckets = createTable(initialSize); + } /** * Returns a new node to be placed in a hash table bucket */ private Node createNode(K key, V value) { - return null; + return new Node(key, value); } + /** * Returns a data structure to be a hash table bucket * @@ -69,7 +81,7 @@ private Node createNode(K key, V value) { * OWN BUCKET DATA STRUCTURES WITH THE NEW OPERATOR! */ protected Collection createBucket() { - return null; + return new ArrayList<>(); } /** @@ -79,13 +91,115 @@ protected Collection createBucket() { * BE SURE TO CALL THIS FACTORY METHOD WHEN CREATING A TABLE SO * THAT ALL BUCKET TYPES ARE OF JAVA.UTIL.COLLECTION * - * @param tableSize the size of the table to create + * @param size the size of the table to create */ - private Collection[] createTable(int tableSize) { - return null; + private Collection[] createTable(int size) { + Collection[] table = new Collection[size]; + for (int i = 0 ; i < size ; i++){ + table[i] = new ArrayList<>(); + } + return table; } // TODO: Implement the methods of the Map61B Interface below // Your code won't compile until you do so! + @Override + public void clear() { + buckets = createTable(buckets.length); + size = 0; + } + + @Override + public boolean containsKey(K key) { + int index = hash(key); + for (Node node : buckets[index]){ + if (node.key.equals(key)){ + return true; + } + } + return false; + } + + @Override + public V get(K key) { + int index = hash(key); + for (Node node : buckets[index]){ + if (node.key.equals(key)){ + return node.value; + } + } + return null; + } + + @Override + public int size() { + return size; + } + + @Override + public void put(K key, V value) { + int index = hash(key); + for (Node node : buckets[index]) { + if (node.key.equals(key)) { + node.value = value; + return; + } + } + buckets[index].add(createNode(key, value)); + size++; + } + + @Override + public Set keySet() { + Set keySet = new HashSet<>(); + for (Collection bucket : buckets) { + for (Node node : bucket) { + keySet.add(node.key); + } + } + return keySet; + } + + + @Override + public V remove(K key) { + int index = hash(key); + Iterator iterator = buckets[index].iterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (node.key.equals(key)) { + V value = node.value; + iterator.remove(); + size--; + return value; + } + } + return null; + } + + @Override + public V remove(K key, V value) { + int index = hash(key); + Iterator iterator = buckets[index].iterator(); + while (iterator.hasNext()) { + Node node = iterator.next(); + if (node.key.equals(key) && node.value.equals(value)) { + iterator.remove(); + size--; + return value; + } + } + return null; + } + + @Override + public Iterator iterator() { + return keySet().iterator(); + } + + private int hash(K key){ + return Math.floorMod(key.hashCode(), buckets.length); + } + } diff --git a/proj0/game2048/Model.java b/proj0/game2048/Model.java index 2ecebebb7..5af1b4a35 100644 --- a/proj0/game2048/Model.java +++ b/proj0/game2048/Model.java @@ -8,13 +8,21 @@ * @author TODO: YOUR NAME HERE */ public class Model extends Observable { - /** Current contents of the board. */ + /** + * Current contents of the board. + */ private Board board; - /** Current score. */ + /** + * Current score. + */ private int score; - /** Maximum score so far. Updated when game ends. */ + /** + * Maximum score so far. Updated when game ends. + */ private int maxScore; - /** True iff game is ended. */ + /** + * True iff game is ended. + */ private boolean gameOver; /* Coordinate System: column C, row R of the board (where row 0, @@ -22,20 +30,26 @@ public class Model extends Observable { * to board.tile(c, r). Be careful! It works like (x, y) coordinates. */ - /** Largest piece value. */ + /** + * Largest piece value. + */ public static final int MAX_PIECE = 2048; - /** A new 2048 game on a board of size SIZE with no pieces - * and score 0. */ + /** + * A new 2048 game on a board of size SIZE with no pieces + * and score 0. + */ public Model(int size) { board = new Board(size); score = maxScore = 0; gameOver = false; } - /** A new 2048 game where RAWVALUES contain the values of the tiles + /** + * A new 2048 game where RAWVALUES contain the values of the tiles * (0 if null). VALUES is indexed by (row, col) with (0, 0) corresponding - * to the bottom-left corner. Used for testing purposes. */ + * to the bottom-left corner. Used for testing purposes. + */ public Model(int[][] rawValues, int score, int maxScore, boolean gameOver) { int size = rawValues.length; board = new Board(rawValues, score); @@ -44,22 +58,27 @@ public Model(int[][] rawValues, int score, int maxScore, boolean gameOver) { this.gameOver = gameOver; } - /** Return the current Tile at (COL, ROW), where 0 <= ROW < size(), - * 0 <= COL < size(). Returns null if there is no tile there. - * Used for testing. Should be deprecated and removed. - * */ + /** + * Return the current Tile at (COL, ROW), where 0 <= ROW < size(), + * 0 <= COL < size(). Returns null if there is no tile there. + * Used for testing. Should be deprecated and removed. + */ public Tile tile(int col, int row) { return board.tile(col, row); } - /** Return the number of squares on one side of the board. - * Used for testing. Should be deprecated and removed. */ + /** + * Return the number of squares on one side of the board. + * Used for testing. Should be deprecated and removed. + */ public int size() { return board.size(); } - /** Return true iff the game is over (there are no moves, or - * there is a tile with value 2048 on the board). */ + /** + * Return true iff the game is over (there are no moves, or + * there is a tile with value 2048 on the board). + */ public boolean gameOver() { checkGameOver(); if (gameOver) { @@ -68,17 +87,23 @@ public boolean gameOver() { return gameOver; } - /** Return the current score. */ + /** + * Return the current score. + */ public int score() { return score; } - /** Return the current maximum game score (updated at end of game). */ + /** + * Return the current maximum game score (updated at end of game). + */ public int maxScore() { return maxScore; } - /** Clear the board to empty and reset the score. */ + /** + * Clear the board to empty and reset the score. + */ public void clear() { score = 0; gameOver = false; @@ -86,41 +111,66 @@ public void clear() { setChanged(); } - /** Add TILE to the board. There must be no Tile currently at the - * same position. */ + /** + * Add TILE to the board. There must be no Tile currently at the + * same position. + */ public void addTile(Tile tile) { board.addTile(tile); checkGameOver(); setChanged(); } - /** Tilt the board toward SIDE. Return true iff this changes the board. - * + /** + * Tilt the board toward SIDE. Return true iff this changes the board. + *

* 1. If two Tile objects are adjacent in the direction of motion and have - * the same value, they are merged into one Tile of twice the original - * value and that new value is added to the score instance variable + * the same value, they are merged into one Tile of twice the original + * value and that new value is added to the score instance variable * 2. A tile that is the result of a merge will not merge again on that - * tilt. So each move, every tile will only ever be part of at most one - * merge (perhaps zero). + * tilt. So each move, every tile will only ever be part of at most one + * merge (perhaps zero). * 3. When three adjacent tiles in the direction of motion have the same - * value, then the leading two tiles in the direction of motion merge, - * and the trailing tile does not. - * */ + * value, then the leading two tiles in the direction of motion merge, + * and the trailing tile does not. + */ public boolean tilt(Side side) { - boolean changed; - changed = false; + board.setViewingPerspective(side); // 设置当前视角 + boolean changed = false; + boolean[][] merged = new boolean[board.size()][board.size()]; + // 遍历每一列 + for (int col = 0; col < board.size(); col++) { + for (int row = board.size() - 1; row >= 0; row--) { + Tile t = board.tile(col, row); + if (t != null) { + int nextRow = row + 1; // 找到下一个非空行 + while (nextRow < board.size() && board.tile(col, nextRow) == null) { + nextRow++; + } - // TODO: Modify this.board (and perhaps this.score) to account - // for the tilt to the Side SIDE. If the board changed, set the - // changed local variable to true. + // 检查是否可以合并 + if (nextRow < board.size() && t.value() == board.tile(col, nextRow).value() && !merged[nextRow][col]) { + board.move(col, nextRow, t); // 合并 + score += 2 * t.value(); + merged[nextRow][col] = true; // 标记已合并 + changed = true; + } else if (nextRow - 1 != row) { + board.move(col, nextRow - 1, t); // 移动至最近一个可用位置 + changed = true; + } + } + } + } - checkGameOver(); + board.setViewingPerspective(Side.NORTH); // 恢复视角为北 + checkGameOver(); // 检查游戏是否结束 if (changed) { setChanged(); } return changed; } + /** Checks if the game is over and sets the gameOver variable * appropriately. */ @@ -137,7 +187,13 @@ private static boolean checkGameOver(Board b) { * Empty spaces are stored as null. * */ public static boolean emptySpaceExists(Board b) { - // TODO: Fill in this function. + for (int i = 0;i < 4;i++) { + for (int j = 0;j < 4;j++) { + if (b.tile(i,j) == null) { + return true; + } + } + } return false; } @@ -148,6 +204,13 @@ public static boolean emptySpaceExists(Board b) { */ public static boolean maxTileExists(Board b) { // TODO: Fill in this function. + for (int i = 0; i < 4; i++){ + for (int j = 0; j < 4; j++){ + if (b.tile(i,j) != null && b.tile(i,j).value() == MAX_PIECE){ + return true; + } + } + } return false; } @@ -159,6 +222,19 @@ public static boolean maxTileExists(Board b) { */ public static boolean atLeastOneMoveExists(Board b) { // TODO: Fill in this function. + for (int i = 0; i < 4 ;i++){ + for (int j = 0; j <4; j++){ + if (b.tile(i,j)==null){ + return true; + } + else if (i < 3 && b.tile(i,j).value() == b.tile(i+1,j).value()){ + return true; + } + else if (j < 3 && b.tile(i,j).value() == b.tile(i,j+1).value()){ + return true; + } + } + } return false; } diff --git a/proj1/deque/ArrayDeque.java b/proj1/deque/ArrayDeque.java new file mode 100644 index 000000000..7c1023ed0 --- /dev/null +++ b/proj1/deque/ArrayDeque.java @@ -0,0 +1,96 @@ +package deque; + +public class ArrayDeque implements Deque { + private T[] items; + private int size; + private int nextFirst; + private int nextLast; + + public ArrayDeque() { + items = (T[]) new Object[8]; + size = 0; + nextFirst = 0; + nextLast = 1; + } + + @Override + public void addFirst(T item) { + if (size == items.length) { + resize(items.length * 2); + } + items[nextFirst] = item; + nextFirst = (nextFirst - 1 + items.length) % items.length; + size++; + } + + @Override + public void addLast(T item) { + if (size == items.length) { + resize(items.length * 2); + } + items[nextLast] = item; + nextLast = (nextLast + 1) % items.length; + size++; + } + + @Override + public int size() { + return size; + } + + @Override + public void printDeque() { + for (int i = 0; i < size; i++) { + System.out.print(items[(nextFirst + 1 + i) % items.length] + " "); + } + System.out.println(); + } + + @Override + public T removeFirst() { + if (isEmpty()) { + return null; + } + nextFirst = (nextFirst + 1) % items.length; + T item = items[nextFirst]; + items[nextFirst] = null; + size--; + if (size > 0 && size == items.length / 4) { + resize(items.length / 2); + } + return item; + } + + @Override + public T removeLast() { + if (isEmpty()) { + return null; + } + nextLast = (nextLast - 1 + items.length) % items.length; + T item = items[nextLast]; + items[nextLast] = null; + size--; + if (size > 0 && size == items.length / 4) { + resize(items.length / 2); + } + return item; + } + + @Override + public T get(int index) { + if (index < 0 || index >= size) { + return null; + } + return items[(nextFirst + 1 + index) % items.length]; + } + + private void resize(int capacity) { + T[] newItems = (T[]) new Object[capacity]; + for (int i = 0; i < size; i++) { + newItems[i] = items[(nextFirst + 1 + i) % items.length]; + } + items = newItems; + nextFirst = capacity - 1; + nextLast = size; + } +} \ No newline at end of file diff --git a/proj1/deque/Deque.java b/proj1/deque/Deque.java new file mode 100644 index 000000000..1d32e1cbb --- /dev/null +++ b/proj1/deque/Deque.java @@ -0,0 +1,15 @@ +package deque; + +public interface Deque { + void addFirst(T item); + void addLast(T item); + int size(); + void printDeque(); + T removeFirst(); + T removeLast(); + T get(int index); + + default boolean isEmpty() { + return size() == 0; + } +} \ No newline at end of file diff --git a/proj1/deque/LinkedListDeque.java b/proj1/deque/LinkedListDeque.java new file mode 100644 index 000000000..97cfd607e --- /dev/null +++ b/proj1/deque/LinkedListDeque.java @@ -0,0 +1,106 @@ +package deque; + +public class LinkedListDeque implements Deque { + private class Node { + T item; + Node next; + Node prev; + + Node(T i, Node n, Node p) { + item = i; + next = n; + prev = p; + } + } + + private Node sentinel; + private int size; + + public LinkedListDeque() { + sentinel = new Node(null, null, null); + sentinel.next = sentinel; + sentinel.prev = sentinel; + size = 0; + } + + @Override + public void addFirst(T item) { + Node newNode = new Node(item, sentinel.next, sentinel); + sentinel.next.prev = newNode; + sentinel.next = newNode; + size++; + } + + @Override + public void addLast(T item) { + Node newNode = new Node(item, sentinel, sentinel.prev); + sentinel.prev.next = newNode; + sentinel.prev = newNode; + size++; + } + + @Override + public int size() { + return size; + } + + @Override + public void printDeque() { + Node current = sentinel.next; + while (current != sentinel) { + System.out.print(current.item + " "); + current = current.next; + } + System.out.println(); + } + + @Override + public T removeFirst() { + if (isEmpty()) { + return null; + } + Node first = sentinel.next; + sentinel.next = first.next; + first.next.prev = sentinel; + size--; + return first.item; + } + + @Override + public T removeLast() { + if (isEmpty()) { + return null; + } + Node last = sentinel.prev; + sentinel.prev = last.prev; + last.prev.next = sentinel; + size--; + return last.item; + } + + @Override + public T get(int index) { + if (index < 0 || index >= size) { + return null; + } + Node current = sentinel.next; + for (int i = 0; i < index; i++) { + current = current.next; + } + return current.item; + } + + public T getRecursive(int index) { + if (index < 0 || index >= size) { + return null; + } + return getRecursiveHelper(sentinel.next, index); + } + + private T getRecursiveHelper(Node node, int index) { + if (index == 0) { + return node.item; + } + return getRecursiveHelper(node.next, index - 1); + } +} \ No newline at end of file diff --git a/proj1/deque/LinkedListDequeTest.java b/proj1/deque/LinkedListDequeTest.java index 141c2b2d0..fcebca1a5 100644 --- a/proj1/deque/LinkedListDequeTest.java +++ b/proj1/deque/LinkedListDequeTest.java @@ -1,6 +1,7 @@ package deque; -import org.junit.Test; +import org.junit.jupiter.api.Test; + import static org.junit.Assert.*; @@ -15,7 +16,7 @@ public class LinkedListDequeTest { public void addIsEmptySizeTest() { System.out.println("Make sure to uncomment the lines below (and delete this print statement)."); - /* + LinkedListDeque lld1 = new LinkedListDeque(); assertTrue("A newly initialized LLDeque should be empty", lld1.isEmpty()); @@ -34,7 +35,7 @@ public void addIsEmptySizeTest() { System.out.println("Printing out deque: "); lld1.printDeque(); - */ + } @Test @@ -42,7 +43,7 @@ public void addIsEmptySizeTest() { public void addRemoveTest() { System.out.println("Make sure to uncomment the lines below (and delete this print statement)."); - /* + LinkedListDeque lld1 = new LinkedListDeque(); // should be empty assertTrue("lld1 should be empty upon initialization", lld1.isEmpty()); @@ -54,7 +55,7 @@ public void addRemoveTest() { lld1.removeFirst(); // should be empty assertTrue("lld1 should be empty after removal", lld1.isEmpty()); - */ + } @Test @@ -62,7 +63,7 @@ public void addRemoveTest() { public void removeEmptyTest() { System.out.println("Make sure to uncomment the lines below (and delete this print statement)."); - /* + LinkedListDeque lld1 = new LinkedListDeque<>(); lld1.addFirst(3); @@ -77,14 +78,14 @@ public void removeEmptyTest() { errorMsg += " actual size() returned 0\n"; assertEquals(errorMsg, 0, size); - */ + } @Test /* Check if you can create LinkedListDeques with different parameterized types*/ public void multipleParamTest() { - /* + LinkedListDeque lld1 = new LinkedListDeque(); LinkedListDeque lld2 = new LinkedListDeque(); LinkedListDeque lld3 = new LinkedListDeque(); @@ -96,7 +97,7 @@ public void multipleParamTest() { String s = lld1.removeFirst(); double d = lld2.removeFirst(); boolean b = lld3.removeFirst(); - */ + } @Test @@ -104,7 +105,7 @@ public void multipleParamTest() { public void emptyNullReturnTest() { System.out.println("Make sure to uncomment the lines below (and delete this print statement)."); - /* + LinkedListDeque lld1 = new LinkedListDeque(); boolean passed1 = false; @@ -112,7 +113,7 @@ public void emptyNullReturnTest() { assertEquals("Should return null when removeFirst is called on an empty Deque,", null, lld1.removeFirst()); assertEquals("Should return null when removeLast is called on an empty Deque,", null, lld1.removeLast()); - */ + } @Test @@ -120,7 +121,7 @@ public void emptyNullReturnTest() { public void bigLLDequeTest() { System.out.println("Make sure to uncomment the lines below (and delete this print statement)."); - /* + LinkedListDeque lld1 = new LinkedListDeque(); for (int i = 0; i < 1000000; i++) { lld1.addLast(i); @@ -134,6 +135,6 @@ public void bigLLDequeTest() { assertEquals("Should have the same value", i, (double) lld1.removeLast(), 0.0); } - */ + } } diff --git a/proj1/deque/MaxArrayDeque.java b/proj1/deque/MaxArrayDeque.java new file mode 100644 index 000000000..3d3169b0a --- /dev/null +++ b/proj1/deque/MaxArrayDeque.java @@ -0,0 +1,45 @@ +package deque; + +import java.util.Comparator; + +public class MaxArrayDeque extends ArrayDeque { + private Comparator comparator; + + /** + * Creates a MaxArrayDeque with the given Comparator. + * @param c the Comparator to use for finding the maximum element + */ + public MaxArrayDeque(Comparator c) { + super(); + this.comparator = c; + } + + /** + * Returns the maximum element in the deque as governed by the previously given Comparator. + * If the MaxArrayDeque is empty, simply return null. + * @return the maximum element in the deque, or null if the deque is empty + */ + public T max() { + return max(this.comparator); + } + + /** + * Returns the maximum element in the deque as governed by the parameter Comparator c. + * If the MaxArrayDeque is empty, simply return null. + * @param c the Comparator to use for finding the maximum element + * @return the maximum element in the deque, or null if the deque is empty + */ + public T max(Comparator c) { + if (isEmpty()) { + return null; + } + T maxElement = get(0); + for (int i = 1; i < size(); i++) { + T currentElement = get(i); + if (c.compare(currentElement, maxElement) > 0) { + maxElement = currentElement; + } + } + return maxElement; + } +} \ No newline at end of file diff --git a/proj1/gh2/GuitarHeroLite.java b/proj1/gh2/GuitarHeroLite.java index 98fbabca9..c618215d7 100755 --- a/proj1/gh2/GuitarHeroLite.java +++ b/proj1/gh2/GuitarHeroLite.java @@ -37,5 +37,4 @@ public static void main(String[] args) { stringC.tic(); } } -} - +} \ No newline at end of file diff --git a/proj1/gh2/GuitarPlayer.java b/proj1/gh2/GuitarPlayer.java index 5dd86bdd3..a9e4322a3 100755 --- a/proj1/gh2/GuitarPlayer.java +++ b/proj1/gh2/GuitarPlayer.java @@ -57,7 +57,6 @@ private double sample() { } return sum; } - public void play() { if (sequence == null) { return; @@ -92,7 +91,7 @@ public void play() { int tempo = (data[0] & 0xff) << 16 | (data[1] & 0xff) << 8 | (data[2] & 0xff); bpm = 60000000.0 / tempo; samplesPerTick = StdAudio.SAMPLE_RATE - * (60.0 / (sequence.getResolution() * bpm)); + * (60.0 / (sequence.getResolution() * bpm)); } else if (mm.getType() == 0x05) { // lyrics data = mm.getData(); @@ -137,4 +136,4 @@ public void play() { System.out.println("please clap"); } -} +} \ No newline at end of file diff --git a/proj1/gh2/GuitarString.java b/proj1/gh2/GuitarString.java index 3c76fa237..7e33fa3ca 100755 --- a/proj1/gh2/GuitarString.java +++ b/proj1/gh2/GuitarString.java @@ -1,10 +1,8 @@ package gh2; +import deque.ArrayDeque; +import deque.Deque; -// TODO: uncomment the following import once you're ready to start this portion -// import deque.Deque; -// TODO: maybe more imports - -//Note: This file will not compile until you complete the Deque implementations +// Note: This file will not compile until you complete the Deque implementations public class GuitarString { /** Constants. Do not change. In case you're curious, the keyword final * means the values cannot be changed at runtime. We'll discuss this and @@ -13,43 +11,47 @@ public class GuitarString { private static final double DECAY = .996; // energy decay factor /* Buffer for storing sound data. */ - // TODO: uncomment the following line once you're ready to start this portion - // private Deque buffer; + private Deque buffer; /* Create a guitar string of the given frequency. */ public GuitarString(double frequency) { - // TODO: Create a buffer with capacity = SR / frequency. You'll need to - // cast the result of this division operation into an int. For - // better accuracy, use the Math.round() function before casting. - // Your should initially fill your buffer array with zeros. + int capacity = (int) Math.round(SR / frequency); + buffer = new ArrayDeque<>(); + for (int i = 0; i < capacity; i++) { + buffer.addLast(0.0); + } } - /* Pluck the guitar string by replacing the buffer with white noise. */ public void pluck() { - // TODO: Dequeue everything in buffer, and replace with random numbers - // between -0.5 and 0.5. You can get such a number by using: - // double r = Math.random() - 0.5; - // - // Make sure that your random numbers are different from each - // other. This does not mean that you need to check that the numbers - // are different from each other. It means you should repeatedly call - // Math.random() - 0.5 to generate new random numbers for each array index. + // Dequeue everything in buffer + int capacity = buffer.size(); + for (int i = 0; i < capacity; i++) { + buffer.removeFirst(); + } + // Replace with random numbers between -0.5 and 0.5 + for (int i = 0; i < capacity; i++) { + double r = Math.random() - 0.5; + buffer.addLast(r); + } } /* Advance the simulation one time step by performing one iteration of - * the Karplus-Strong algorithm. - */ + * the Karplus-Strong algorithm. */ public void tic() { - // TODO: Dequeue the front sample and enqueue a new sample that is - // the average of the two multiplied by the DECAY factor. - // **Do not call StdAudio.play().** + // Dequeue the front sample + double firstSample = buffer.removeFirst(); + // Get the new front sample + double secondSample = buffer.get(0); + // Calculate the new sample + double newSample = (firstSample + secondSample) / 2 * DECAY; + // Enqueue the new sample + buffer.addLast(newSample); } /* Return the double at the front of the buffer. */ public double sample() { - // TODO: Return the correct thing. - return 0; + // Return the correct thing + return buffer.get(0); } -} - // TODO: Remove all comments that say TODO when you're done. +} \ No newline at end of file diff --git a/proj1/gh2/TTFAF.java b/proj1/gh2/TTFAF.java index 61115ec57..f1ebce1bf 100755 --- a/proj1/gh2/TTFAF.java +++ b/proj1/gh2/TTFAF.java @@ -29,159 +29,159 @@ public static void main(String[] args) { } private static final String TTFAF = - "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" - + "6zR/5Bb/AT7+4c9/APjxG/j/XQ2yXpqSAA=="; -} + "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" + + "6zR/5Bb/AT7+4c9/APjxG/j/XQ2yXpqSAA=="; +} \ No newline at end of file diff --git a/proj1/gh2/TestGuitarString.java b/proj1/gh2/TestGuitarString.java index 102f4a899..449cafc01 100644 --- a/proj1/gh2/TestGuitarString.java +++ b/proj1/gh2/TestGuitarString.java @@ -55,7 +55,7 @@ public void testTic() { @Test public void testTicCalculations() { // Create a GuitarString of frequency 11025, which - // is a Deque of length 4. + // is a Deque of length 4. GuitarString s = new GuitarString(11025); s.pluck(); @@ -63,7 +63,7 @@ public void testTicCalculations() { double s1 = s.sample(); s.tic(); double s2 = s.sample(); - s.tic(); + s.tic(); double s3 = s.sample(); s.tic(); double s4 = s.sample(); @@ -79,5 +79,4 @@ public void testTicCalculations() { // for assertEquals(double, double) assertEquals("Wrong tic value. Try running the testTic method.", expected, s5, 0.001); } -} - +} \ No newline at end of file diff --git a/proj1/pom.xml b/proj1/pom.xml index f1822ea65..b00e919c4 100644 --- a/proj1/pom.xml +++ b/proj1/pom.xml @@ -14,6 +14,38 @@ CS61B proj1 1.0-SNAPSHOT + + + org.junit.jupiter + junit-jupiter + RELEASE + compile + + + junit + junit + RELEASE + compile + + + junit + junit + RELEASE + compile + + + junit + junit + RELEASE + compile + + + junit + junit + RELEASE + compile + + ${project.basedir} @@ -40,5 +72,5 @@ - - + + \ No newline at end of file diff --git a/proj2/gitlet/Commit.java b/proj2/gitlet/Commit.java index 929165190..e0e86323b 100644 --- a/proj2/gitlet/Commit.java +++ b/proj2/gitlet/Commit.java @@ -1,26 +1,62 @@ package gitlet; -// TODO: any imports you need here - -import java.util.Date; // TODO: You'll likely use this in this class - -/** Represents a gitlet commit object. - * TODO: It's a good idea to give a description here of what else this Class - * does at a high level. - * - * @author TODO - */ -public class Commit { - /** - * TODO: add instance variables here. - * - * List all instance variables of the Commit class here with a useful - * comment above them describing what that variable represents and how that - * variable is used. We've provided one example for `message`. - */ - - /** The message of this Commit. */ +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** 表示一个gitlet提交对象。 */ +public class Commit implements Serializable { private String message; + private Date timestamp; + private String id; + private String parent; + private Map blobs; + + public Commit(String message, Date timestamp, String parent, Map blobs) { + this.message = message; + this.timestamp = timestamp; + this.parent = parent; + this.blobs = blobs; + this.id = Utils.sha1(message, timestamp.toString(), parent, blobs.toString()); + } + + public String getId() { + return id; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Date getTimestamp() { + return timestamp; + } + + public void setTimestamp(Date timestamp) { + this.timestamp = timestamp; + } + + public void setId(String id) { + this.id = id; + } + + public String getParent() { + return parent; + } + + public void setParent(String parent) { + this.parent = parent; + } + + public void setBlobs(Map blobs) { + this.blobs = blobs; + } - /* TODO: fill in the rest of this class. */ -} + public Map getBlobs() { + return blobs; + } +} \ No newline at end of file diff --git a/proj2/gitlet/Main.java b/proj2/gitlet/Main.java index 6322f9774..16c22ae99 100644 --- a/proj2/gitlet/Main.java +++ b/proj2/gitlet/Main.java @@ -1,24 +1,562 @@ package gitlet; -/** Driver class for Gitlet, a subset of the Git version-control system. - * @author TODO - */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** Gitlet的驱动类,一个Git版本控制系统的子集。 */ public class Main { - /** Usage: java gitlet.Main ARGS, where ARGS contains - * ... - */ - public static void main(String[] args) { - // TODO: what if args is empty? + /** 用法: java gitlet.Main ARGS, 其中ARGS包含 ... */ + public static void main(String[] args) throws IOException { + // 如果args为空,提示用户输入命令 + if (args.length == 0) { + System.out.println("请输入一个命令。"); + return; + } + String firstArg = args[0]; - switch(firstArg) { + switch (firstArg) { case "init": - // TODO: handle the `init` command + // 处理`init`命令 + init(); break; case "add": - // TODO: handle the `add [filename]` command + // 处理`add [filename]`命令 + if (args.length < 2) { + System.out.println("请输入要添加的文件名。"); + return; + } + add(args[1]); + break; + case "commit": + // 处理`commit [message]`命令 + if (args.length < 2) { + System.out.println("请输入提交信息。"); + return; + } + commit(args[1]); + break; + case "rm": + // 处理`rm [filename]`命令 + if (args.length < 2) { + System.out.println("请输入要移除的文件名。"); + return; + } + rm(args[1]); + break; + case "log": + // 处理`log`命令 + log(); + break; + case "golobal-log": + // 处理`global-log`命令 + globalLog(); break; - // TODO: FILL THE REST IN + case "find": + // 处理`find [message]`命令 + if (args.length < 2) { + System.out.println("请输入要查找的提交信息。"); + return; + } + find(args[1]); + break; + case "status": + status(); + break; + case "checkout": + checkout(args); + break; + case "branch": + branch(args[1]); + break; + case "rm branch": + rmbranch(args[1]); + break; + case " reset": + reset(args[1]); + break; + case " merge": + merge(args[1]); + break; + default: + System.out.println("未知命令: " + firstArg); + break; + } + } + + /** + * 初始化Gitlet版本控制系统。 + * 创建.gitlet目录,并生成初始提交。 + */ + public static void init() { + // 创建.gitlet目录 + File gitletDir = new File(".gitlet"); + if (gitletDir.exists()) { + System.out.println("当前目录中已存在一个Git let版本控制系统。"); + return; + } + + if (!gitletDir.mkdir()) { + System.out.println("创建.gitlet目录失败。"); + return; + } + + // 创建初始提交 + Commit initialCommit = new Commit("initial commit", new Date(0), null, new HashMap<>()); + File commitFile = new File(gitletDir, initialCommit.getId()); + Utils.writeObject(commitFile, initialCommit); + + // 设置master分支 + File masterBranch = new File(gitletDir, "master"); + Utils.writeContents(masterBranch, initialCommit.getId()); + } + + /** + * 将指定文件添加到暂存区。 + * @param fileName 要添加的文件名 + * @throws IOException 如果文件读取或写入失败 + */ + public static void add(String fileName) throws IOException { + // 检查文件是否存在 + File file = new File(fileName); + if (!file.exists()) { + System.out.println("文件不存在。"); + return; + } + + // 读取文件内容 + byte[] fileContent = Files.readAllBytes(file.toPath()); //将文件内容逐字节读取到一个字节数组中 + File stagingArea = new File(".gitlet/staging"); + if (!stagingArea.exists()) { + stagingArea.mkdir(); + } + + // 创建暂存文件 + File stagedFile = new File(stagingArea, fileName); + if (stagedFile.exists()) { + byte[] stagedContent = Files.readAllBytes(stagedFile.toPath()); + if (Utils.sha1(fileContent).equals(Utils.sha1(stagedContent))) { + return; // 如果文件内容未变化,则无需重复添加 + } + } + + // 将文件内容写入暂存区 + Utils.writeContents(stagedFile, fileContent); + } + + /** + * 提交暂存区中的更改。 + * @param message 提交信息 + * @throws IOException 如果文件读取或写入失败 + */ + public static void commit(String message) throws IOException { + // 检查提交信息是否为空 + if (message.trim().isEmpty()) { + System.out.println("请输入提交信息。"); + return; + } + + // 检查暂存区是否为空 + File stagingArea = new File(".gitlet/staging"); + if (!stagingArea.exists() || stagingArea.list().length == 0) { + System.out.println("没有添加到提交的更改。"); + return; + } + + // 获取当前提交 + Commit parentCommit = getCurrentCommit(); + + // 创建新的blobs映射 + Map newBlobs = new HashMap<>(parentCommit.getBlobs()); + for (File file : stagingArea.listFiles()) { + byte[] fileContent = Files.readAllBytes(file.toPath()); + String blobId = Utils.sha1(fileContent); // 生成blobId + File blobFile = new File(".gitlet", blobId);// 创建blobFile + Utils.writeContents(blobFile, fileContent); // 将文件内容写入blobFile + newBlobs.put(file.getName(), blobId); // 将文件名和blobI + // d映射关系存入newBlobs + } + + // 创建新的提交对象 + Commit newCommit = new Commit(message, new Date(), getCurrentCommitId(), newBlobs); + File newCommitFile = new File(".gitlet", newCommit.getId()); + Utils.writeObject(newCommitFile, newCommit); + + // 更新head指针 + Utils.writeContents(new File(".gitlet", "master"), newCommit.getId()); + + // 清空暂存区 + for (File file : stagingArea.listFiles()) { + file.delete(); + } + } + + /** + * 从暂存区或工作目录中移除文件。 + * @param fileName 要移除的文件名 + * @throws IOException 如果文件读取或写入失败 + */ + public static void rm(String fileName) throws IOException { + File stagingArea = new File(".gitlet/staging"); + File stagedFile = new File(stagingArea, fileName); // 这行代码创建了一个 File 对象 stagedFile,它表示 stagingArea 目录中的一个名为 fileName 的文件。 + File removalArea = new File(".gitlet/removal"); + + if(!removalArea.exists()){ + removalArea.mkdir(); + } + Commit parentCommit = getCurrentCommit(); + + // 如果文件在暂存区中,则删除它 + if (stagedFile.exists()) { + Utils.writeObject(stagedFile, removalArea); + stagedFile.delete(); + } + + // 如果文件在当前提交中,则从工作目录中删除它,并标记为待删除 + if (parentCommit.getBlobs().containsKey(fileName)) { // 检查 parentCommit 的 blobs 映射中是否包含指定的 fileName + File file = new File(fileName); + if (file.exists()) { + Utils.writeObject(stagedFile, removalArea); + file.delete(); + } + Utils.writeContents(new File(stagingArea, fileName + ".rm"), ""); + } else if (!stagedFile.exists()) { + System.out.println("没有理由移除该文件。"); + } + } + + /** + * 显示提交历史。 + * @throws IOException 如果文件读取失败 + */ + public static void log() throws IOException { + String commitId = getCurrentCommitId(); + + // 遍历提交历史并打印每个提交的信息 + while (commitId != null) { + Commit commit = getCommitById(commitId); + System.out.println("==="); + System.out.println("commit " + commit.getId()); + if (commit.getParent() != null) { + Commit parentCommit = getCommitById(commit.getParent()); + if (parentCommit.getParent() != null) { + System.out.println("Merge: " + commit.getParent().substring(0, 7) + " " + parentCommit.getParent().substring(0, 7)); + } + } + System.out.println("Date: " + commit.getTimestamp()); + System.out.println(commit.getMessage()); + System.out.println(); + commitId = commit.getParent(); + } + } + /** + * 显示所有提交历史。 + * @throws IOException 如果文件读取失败 + */ + public static void globalLog() throws IOException{ + File gitletDir = new File (".gitlet"); + for (File files : gitletDir.listFiles()){ + if (files.isFile()) { + Commit commit = Utils.readObject(files, Commit.class); + System.out.println("==="); + System.out.println("commit " + commit.getId()); + if (commit.getParent() != null) { + Commit parentCommit = getCommitById(commit.getParent()); + if (parentCommit.getParent() != null) { + System.out.println("Merge: " + commit.getParent().substring(0, 7) + " " + parentCommit.getParent().substring(0, 7)); + } + } + System.out.println("Date: " + commit.getTimestamp()); + System.out.println(commit.getMessage()); + System.out.println(); + + + } + } } -} + /** + * 查找提交历史。 + * @param message 提交信息 + * @throws IOException 如果文件读取失败 + */ + + public static void find(String message) throws IOException{ + File gitletDir = new File(".gitlet"); + for (File files : gitletDir.listFiles()){ + if (files.isFile()){ + Commit commit = Utils.readObject(files, Commit.class); + if (commit.getMessage().equals(message)){ + System.out.println(commit.getId()); + } + } + } + } + + public static void status() throws IOException{ + File gitletDir = new File(".gitlet"); + File branchesDir = new File(gitletDir,"branch"); + File removalArea = new File(gitletDir,"removal"); + + String currentBranch = Utils.readContentsAsString(new File (gitletDir, "HEAD")); + + //显示分支 + System.out.println("===branch==="); + for (File branch : branchesDir.listFiles()){ + if (branch.getName().equals(currentBranch)){ + System.out.println("*"+ branch.getName()); + }else{ + System.out.println(branch.getName()); + } + } + System.out.println(); + + File stagingArea = new File(".gitlet/staging"); + //显示暂存区文件 + System.out.println("===暂存区==="); + for (File files : stagingArea.listFiles()){ + if (files.isFile()){ + System.out.println(files.getName()); + } + } + System.out.println(); + //显示已删除文件 + System.out.println("===已删除文件==="); + for (File rm : removalArea.listFiles()){ + System.out.println(rm.getName()); + } + System.out.println(); + + } + + private static void checkout(String []args) throws IOException{ + //传入id和文件名的情况 + if (args.length == 4 && args[2].equals( "--")){ + checkoutFileCommit(args[1], args[3]); + }//传入文件名的情况 + else if (args.length == 3 && args[1].equals("--")) { + checkoutFileHead(args[2]); + }//传入分支名的情况 + else if (args.length == 2){ + checkoutBranch(args[1]); + }else{ + System.out.println("传入参数错误"); + } + } + + private static void checkoutFileCommit(String commitId , String fileName) throws IOException { + Commit commit = getCommitById(commitId); + if (commit == null){ + System.out.println("没有该id的提交"); + return; + } + if (!commit.getBlobs().containsKey(fileName)){ + System.out.println("该文件不存在"); + return; + } + String blobId = commit.getBlobs().get(fileName); + File blobFile = new File (".gitlet" , blobId); + byte [] fileContent = Utils.readContents(blobFile); + Utils.writeContents(new File(fileName),fileContent); + + + } + + private static void checkoutFileHead(String fileName) throws IOException{ + Commit headCommit = getCurrentCommit(); + if (!headCommit.getBlobs().containsKey(fileName)){ + System.out.println("文件在该提交中不存在"); + return; + } + String bolbId = headCommit.getBlobs().get(fileName); + File bolbFile = new File (".gitlet" , bolbId); + byte [] fileContent = Utils.readContents(bolbFile); + Utils.writeContents(new File(fileName) , fileContent); + } + private static void checkoutBranch(String branchName) throws IOException{ + + File branchFile = new File(".gitlet/branches",branchName); + if (!branchFile.exists()){ + System.out.println("没有该分支"); + return; + } + String currentBranch = Utils.readContentsAsString(new File(".gitlet","HEAD")); + if (branchName.equals(currentBranch)){ + System.out.println("无须检出该分支"); + } + + String commitid = Utils.readContentsAsString(branchFile); + Commit commit = getCommitById(commitid); + if (commit == null){ + System.out.println("没有该id的提交"); + } + + for (String fileName : Utils.plainFilenamesIn(".")){ + if (!commit.getBlobs().containsKey(fileName) && getCurrentCommit().getBlobs().containsKey(fileName)){ + System.out.println("有跟踪的文件会被覆盖 请先删除 或添加并提交它"); + return; + } + } + //清空工作目录 + for (String fileName : Utils.plainFilenamesIn(".")){ + File file = new File(fileName); + if (file.isFile()){ + file.delete(); + } + } + //从提交中赋值文件 + for ( Map.Entry entry : commit.getBlobs().entrySet()){ + String fileName = entry.getKey(); + String commmitId = entry.getValue(); + File bolbFile = new File(fileName,commmitId); + byte [] fileContent = Utils.readContents(bolbFile); + Utils.writeContents(new File(fileName),fileContent); + + } + + //更新HEAD并且清空暂存区 + + Utils.writeContents(new File(".gitlet" , "HEAD"),branchName); + File stagingArea = new File (".gitlet/satging"); + for(File file : stagingArea.listFiles()){ + if (file.isFile()){ + file.delete(); + } + } + + + } + + public static void branch(String branchName) throws IOException{ + + File gitletDir = new File (".gitlet"); + File branchDir = new File (gitletDir,"branches"); + //检查分支目录是否创建 + if (!branchDir.exists()){ + branchDir.mkdirs(); + } + //检查分支是否存在 + File branchFile = new File (branchDir,branchName); + if (branchFile.exists()){ + System.out.println("当前分支已存在"); + return; + } + //获取当前提交的分支id + String currentCommitId = getCurrentCommitId(); + //创建新分支文件 + Utils.writeContents(branchFile,currentCommitId); + + } + + public static void rmbranch( String branchName) throws IOException{ + File gitletDir = new File (".gitlet"); + File branchDir = new File (gitletDir,"branches"); + if (!branchDir.exists()){ + System.out.println("文件夹不存在"); + return; + } + //检查分支是否存在 如果存在就删除 + File branchFile = new File (branchDir , branchName); + if (branchFile.isFile()){ + branchFile.delete(); + }else{ + System.out.println("该分支不存在"); + } + File headFile = new File(gitletDir,"HEAD"); + if (headFile.exists()){ + String currentId = getCurrentCommitId(); + if (branchName.equals(currentId)){ + System.out.println("不能删除档当前分支"); + }else{ + branchFile.delete(); + } + } + } + + public static void reset(String commitId) throws IOException{ + //获取指定的提交对象 + Commit commit = getCommitById(commitId); + if (commit == null){ + System.out.println("没有该id的提交"); + return; + } + //清空工作目录 + for (String fileName : Utils.plainFilenamesIn(".")){ + File file = new File(fileName); + if (file.isFile()){ + file.delete(); + } + } + + //从提交中复制文件到工作目录 + for (Map.Entry entry : commit.getBlobs().entrySet()){ + String fileName = entry.getKey(); + String bolbId = entry.getValue(); + File blobFile = new File (".gitlet" , bolbId); + byte[] fileContent = Utils.readContents(blobFile); + Utils.writeContents(new File(fileName) , fileContent); + + } + + //更新当前分支的头指针 + String currentBranch = Utils.readContentsAsString(new File (".gitlet" ,"HEAD")); + File branchFile = new File (".gitlet/branches" , currentBranch); + Utils.writeContents(branchFile , commitId); + + + //清空暂存区文件 + File stagingFile = new File (".gitlet/staging" ); + for (File files : stagingFile.listFiles()){ + if (files.isFile()){ + files.delete(); + } + } + + } + + public static void merge(String branchName) throws IOException{ + File gitletDir = new File(".getlet"); + String currentCommitId = getCurrentCommitId(); + + } + + /** + * 获取当前分支的最新提交ID。 + * @return 当前分支的最新提交ID + * @throws IOException 如果读取文件失败 + */ + private static String getCurrentCommitId() throws IOException { + File gitletDir = new File(".gitlet"); + File headFile = new File(gitletDir, "master"); + return Utils.readContentsAsString(headFile); + } + + /** + * 获取当前分支的最新提交对象。 + * @return 当前分支的最新提交对象 + * @throws IOException 如果读取文件失败 + */ + private static Commit getCurrentCommit() throws IOException { + String commitId = getCurrentCommitId(); + return getCommitById(commitId); + } + + /** + * 根据提交ID获取提交对象。 + * @param commitId 提交ID + * @return 提交对象 + * @throws IOException 如果读取文件失败 + */ + private static Commit getCommitById(String commitId) throws IOException { + File gitletDir = new File(".gitlet"); + return Utils.readObject(new File(gitletDir, commitId), Commit.class); + } + + + +} \ No newline at end of file diff --git a/proj3/byow/Core/WorldGenerator.java b/proj3/byow/Core/WorldGenerator.java new file mode 100644 index 000000000..e2982b782 --- /dev/null +++ b/proj3/byow/Core/WorldGenerator.java @@ -0,0 +1,205 @@ +package byow.Core; +import java.util.*; +import byow.TileEngine.TETile; +import byow.TileEngine.Tileset; +import byow.TileEngine.TERenderer; + +public class WorldGenerator { + private static final int WIDTH = 150; + private static final int HEIGHT = 60; + private static final int MAX_ROOMS = 30; + private static final int MIN_ROOMS = 20; + private static final int MAX_ROOM_SIZE = 15; + private static final int MIN_ROOM_SIZE = 8; + private static final int HALLWAY_WIDTH = 2; + private static Random RANDOM; + + public static void main(String[] args) { + long seed = Long.parseLong(args[0]); + RANDOM = new Random(seed); + + TERenderer ter = new TERenderer(); + ter.initialize(WIDTH, HEIGHT); + + TETile[][] world = new TETile[WIDTH][HEIGHT]; + initializeWorld(world); + + List rooms = generateRooms(world); + connectRooms(world, rooms); + + ter.renderFrame(world); + } + + private static void initializeWorld(TETile[][] world) { + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + world[i][j] = Tileset.NOTHING; + } + } + } + + private static List generateRooms(TETile[][] world) { + List rooms = new ArrayList<>(); + int roomCount = RANDOM.nextInt(MAX_ROOMS - MIN_ROOMS + 1) + MIN_ROOMS; + int currentCount = 0; + while (currentCount < roomCount) { + int roomWidth = RANDOM.nextInt(MAX_ROOM_SIZE - MIN_ROOM_SIZE + 1) + MIN_ROOM_SIZE; + int roomHeight = RANDOM.nextInt(MAX_ROOM_SIZE - MIN_ROOM_SIZE + 1) + MIN_ROOM_SIZE; + int x = RANDOM.nextInt(WIDTH - roomWidth); + int y = RANDOM.nextInt(HEIGHT - roomHeight); + + Room room = new Room(x, y, roomWidth, roomHeight); + if (isValidRoom(world, room)) { + createRoom(world, room); + rooms.add(room); + currentCount++; + } + } + return rooms; + } + + private static boolean isValidRoom(TETile[][] world, Room room) { + for (int i = room.x; i < room.x + room.width; i++) { + for (int j = room.y; j < room.y + room.height; j++) { + if (world[i][j] != Tileset.NOTHING) { + return false; + } + } + } + return true; + } + + private static void createRoom(TETile[][] world, Room room) { + for (int i = room.x; i < room.x + room.width; i++) { + for (int j = room.y; j < room.y + room.height; j++) { + if (i == room.x || i == room.x + room.width - 1 || j == room.y || j == room.y + room.height - 1) { + world[i][j] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } else { + world[i][j] = Tileset.FLOOR; + } + } + } + } + + private static void connectRooms(TETile[][] world, List rooms) { + for (int i = 0; i < rooms.size() - 1; i++) { + Room room1 = rooms.get(i); + Room room2 = rooms.get(i + 1); + createHallway(world, room1, room2); + } + } + + private static void createHallway(TETile[][] world, Room room1, Room room2) { + int x1 = room1.centerX(); + int y1 = room1.centerY(); + int x2 = room2.centerX(); + int y2 = room2.centerY(); + + while (x1 != x2) { + world[x1][y1] = Tileset.FLOOR; + if (x1 < x2) { + x1++; + } else { + x1--; + } + } + while (y1 != y2) { + world[x1][y1] = Tileset.FLOOR; + if (y1 < y2) { + y1++; + } else { + y1--; + } + } + + addHallwayWalls(world, room1, room2); + } + + private static void addHallwayWalls(TETile[][] world, Room room1, Room room2) { + int x1 = room1.centerX(); + int y1 = room1.centerY(); + int x2 = room2.centerX(); + int y2 = room2.centerY(); + + for (int x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) { + if (world[x][y1] != Tileset.FLOOR) { + world[x][y1] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + if (y1 + 1 < HEIGHT && world[x][y1 + 1] != Tileset.FLOOR) { + world[x][y1 + 1] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + if (y1 - 1 >= 0 && world[x][y1 - 1] != Tileset.FLOOR) { + world[x][y1 - 1] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + } + + for (int y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) { + if (world[x2][y] != Tileset.FLOOR) { + world[x2][y] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + if (x2 + 1 < WIDTH && world[x2 + 1][y] != Tileset.FLOOR) { + world[x2 + 1][y] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + if (x2 - 1 >= 0 && world[x2 - 1][y] != Tileset.FLOOR) { + world[x2 - 1][y] = TETile.colorVariant(Tileset.WALL, 32, 32, 32, RANDOM); + } + } + } + + + private static class Room { + int x, y, width, height; + + Room(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + public int centerX() { + return x + width / 2; + } + public int centerY(){ + return y + height / 2; + } + + public boolean isEdge(int x, int y) { + return x == this.x || x == this.x + width -1 || y == this.y || y == this.y + height -1; + } + } + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/proj3/byow/Networking/BYOWClient.java b/proj3/byow/Networking/BYOWClient.java index 36218e99e..b477abdfe 100644 --- a/proj3/byow/Networking/BYOWClient.java +++ b/proj3/byow/Networking/BYOWClient.java @@ -123,6 +123,8 @@ private static File join(File first, String... others) { public static void main(String[] args) throws IOException { + + System.out.println("BYOW Client. Please Enter the following information to connect to a server..."); Scanner scanner = new Scanner(System.in); System.out.print("IP Address: "); diff --git a/proj3/byow/Networking/BYOWServer.java b/proj3/byow/Networking/BYOWServer.java index cffdcc2d1..beae70f1d 100644 --- a/proj3/byow/Networking/BYOWServer.java +++ b/proj3/byow/Networking/BYOWServer.java @@ -13,6 +13,7 @@ public class BYOWServer { + static private final File CWD = new File(System.getProperty("user.dir")); static private final String CANVAS_FILE = ".server_canvas.png"; diff --git a/proj3/byow/lab12/HexWorld.java b/proj3/byow/lab12/HexWorld.java index ed8b2ba06..6be7e8b3f 100644 --- a/proj3/byow/lab12/HexWorld.java +++ b/proj3/byow/lab12/HexWorld.java @@ -1,6 +1,4 @@ package byow.lab12; -import org.junit.Test; -import static org.junit.Assert.*; import byow.TileEngine.TERenderer; import byow.TileEngine.TETile; @@ -12,4 +10,79 @@ * Draws a world consisting of hexagonal regions. */ public class HexWorld { + private static final int WIDTH = 150; + private static final int HEIGHT = 50; + private static final int HEX_SIZE = 3; + private static final int SEED = 114514; + private static final Random RANDOM = new Random(SEED); + + public static void main(String[] args) { + TERenderer ter = new TERenderer(); + ter.initialize(WIDTH, HEIGHT); + TETile[][] world = new TETile[WIDTH][HEIGHT]; + beginWorld(world); + generateHexPattern(world, WIDTH / 2, HEIGHT / 2, HEX_SIZE); + ter.renderFrame(world); + } + + private static void beginWorld(TETile[][] world) { + for (int i = 0; i < WIDTH; i++) { + for (int j = 0; j < HEIGHT; j++) { + world[i][j] = Tileset.NOTHING; + } + } + } + + private static void addHexagon(TETile[][] world, int x, int y, int size, TETile tile) { + for (int i = 0; i < size; i++) { + int rowWidth = size + 2 * i; + int xPos = x - i; + int yPos = y + i; + addHexRow(world, xPos, yPos, rowWidth, tile); + } + + for (int i = 0; i < size; i++) { + int rowWidth = size + 2 * (size - 1 - i); + int xPos = x - (size - 1 - i); + int yPos = y + size + i; + addHexRow(world, xPos, yPos, rowWidth, tile); + } + } + + private static void addHexRow(TETile[][] world, int x, int y, int width, TETile tile) { + for (int i = 0; i < width; i++) { + int currentX = x + i; + if (currentX >= 0 && currentX < world.length && y >= 0 && y < world[0].length) { + world[currentX][y] = TETile.colorVariant(tile, 32, 32, 32, new Random()); + } + } + } + + private static TETile getRandomTile() { + TETile[] tiles = {Tileset.FLOWER, Tileset.GRASS, Tileset.SAND, Tileset.WALL, Tileset.WATER}; + return tiles[RANDOM.nextInt(tiles.length)]; + } + + private static void generateHexPattern(TETile[][] world, int centerX, int centerY, int size) { + addHexagon(world, centerX, centerY, size, getRandomTile()); + // First layer + int[][] firstLayerOffsets = { + {2 * size - 1, -size}, {2 * size - 1, size}, + {0, 2 * size}, {-2 * size + 1, size}, + {-2 * size + 1, -size}, {0, -2 * size} + }; + for (int[] offset : firstLayerOffsets) { + addHexagon(world, centerX + offset[0], centerY + offset[1], size, getRandomTile()); + } + // Second layer + int[][] secondLayerOffsets = { + {4 * size - 2, -2 * size}, {4 * size - 2, 0}, {4 * size - 2, 2 * size}, + {2 * size - 1, 3 * size}, {0, 4 * size}, {-2 * size + 1, 3 * size}, + {-4 * size + 2, 2 * size}, {-4 * size + 2, 0}, {-4 * size + 2, -2 * size}, + {-2 * size + 1, -3 * size}, {0, -4 * size}, {2 * size - 1, -3 * size} + }; + for (int[] offset : secondLayerOffsets) { + addHexagon(world, centerX + offset[0], centerY + offset[1], size, getRandomTile()); + } + } } diff --git a/proj3/byow/lab13/MemoryGame.java b/proj3/byow/lab13/MemoryGame.java index 048d77deb..4dc756bd8 100644 --- a/proj3/byow/lab13/MemoryGame.java +++ b/proj3/byow/lab13/MemoryGame.java @@ -29,12 +29,7 @@ public class MemoryGame { "Too easy for you!", "Wow, so impressive!"}; public static void main(String[] args) { - if (args.length < 1) { - System.out.println("Please enter a seed"); - return; - } - - long seed = Long.parseLong(args[0]); + long seed = 114514; MemoryGame game = new MemoryGame(40, 40, seed); game.startGame(); } @@ -43,42 +38,90 @@ public MemoryGame(int width, int height, long seed) { /* Sets up StdDraw so that it has a width by height grid of 16 by 16 squares as its canvas * Also sets up the scale so the top left is (0,0) and the bottom right is (width, height) */ + //TODO: Initialize random number generator this.width = width; this.height = height; - StdDraw.setCanvasSize(this.width * 16, this.height * 16); - Font font = new Font("Monaco", Font.BOLD, 30); - StdDraw.setFont(font); - StdDraw.setXscale(0, this.width); - StdDraw.setYscale(0, this.height); - StdDraw.clear(Color.BLACK); - StdDraw.enableDoubleBuffering(); + this.rand = new Random(seed); + + StdDraw.setCanvasSize(width * 16, height * 16); + StdDraw.setXscale(0, width); + StdDraw.setYscale(0, height); - //TODO: Initialize random number generator } public String generateRandomString(int n) { //TODO: Generate random string of letters of length n - return null; + StringBuilder sb = new StringBuilder(n); + for (int i = 0 ; i < n ; i++){ + sb.append(CHARACTERS[rand.nextInt(CHARACTERS.length)]); + } + return sb.toString(); } public void drawFrame(String s) { //TODO: Take the string and display it in the center of the screen + StdDraw.clear(Color.BLACK); + StdDraw.setPenColor(Color.white); + StdDraw.text(width/2,height/2,s); + if (!gameOver){ + StdDraw.setFont(new Font("Monaco" , Font.BOLD,30)); + StdDraw.textLeft(1,height - 1,"ROUND:" + round); + StdDraw.textRight(width - 1 , height - 1, playerTurn ? "Type!" : "Watch"); + StdDraw.setFont(new Font("Monaco" , Font.BOLD,30)); + } + //TODO: If game is not over, display relevant game information at the top of the screen + StdDraw.show(); } public void flashSequence(String letters) { //TODO: Display each character in letters, making sure to blank the screen between letters + for (char c: letters.toCharArray()){ + drawFrame(String.valueOf(c)); + StdDraw.pause(1000); + StdDraw.clear(Color.BLACK); + StdDraw.show(); + StdDraw.pause(500); + } + } public String solicitNCharsInput(int n) { //TODO: Read n letters of player input - return null; + StringBuilder sb = new StringBuilder(); + while (sb.length() < n){ + if (StdDraw.hasNextKeyTyped()){ + sb.append(StdDraw.nextKeyTyped()); + drawFrame(sb.toString()); + } + } + return sb.toString(); } public void startGame() { //TODO: Set any relevant variables before the game starts - + gameOver = false; + round = 1; //TODO: Establish Engine loop + while (!gameOver){ + playerTurn = false; + drawFrame("ROUND" + round); + StdDraw.pause(1000); + + String sequence = generateRandomString(round); + flashSequence(sequence); + + playerTurn = true; + String playInput = solicitNCharsInput(round); + + if (!playInput.equals(sequence)){ + gameOver = true; + }else{ + round++; + } + } + drawFrame("游戏结束,最高记录"+round); + } }